Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f386f37
Added phylorefType to Brochu 2003 example.
gaurav Feb 9, 2021
7a908d6
Added phyloref type generation and to expected JSON-LD and NQ output.
gaurav Feb 9, 2021
bb7b289
Removed phyloref:MalformedPhyloreference.
gaurav Feb 9, 2021
1b45ce6
Added possible phylorefTypes to the JSON Schema.
gaurav Feb 9, 2021
24291c5
Rewrote examples to handle any number of example files.
gaurav Feb 9, 2021
d55984d
Fixed `cladeDefinition` to `definition` in example.
gaurav Feb 9, 2021
a59e153
Changed the base URI for brochu_2003 example to reuse it for all tests.
gaurav Feb 9, 2021
ad2888d
Fixed schema: should require `definition`, not `cladeDefinition`.
gaurav Feb 9, 2021
1d59465
Improved baseURI, simplified unnecessary code.
gaurav Feb 9, 2021
db4840f
Added Testudinata as an apomorphy-based phyloref example.
gaurav Feb 9, 2021
60769d8
Added code for generating JSON-LD for apomorphy-based phylorefs.
gaurav Feb 9, 2021
cf0d033
feat: Display list of JSON Schema violations.
gaurav Feb 9, 2021
b275f7f
Added phyloref:Phyloreference as superclass to apomorphy-based phylorefs
gaurav Feb 9, 2021
96fcaf5
Fixed some JSON Schema validation errors.
gaurav Feb 9, 2021
8db8d86
Regenerated expected JSON-LD and NQ files.
gaurav Feb 9, 2021
540ce4a
Reduced JPhyloRef test requirements.
gaurav Feb 9, 2021
9af3e17
Added an exactMatch field to record a reference to another ontology.
gaurav Feb 9, 2021
5a7795e
feat: We now preserve references to TUs/phylorefs in logical expressions
gaurav Feb 10, 2021
67091ab
Expanded taxonomic units to support IDs.
gaurav Feb 10, 2021
efee3de
Added example file that uses a phyloref as a specifier.
gaurav Feb 10, 2021
d7bf995
Removed overlong commented-out debugging line.
gaurav Feb 10, 2021
f46731b
Removed incorrectly duplicated phyloreference.
gaurav Feb 10, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/context/development/phyx.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#",
"skos": "http://www.w3.org/2004/02/skos/core#",

"obo": "http://purl.obolibrary.org/obo/",
"dwc": "http://rs.tdwg.org/dwc/terms/",
Expand Down Expand Up @@ -186,6 +187,12 @@

"title": "dct:title",

"representsTaxonomicUnits": "obo:CDAO_0000187"
"representsTaxonomicUnits": "obo:CDAO_0000187",

