← Return to the example · Supporting files

2021 project ontology in Gistv1

Saved notebook · 39 cells. Code and outputs below are retained from the original; nothing was executed for this reading copy. Environment dependencies, missing data and the model limitations remain as described in the linked guide.

Cell 1 · code

# Privacy edit, 4 October 2026: personal filesystem paths were replaced by neutral example paths.
# Existing calculations and saved results were not rerun; this file is a privacy-edited reading edition.
import os
import graphviz
import owlready2 as owl
import weakref
import graph_onto as GO # set up within this directory

Cell 2 · code

onto_path = 'file://' + os.path.abspath('ontologies/gistCore9.5.0')
onto = owl.get_ontology(onto_path).load()
print('Loaded owl file at:', onto_path)
# onto1 = get_ontology("file://" + os.path.abspath("ontologies/project_example.owl")).load() NEED TO ADD EMPTY ONTOLOGY
# onto.base_iri

Cell 3 · code

# OPTION LOOK ACROSS ALL CLASSES using the generator
for x in onto.classes(): 
    print(x)

Cell 4 · code

# OPTION Or transform the generator into a list with the list() function
class_as_list=list(onto.classes())
print (class_as_list[-10]) # Get a random class in collection
list (onto.disjoint_classes()) # or look at disjoint classes
# Or, rather than simply classes,etreive all disjoint individual entity objects, stored in the dict
disjoints = list(onto.disjoints())
for x in disjoints: 
    print(x, '    ',x.__dict__,'\n')

Cell 5 · code

# FIND THE CLASSES OF INTEREST
Project_search_results_as_list=onto.search(iri='*Project*') # search for entities by looking along the full IRI
Task_search_results_as_list=onto.search(iri='*Task')
Artifact_search_results_as_list=onto.search(iri='*Artifact')
print(Project_search_results_as_list,Task_search_results_as_list,Artifact_search_results_as_list)

Cell 6 · code

# SELECT THE CLASSES OF INTEREST FROM SEARCH RESULTS
Project_class_actually=Project_search_results_as_list[0]
Task_class_actually=Task_search_results_as_list[0]
Artifact_class_actually=Artifact_search_results_as_list[0]

Cell 7 · code

# OPTION HAVE A LOOK AT CLASS PROPERTIES
print ('is a', Artifact_class_actually.is_a)  # this gives SUPER classes
print('equivalent_to:', Artifact_class_actually.equivalent_to)
print('has subclasses: ', onto.search(subclass_of=Artifact_class_actually))  # this give SUB classes
for sc in Artifact_class_actually.ancestors():
    print (sc)
for sc in Artifact_class_actually.descendants():
    print (sc)
print(Artifact_class_actually.__dict__)

Cell 8 · code

# CREATE INSTANCES OF THIS CLASS

Cell 9 · code

#Refer to each project as ProjectX[0] etc
Project=[]
ProjectX=[]
for p in range (0,3):
    name='Project'+str(p)
    Project.append(name) # this does nothing 
    ProjectX.append(Project_class_actually(Project[p]))
    print (Project[p], '   ',ProjectX[p])

Cell 10 · code

# TaskX[0] etc
Task=[]
TaskX=[]
for t in range (0,9):
    name='Task'+str(t)
    Task.append(name)
    TaskX.append(Task_class_actually(Task[t]))
    print (Task[t], '   ',TaskX[t])

Cell 11 · code

# ArtifactX[0] etc
Artifact=[]
ArtifactX=[]
for t in range (0,3):
    name='Artifact'+str(t)
    Artifact.append(name)
    ArtifactX.append(Artifact_class_actually(Artifact[t]))
    print (Artifact[t], '   ',ArtifactX[t])

Cell 12 · code

ProjectX[2]
Saved output
gist.Project2

Cell 13 · code

# The first parameter is the name (or identifier) of the Individual; it corresponds to the .name attribute in Owlready2. 
# If not given, the name if automatically generated from the Class name and a number.
random_name=Project_class_actually('Project_Fruitloop100')# create a one off project EASIEST
ProjectX.append(Project_class_actually('Project_Fruitloop200')) # SECOND EASIEST
ProjectX.append(Project_class_actually('Project_Fruitloop300',namespace=onto,hasSubTask=[TaskX[0]])) # THIRD EASIEST

Cell 14 · code

# OPTIONAL  
# ACCESS INSTANCES BY GENERAL VARIABLE OR BY ITERATING THROUGH CLASS
print (ProjectX[0].name,ProjectX[0].iri)
list (onto.individuals())
# note that this particular ontology has ensured some individuals are disjoint
# Some tasks will not be disjoint, but Project people will be, so good to have a go at creating this
print ('\n different indiviudals')
list (onto.different_individuals())
list (onto.individuals())

Cell 15 · code

# OPTIONAL  
for p in Project_class_actually.instances(): print (p.name)
for t in Task_class_actually.instances(): print (t.name)
for t in Artifact_class_actually.instances():print (t.name)

