ExPaNDS-eu / ExPaNDS-experimental-techniques-ontology

EU Photon and Neutron Ontologies (task 3.2)
8 stars 4 forks source link

Release both PaNET before and after reasoning #120

Closed gkoum closed 2 months ago

gkoum commented 4 months ago

In line with the comments of Paul Millar here there is a difference in releasing the ontology before and after running the reasoner.

It is obvious that the ontology should be released without any inferred axioms by the reasoner for someone who is capable to open it through protege and run the reasoner. The reference point should not be burdened with the overhead of all superclasses of a class if it is going to be used as a Tbox/model.

On the other hand I argue that PaNET should also be available in the reasoned form as well. This will target the users that want to exploit it using SPARQL queries, or simple python scripts. In the case of a clean Tbox the user looses all the inferred axioms and possibly some valuable results.

For instance I tried to get all 'x-ray probe' techniques using owlready2 to fire a SPARQL query and I got 50 in the beforeReasoning and 90+ in the afterReasoning version.

This version can be used 'as is' by putting it behind a SPARQL endpoint or parsing it with simple python/Java scripts.

spc93 commented 3 months ago

I agree.

spc93 commented 3 months ago

Only loosely related but... I've been looking at using the reasoners in owlready2 in order to get a full list of superclasses. My initial experience is that (1) only the pellet reasoner seems to work properly (the default HermiT reasoner gives almost nothing). (2) It is still necessary to use the Python .mro method to get all subclasses, i.e. this requires both the reasoner AND .mro, in general. Possibly I'm doing something stupid but in vase this saves someone some time...

gkoum commented 3 months ago

I have done some tests myself with owlready2 and and rdflib as well as with the java library behind the Protege DL query tab the owlapi and I sometimes am confused with the results. Can you please share the scripts you use?

Maybe we can have a repository to exchange code snippets regarding utilizing PaNET within the /ExPaNDS-eu domain.

spc93 commented 3 months ago

Some code below. It seems to work but I am also confused!

from owlready2 import *
# be careful - restart kernel for new owl file

def displayParentsChildren(panet_url, term):

    # panet_url: url or filename of ontology .owl file
    # technique: name, label or alt. label of PaNET term    

    panet = get_ontology(panet_url).load()
    with panet:

        sync_reasoner_pellet()

        panet_class = None

        for pncls in panet.classes():
            if term == pncls.name:
                panet_class = pncls
                break      

        # if term isn't a panet name then look for it in labels
        if panet_class == None:
            for pncls in panet.classes():
                if term in pncls.label or term in pncls.altLabel:
                    panet_class = pncls
                    break  

        if panet_class == None:
            raise NameError("=== error - can't find term '%s' as a panet name, label or alt. label" % term)

        parents = panet_class.mro()[0:-2]
        #parents = list(panet.get_parents_of(panet_class)) ## alternative - doesn't seemto work

        print('\nProperties of %s (Label: %s) in %s:\n' % (pncls, pncls.label[0], panet_url))

        # remove owl.thing (only present if no other direct superclasses)
        direct_superclasses = [cls for cls in panet_class.is_a if cls != owl.Thing] 

        print('\nSuperclasses (direct and given by equivalent classes):\n')
        displayClasses(direct_superclasses)   
        print('\nNo. of direct_superclasses of %s: %i ' % (panet_class, len(direct_superclasses)))
        print('\n' + '-'*50)

        print('\nAll superclasses:\n')
        displayClasses(parents)
        #print('\nNo. of superclasses of %s (including self): %i ' % (panet_class, icount))
        print('\nNo. of superclasses of %s (including self): %i ' % (panet_class, len(parents)))
        print('\n' + '-'*50)

        subclasses = []
        for cls in panet.classes():
            if panet_class in cls.mro()[0:-2]:
                subclasses += [cls]

        #subclasses = list(panet.get_children_of(panet_class)) ### alternative -doesn't seem to work

        #subclasses = list(panet_class.subclasses())
        print('\nSubclasses (children):\n')
        displayClasses(subclasses)   
        print('\nNo. of subclasses of %s (including self): %i ' % (panet_class, len(subclasses)))
        print('\n' + '-'*50)

def displayClasses(classList):
    # order and print classes in class list, with all labels
    cls_list = []

    for cls in classList:
        label = ''
        if cls.label != []:
            label = cls.label[0]

        if not cls.altLabel == []:
            altlabels = '(Alt. Labels: ' + ', '.join(cls.altLabel) + ')'
        else:
            altlabels = ''

        cls_list += ['%s %s %s' % (str(cls), label, altlabels)]

    cls_list.sort()
    for cls_str in cls_list:
        print(cls_str)

def findLabelClashes(panet_url):
    # Find and display duplicated labels  

    panet = get_ontology(panet_url).load()
    #print(file)

    all_labels = []
    #all_labels = ['birefringence', 'MAD'] # for testing

    duplicate_labels = []

    for pncls in panet.classes():

        if not len(pncls.label) == 0: # ignore if no label
            for label in all_labels:
                if (label == pncls.label[0]) or (label in pncls.altLabel):
                    duplicate_labels += [label]

        all_labels += pncls.label
        all_labels += pncls.altLabel

    return(duplicate_labels)

def showClassesWithLabels(label_list, panet_url):
    # show PaNET classes that have label or altLabel in label_list

    panet = get_ontology(panet_url).load()

    for label in label_list:
        for pncls in panet.classes():
            if not len(pncls.label) == 0: # ignore if no label
                if (label == pncls.label[0]) or (label in pncls.altLabel):
                    print('Duplicate Label: %s\tPaNET Class: ' %  label, pncls, pncls.label[0], pncls.altLabel)

def showLabelClashes(file):
    # display classes with label clashes
    print('Label clashes in %s:' % file)
    clashes = findLabelClashes(file)
    if clashes == []:
        print('No clashes')
    else:
        print('Clashes found:')
        showClassesWithLabels(clashes, file)

#file = 'http://purl.org/pan-science/PaNET/PaNET.owl' # current release
#file = '/dls/science/users/spc93/git/ExPaNDS-experimental-techniques-ontology/source/PaNET.owl' # local test version
file = '/dls/science/users/spc93/tmp/PaNET.owl' # tmp test version
#file = '/dls/science/users/spc93/tmp/PaNET_reasoned.owl' # tmp test version reasoned
showLabelClashes(file)

displayParentsChildren(file, 'neutron single crystal diffraction') #112
displayParentsChildren(file, 'imaging') #115
displayParentsChildren(file, 'x-ray absorption spectroscopy') #118
spc93 commented 3 months ago

Oops - sorry about the formatting!