"apomorphy": "testcase:apomorphy",
"exactMatch": {
"@id": "skos:exactMatch",
"@type": "@id"
}
}
}
47 changes: 39 additions & 8 deletions docs/context/development/schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
{
"definitions": {
"id": {
"type": "object",
"description": "Any entity that can be identified by a URI.",
"additionalProperties": false,
"properties": {
"@id": {
"type": "string",
"description": "The URI used to identify this entity.",
"minLength": 1
},
"@type": {
"type": "string",
"description": "The type of this entity.",
"minLength": 1
}
},
"required": [ "@id" ]
},
"agent": {
"type": "object",
"description": "A person or entity.",
Expand Down Expand Up @@ -111,9 +129,7 @@
}
},
"required": [
"name",
"volume",
"identifier"
"name"
]
},
"identifier": {
Expand Down Expand Up @@ -164,6 +180,9 @@
"http://rs.tdwg.org/dwc/terms/Occurrence"
]
},
"rdf:ID": {
"$ref": "#/definitions/id"
},
"label": {
"type": "string",
"minLength": 1
Expand Down Expand Up @@ -201,8 +220,6 @@
},
"required": [
"@type",
"nomenclaturalCode",
"label",
"nameComplete"
]
}
Expand Down Expand Up @@ -277,14 +294,22 @@
"minItems": 0,
"items": {
"required": [
"cladeDefinition"
"definition"
],
"properties": {
"regnumId": {
"type": "string",
"description": "The identifier of this clade definition in the Regnum database",
"minLength": 1
},
"phylorefType": {
"description": "The type of this phyloreference.",
"enum": [
"phyloref:PhyloreferenceUsingMaximumClade",
"phyloref:PhyloreferenceUsingMinimumClade",
"phyloref:PhyloreferenceUsingApomorphy"
]
},
"label": {
"type": "string",
"description": "The name or label of this phyloreference."
Expand Down Expand Up @@ -313,7 +338,10 @@
"uniqueItems": true,
"minItems": 1,
"items": {
"$ref": "#/definitions/taxonomic_unit"
"anyOf": [
{ "$ref": "#/definitions/taxonomic_unit" },
{ "$ref": "#/definitions/id" }
]
}
},
"externalSpecifiers": {
Expand All @@ -322,7 +350,10 @@
"uniqueItems": true,
"minItems": 0,
"items": {
"$ref": "#/definitions/taxonomic_unit"
"anyOf": [
{ "$ref": "#/definitions/taxonomic_unit" },
{ "$ref": "#/definitions/id" }
]
}
}
}
Expand Down
101 changes: 84 additions & 17 deletions src/wrappers/PhylorefWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const moment = require('moment');
const { has, cloneDeep } = require('lodash');

const owlterms = require('../utils/owlterms');
const { TaxonomicUnitWrapper } = require('./TaxonomicUnitWrapper');
const { PhylogenyWrapper } = require('./PhylogenyWrapper');

Expand Down Expand Up @@ -369,10 +370,56 @@ class PhylorefWrapper {
}

static getIncludesRestrictionForTU(tu) {
const tunit = new TaxonomicUnitWrapper(tu).asOWLEquivClass;

if (has(tunit, '@id')) {
// This is a reference! So we treat it differently.
const type = tunit['@type'] || '';
if (type === 'phyloref:Phyloreference') {
// Phyloreferences need to be incorporated directly with a `some` clause.
return {
'@type': 'owl:Restriction',
onProperty: owlterms.CDAO_HAS_DESCENDANT,
someValuesFrom: tunit,
};
}

// If it's not a Phyloreference, we assume that it is an opaque taxonomic
// unit that has been identified with its own URI. In that case, we need
// to use the same EXCLUDES_TU property that we usually use.
}

return {
'@type': 'owl:Restriction',
onProperty: owlterms.PHYLOREF_INCLUDES_TU,
someValuesFrom: tunit,
};
}

static getExcludesRestrictionForTU(tu) {
const tunit = new TaxonomicUnitWrapper(tu).asOWLEquivClass;

if (has(tunit, '@id')) {
// This is a reference! So we treat it differently.
const type = tunit['@type'] || '';
if (type === 'phyloref:Phyloreference') {
// Phyloreferences need to be incorporated directly with a `some` clause.
return {
'@type': 'owl:Restriction',
onProperty: owlterms.PHYLOREF_EXCLUDES_LINEAGE_TO,
someValuesFrom: tunit,
};
}

// If it's not a Phyloreference, we assume that it is an opaque taxonomic
// unit that has been identified with its own URI. In that case, we need
// to use the same EXCLUDES_TU property that we usually use.
}

return {
'@type': 'owl:Restriction',
onProperty: 'phyloref:includes_TU',
someValuesFrom: new TaxonomicUnitWrapper(tu).asOWLEquivClass,
onProperty: owlterms.PHYLOREF_EXCLUDES_TU,
someValuesFrom: tunit,
};
}

Expand All @@ -387,11 +434,7 @@ class PhylorefWrapper {
someValuesFrom: {
'@type': 'owl:Class',
intersectionOf: [
{
'@type': 'owl:Restriction',
onProperty: 'phyloref:excludes_TU',
someValuesFrom: new TaxonomicUnitWrapper(tu1).asOWLEquivClass,
},
PhylorefWrapper.getExcludesRestrictionForTU(tu1),
PhylorefWrapper.getIncludesRestrictionForTU(tu2),
],
},
Expand Down Expand Up @@ -530,11 +573,7 @@ class PhylorefWrapper {
'@type': 'owl:Class',
intersectionOf: [
includedExpr,
{
'@type': 'owl:Restriction',
onProperty: 'phyloref:excludes_TU',
someValuesFrom: new TaxonomicUnitWrapper(tu).asOWLEquivClass,
},
PhylorefWrapper.getExcludesRestrictionForTU(tu),
],
}];

Expand All @@ -549,11 +588,7 @@ class PhylorefWrapper {
{
'@type': 'owl:Restriction',
onProperty: 'obo:CDAO_0000144', // has_Ancestor
someValuesFrom: {
'@type': 'owl:Restriction',
onProperty: 'phyloref:excludes_TU',
someValuesFrom: new TaxonomicUnitWrapper(tu).asOWLEquivClass,
},
someValuesFrom: PhylorefWrapper.getExcludesRestrictionForTU(tu),
},
],
});
Expand Down Expand Up @@ -664,19 +699,40 @@ class PhylorefWrapper {
const internalSpecifiers = phylorefAsJSONLD.internalSpecifiers || [];
const externalSpecifiers = phylorefAsJSONLD.externalSpecifiers || [];

// If it is an apomorphy-based class expression, we can't generate logical
// expressions for it anyway.
const phylorefType = phylorefAsJSONLD.phylorefType;
if (
(phylorefType && phylorefType === 'phyloref:PhyloreferenceUsingApomorphy')
|| (has(phylorefAsJSONLD, 'apomorphy'))
) {
// This is an apomorphy-based definition!
phylorefAsJSONLD.subClassOf = [
'phyloref:Phyloreference',
'phyloref:PhyloreferenceUsingApomorphy',
];

return phylorefAsJSONLD;
}

// We might need to make component classes.
// So we reset our component class counts and records.
PhylorefWrapper.componentClassCount = 0;
PhylorefWrapper.componentClassesByLabel = {};
phylorefAsJSONLD.hasComponentClass = [];

// The type of this phyloreference.
let calculatedPhylorefType;

// The list of logical expressions generated for this phyloref.
let logicalExpressions = [];

if (internalSpecifiers.length === 0) {
// We can't handle phyloreferences without at least one internal specifier.
phylorefAsJSONLD.malformedPhyloreference = 'No internal specifiers provided';
} else if (externalSpecifiers.length > 0) {
calculatedPhylorefType = 'phyloref:PhyloreferenceUsingMaximumClade';

// If the phyloreference has at least one external specifier, we
// can provide a simplified expression for the internal specifier,
// in the form:
Expand All @@ -701,6 +757,8 @@ class PhylorefWrapper {
);
}
} else {
calculatedPhylorefType = 'phyloref:PhyloreferenceUsingMinimumClade';

// We only have internal specifiers. We therefore need to use the algorithm in
// PhylorefWrapper.createClassExpressionsForInternals() to create this expression.
logicalExpressions = PhylorefWrapper.createClassExpressionsForInternals(
Expand Down Expand Up @@ -762,6 +820,15 @@ class PhylorefWrapper {
}
phylorefAsJSONLD.subClassOf.push('phyloref:Phyloreference');

// If the this Phyloref has a phylorefType that differs from the calculated
// phyloref type, throw an error.
if (has(phylorefAsJSONLD, 'phylorefType') && phylorefAsJSONLD.phylorefType !== calculatedPhylorefType) {
throw new Error(
`Phyloref ${this.label} has phylorefType set to '${phylorefAsJSONLD.phylorefType}', but it appears to be a '${calculatedPhylorefType}'.`
);
}
phylorefAsJSONLD.subClassOf.push(calculatedPhylorefType);

return phylorefAsJSONLD;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/wrappers/TaxonomicUnitWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ class TaxonomicUnitWrapper {
return new SpecimenWrapper(this.specimen).asOWLEquivClass;
}

// Is this just a reference (i.e. { "@id": <URI> })? If so, return that
// unchanged.
if (has(this.tunit, '@id')) return this.tunit;

// Nothing we can do, so just ignore it.
return undefined;
}
Expand Down
Loading