Cell 16 · code

# CREATE RELATIONSHIPS

Cell 17 · code

# Most simple
# ProjectX[0].hasSubTask = [TaskX[0],TaskX[1],TaskX[2]]

Cell 18 · code

# Second most simple
# ProjectX[0] is type Gist.Project and is not subscriptable further. But below is a generator so can use:
#for p in Project_class_actually.instances(): p.hasSubTask = [TaskX[0]]

Cell 19 · code

# Third most simple

Cell 20 · code

#problem is here, that I dont know what order the instances are presented in. So only good for slapdash
counter=0
for p in Project_class_actually.instances():
    p.hasSubTask = [TaskX[counter],TaskX[counter+1],TaskX[counter+2]]
    counter+=3

Cell 21 · code

counter=0
for p in Project_class_actually.instances():
    p.produces = [ArtifactX[counter]]
    counter+=1

Cell 22 · code

#OPTIONAL check relationships have worked
print (ProjectX[0].get_properties(),'\n') # OR..
for p in Project_class_actually.instances(): print (p.get_properties(),'\n')
print(ProjectX[2].INDIRECT_hasSubTask,'\n') # alternative
print(ProjectX[2].INDIRECT_produces,'\n')
property_list=list(onto.properties()) #list of all generic properties:  
rel = property_list[-1] # select a particular relation from the list
print(rel, rel.__dict__)

Cell 23 · code

#Interested in the relation 'produces'
#  the .class_property_type attribute of Properties allows to indicate how to handle class properties:
# “some”: handle class properties as existential restrictions (i.e. SOME restrictions and VALUES restrictions).
# “only”: handle class properties as universal restrictions (i.e. ONLY restrictions).
# “relation”: handle class properties as relations (i.e. simple RDF triple, as in Linked Data).
print(onto.search(produces = "*")) #searches for individuals related w ‘produces’ 
pr=onto.search(iri='*produces*') # this focusses on the relationship itself
print (pr)
print('class_property_some:', pr[0]._class_property_some)
print('class_property_only:', pr[0]._class_property_only)
print('class_property_relation:', pr[0]._class_property_relation)
print(pr[0].__dict__)
# print('name(string):', pr[0].name)
#print('module_type:', pr[0].__module__)
# print('is_a:', pr[0].is_a) # will come back saying its an owl property

Cell 24 · code

#calling the functions from *.py file

Cell 25 · code

entity = GO.keyword_search_onto('Artifact', onto)
print(entity == onto.Artifact, entity,'-'*20,'\n')
kg = GO.ontograf_simple(entity, onto)
print(kg)
GO.convert_to_graphviz(kg)

Cell 26 · code

# so far, I have introduced a new property ' produces' between instances of Project and Artifact.
#This does not appear in the class rules, and it will need to presumably.

Cell 27 · code

onto.save(file = "Project_model.owl", format = "rdfxml")

Cell 28 · code

Artifact_class_actually.instances()
Saved output
[gist.Artifact0, gist.Artifact1, gist.Artifact2]

Cell 29 · code

# ACTION THIS BELOW
# We can see from this, that relationship properties have to be created both sides 
print(onto.search(hasSubTask = "*"))
ProjectX[0].__dict__
TaskX[0].__dict__
Saved output
[gist.Project0, gist.Project1, gist.Project2]

Cell 30 · code

# annotations are one of the property types where the objects are names or strings or link addresses (IRIs),
# but over which no reasoning may occur. Annotations provide the labels, definitions, comments, and pointers to the actual objects in the system. We can assign values in a straightforward manner to annotations (in this case, <code>altLabel</code>):

Cell 31 · code

ProjectX[0].altLabel = ["Digital_Reset_project",'2021_Cloud_project']

Cell 32 · code

ProjectX[0].get_properties()

Cell 33 · code

print(ProjectX[0].altLabel)

Cell 34 · code

# Owlready2 enables us to also place restrictions on our classes
#nthrough a special type of class constructed by the system.
some - Property.some(Range_Class)
only - Property.only(Range_Class)
min - Property.min(cardinality, Range_Class)
max - Property.max(cardinality, Range_Class)
exactly - Property.exactly(cardinality, Range_Class)
value - Property.value(Range_Individual / Literal value)
has_self - Property.has_self(Boolean value).

Cell 35 · markdown

Operators

Owlready2 provides three logical operators between classes (including class constructs and restrictions):

Cell 36 · markdown

Both HermiT and Pellet are written in Java, so require access to a JVM on your system. If you have difficulty running these systems it is likely because you: 1) do not have a recent version of Java installed on your system; or 2) do not have a proper PATH statement in your environmental variables to find the Java executable. If you encounter such problems, please consult third-party sources to get Java properly configured for your system before continuing with this installment.

Cell 37 · code

owl.sync_reasoner()

Cell 38 · code

owl.sync_reasoner_pellet()

Cell 39 · code