Skip to content

Commit

Permalink
fix: bugs with rdflib.extras.infixowl (#2390)
Browse files Browse the repository at this point in the history
Fix the following issues in `rdflib.extras.infixowl`:
- getting and setting of max cardinality only considered identifiers and not other RDF terms.
- The return value of `manchesterSyntax` was wrong for some cases.
- The way that `BooleanClass` was generating its string representation (i.e. `BooleanClass.__repr__`) was wrong for some cases.

Other changes:
- Added an example for using infixowl to create an ontology.
- Updated infixowl tests.
- Updated infixowl documentation.

This code is based on code from:
- <#2307>

Changes are primarily authored by <https://github.com/gjhiggins>.

---------

Co-authored-by: Graham Higgins <gjh@bel-epa.com>
  • Loading branch information
aucampia and Graham Higgins committed May 19, 2023
1 parent e103078 commit cd0b442
Show file tree
Hide file tree
Showing 4 changed files with 488 additions and 93 deletions.
280 changes: 280 additions & 0 deletions examples/infixowl_ontology_creation.py
@@ -0,0 +1,280 @@
from rdflib import Graph, Literal, Namespace, URIRef
from rdflib.extras.infixowl import Class, Ontology, Property, min, only, some

CPR = Namespace("http://purl.org/cpr/0.75#")
INF = Namespace("http://www.loa-cnr.it/ontologies/InformationObjects.owl#")
EDNS = Namespace("http://www.loa-cnr.it/ontologies/ExtendedDnS.owl#")
DOLCE = Namespace("http://www.loa-cnr.it/ontologies/DOLCE-Lite.owl#")
REL = Namespace("http://www.geneontology.org/owl#")
GALEN = Namespace("http://www.co-ode.org/ontologies/galen#")
TIME = Namespace("http://www.w3.org/2006/time#")
CYC = Namespace("http://sw.cyc.com/2006/07/27/cyc/")


def infixowl_example():
g = Graph()
g.bind("cpr", CPR, override=False)
g.bind("ro", REL, override=False)
g.bind("inf", INF, override=False)
g.bind("edns", EDNS, override=False)
g.bind("dol", DOLCE, override=False)
g.bind("time", TIME, override=False)
g.bind("galen", GALEN, override=False)

Class.factoryGraph = g
Property.factoryGraph = g
Ontology.factoryGraph = g

cprOntology = Ontology(URIRef("http://purl.org/cpr/owl")) # noqa: N806
cprOntology.imports = [
URIRef("http://obo.sourceforge.net/relationship/relationship.owl"),
URIRef(DOLCE),
URIRef(EDNS),
URIRef("http://www.w3.org/2006/time#"),
]
cprOntology.comment = [
Literal(
"""This OWL ontology was generated by Fuxi 0.85b.dev-r107
(with newly added Infix OWL syntax library). It imports the
OBO relationship ontology, DOLCE, and OWL time. It formally
defines a focused, core set of archetypes [Jung, C.]
replicated in various patient record terminology. This core is
defined in RDF and follows the normalization principles
of "rigorous formal ontologies" [Rector, A.]."""
)
]
cprOntology.setVersion(Literal("0.75"))

# Relations
# represented-by
representationOf = Property( # noqa: N806
CPR["representation-of"],
inverseOf=Property(CPR["represented-by"]),
comment=[
Literal(
"""Patient records stand in the cpr:representation-of relation
with patients"""
)
],
)
representedBy = Property( # noqa: F841, N806
CPR["represented-by"], inverseOf=representationOf
)
# description-of
descrOf = Property( # noqa: N806
CPR["description-of"],
comment=[
Literal(
"""Clinical descriptions stand in the cpr:description-of
relation with various clinical phenomenon"""
)
],
domain=[Class(CPR["clinical-description"])],
)
# cpr:interpreted-by
interpretedBy = Property( # noqa: F841, N806
CPR["interpreted-by"],
comment=[
Literal(
"""Signs and symptoms are interpreted by rational physical
objects (people)"""
)
],
domain=[Class(CPR["medical-sign"]) | Class(CPR["symptom"])],
range=[Class(CPR.person)],
)
# cpr:realized-by
realizedBy = Property( # noqa: N806
CPR["realized-by"],
comment=[
Literal(
"""The epistemological relation in which screening acts and
the problems they realize stand to each other"""
)
],
inverseOf=Property(CPR["realizes"]),
domain=[Class(CPR["medical-problem"])],
range=[Class(CPR["screening-act"])],
)
# cpr:realizes
realizes = Property(CPR["realizes"], inverseOf=realizedBy) # noqa: F841

# Classes
# cpr:person
person = Class(CPR.person)
person.comment = [
Literal(
"""A class which directly corresponds with the “Person” class in
both GALEN and Cyc"""
)
]
person.subClassOf = [Class(EDNS["rational-physical-object"])]
person.equivalentClass = [Class(GALEN.Person), Class(CYC.Person)]

# cpr:patient
patient = Class(CPR.patient)
patient.comment = [
Literal(
"""A class which directly corresponds with the “Patient”
and “MedicalPatient” classes in GALEN / Cyc"""
)
]
# patient.equivalentClass = [Class(GALEN.Patient),Class(CYC.MedicalPatient)]
patient.subClassOf = [CPR["represented-by"] @ some @ Class(CPR["patient-record"])]
person += patient

# cpr:clinician
clinician = Class(CPR.person)
clinician.comment = [
Literal(
"""A person who plays the clinician role (typically Nurse,
Physician / Doctor, etc.)"""
)
]
person += clinician

# bytes
bytes = Class(CPR.bytes)
bytes.comment = [
Literal(
"""The collection of physical objects which constitute a stream of
bytes in memory, disk, etc."""
)
]
bytes.subClassOf = [DOLCE["non-agentive-physical-object"]]

# cpr:patient-record
patientRecord = Class(CPR["patient-record"]) # noqa: N806
patientRecord.comment = [
Literal(
"""a class (a representational artifact [REFTERM]) depicting
relevant clinical information about a specific patient and is
primarily comprised of one or more
cpr:clinical-descriptions."""
)
]
patientRecord.seeAlso = [URIRef("")]
patientRecord.subClassOf = [
bytes,
# Class(CYC.InformationBearingThing),
CPR["representation-of"] @ only @ patient,
REL.OBO_REL_has_proper_part @ some @ Class(CPR["clinical-description"]),
]

# cpr:medical-problem
problem = Class(
CPR["medical-problem"],
subClassOf=[
Class(DOLCE.quality),
realizedBy @ only @ Class(CPR["screening-act"]),
],
)
problem.comment = [
Literal(
""".. problems that clearly require the intervention of a health
care professional. These include acute problems requiring
hospitalization and chronic problems requiring long-term
management."""
)
]

# cpr:clinical-description
clinDescr = Class(CPR["clinical-description"]) # noqa: N806
clinDescr.disjointWith = [CPR["patient-record"]]
clinDescr.comment = [
Literal(
"""A class which corresponds (at least syntactically) with the HL7
RIM Act Class, insofar as its members consist of clinical
recordings (representational artifacts) of natural phenomena
of clinical significance"""
)
]
clinDescr.subClassOf = [
bytes,
# Class(CYC.InformationBearingThing),
DOLCE["has-quality"] @ some @ Class(TIME.TemporalEntity),
descrOf @ min @ Literal(1),
]

# cpr:medical-sign
sign = Class(
CPR["medical-sign"],
subClassOf=[
problem,
Property(CPR["interpreted-by"]) @ only @ clinician,
Property(CPR["interpreted-by"]) @ some @ clinician,
],
disjointWith=[CPR.symptom],
)
sign.comment = [
Literal(
"""A cpr:medical-problem which are specifically interpreted by a
clinician. As such, this class is informally defined as an
objective indication of a quality typically detected by a
physician during a physical examination of a patient."""
)
]

symptom = Class(
CPR["symptom"],
subClassOf=[
problem,
Property(CPR["interpreted-by"]) @ only @ patient,
Property(CPR["interpreted-by"]) @ some @ patient,
],
disjointWith=[sign],
)
symptom.comment = [
Literal(
"""(Medicine) any sensation or change in bodily function that is
experienced by a patient and is associated with a particular
disease."""
)
]

# clinical-act heriarchy
clinicalAct = Class( # noqa: N806
CPR["clinical-act"], subClassOf=[Class(EDNS.activity)]
)

therapy = Class(CPR["therapeutic-act"], subClassOf=[clinicalAct])
therapy += Class(CPR["physical-therapy"], disjointWith=[CPR["medical-therapy"]])
therapy += Class(
CPR["psychological-therapy"],
disjointWith=[CPR["medical-therapy"], CPR["physical-therapy"]],
)

medicalTherapy = Class( # noqa: N806
CPR["medical-therapy"],
disjointWith=[CPR["physical-therapy"], CPR["psychological-therapy"]],
)
therapy += medicalTherapy
medicalTherapy += Class(CPR["substance-administration"])

diagnosticAct = Class(CPR["diagnostic-act"], subClassOf=[clinicalAct]) # noqa: N806
diagnosticAct.disjointWith = [CPR["therapeutic-act"]]

screeningAct = Class(CPR["screening-act"]) # noqa: N806
screeningAct += Class(CPR["laboratory-test"])

diagnosticAct += screeningAct

screeningAct += Class(
CPR["medical-history-screening-act"],
disjointWith=[CPR["clinical-examination"], CPR["laboratory-test"]],
)

screeningAct += Class(
CPR["clinical-examination"],
disjointWith=[CPR["laboratory-test"], CPR["medical-history-screening-act"]],
)

device = Class( # noqa: F841
CPR["medical-device"], subClassOf=[Class(GALEN.Device)]
)

print(g.serialize(format="turtle"))


if __name__ == "__main__":
infixowl_example()

0 comments on commit cd0b442

Please sign in to comment.