can't assign an object property to instances of a class.

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

can't assign an object property to instances of a class.

leonlp
Hi, i'm new to owlready2.
I'm trying to assign an object property to all the instances of a class but i'm getting an error.

Context:

I'm creating an ontology about african languages (families of languages, where they are spoken in africa etc...)
Instances and values of object and data properties comes from csv files imported into pd dataframes.

Previously, I created a function (import_individuals()) to populate child class with their corresponding instances (for example, NigerCongolese is a family of languages and their instances are simply the names of languages in the dataframe).

Code:


With onto:
    class Languages(Thing): #parent class
        namespace=onto

    class Localization(Thing):
        namespace=onto

    class NigerCongolese(Languages): #child class
        namespace=onto

    class AfroAsian(Languages): #Another child class
        namespace=onto

    class IsSpokenIn(ObjectProperty, FunctionalProperty):
        namespace=onto
        domain=[Languages]
        range=[Localization]

datas=pd.read_pickle('./projet_ontologie/1_data/0_pickle/datas.pkl')
langFamilies=['Afro-Asiatic', 'Niger-Congo']
langFamClasses=[AfroAsian, NigerCongolese]

for family, famClass in zip_longest(langFamilies, langFamClasses):
     import_individuals(famClass, datas, onto, 'family', family) #this function works well so i don't wrote it in how i declared it but if you think i should i'll write it in an answer.

# The problem occurs here:
for lang in NigerCongolese.instances():
    IsSpokenIn[lang].append(WestAfrica)
    IsSpokenIn[lang].append(CentralAfrica)

I'm getting the following error:
AttributeError: 'mappingproxy' object has no attribute 'pop'

What is really strange is that this worked last night when i wrote the code bellow (it return a tuple with the Subject and Object of the relation).
for rel in onto.IsSpokenIn.get_relations():
     print(rel)

>>> (instance, class)

Thank you and if you think i should be more explicit in the code tell me it :).



Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Jiba
Administrator
Hi,

    IsSpokenIn[lang].append(WestAfrica)

I think the problem is that WestAfrica is a class and not an individual. Owlready accepts classes in relation, but it is currently implemented only in class properties, non on individual properties (but here, lang is an individual).

Relation between an individual and a class must be represented by a restriction.

You can either create a restriction manually, as follows:

    lang.is_a.append(IsSpokenIn.some(WestAfrica))

Or you can create the inverse property of IsSpokenIn, and use this inverse property on the class (using Owlready class properties, which accepts both individuals and classes):

with onto:
    class HasLanguage(ObjectProperty):
        inverse=IsSpokenIn
        domain=[Localization]
        range=[Languages]

WestAfrica.HasLanguage.append(lang)

This will automatically create the restrictions.

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

leonlp
Thank you Jiba, it seems to work, it was actually a misunderstanding about how this worked. It's more clear now :)
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

sam.regenbogen
In reply to this post by Jiba
Sorry to bump an old thread, but my question is similar enough that I didn't think it needed a new one.

I ran into the same error message when I was trying to set relations between two individuals, due to the same misunderstanding as the OP...

Can I solve it using the restriction method you mentioned, or am I trying to do something that doesn't make sense in the context of owl?
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Jiba
Administrator
Hi,

I do not understand what you mean by "OP"?

You can create a relation between 2 individuals as follows:

individual1.relation = individual2 # for functional property

individual1.relation.append(individual2) # for non functional property

Jiba
ted
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

ted
I'm getting the same error when appending a punned entity:


File ".../python3.7/site-packages/owlready2/util.py", line 77, in append
    def append(self, x):          old = list(self); super().append(x)         ; self._callback(self._obj, old)
File ".../python3.7/site-packages/owlready2/prop.py", line 1046, in _callback
    added.__dict__.pop(inverse_python_name, None) # Remove => force reloading; XXX optimizable
AttributeError: 'mappingproxy' object has no attribute 'pop'


The error makes sense: object.__dict__ does not generally support pop. When I eliminate the logic or change it to, eg, ...

if hasattr(added, inverse_python_name): delattr(added, inverse_python_name)

... the error disappears, as expected, and the append seems to succeed, but, based on your previous comment, I'm wondering if the result is ultimately incorrect.
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Jiba
Administrator
Hello,

The call to added.__dict__.pop() occurs in the class named "IndividualValueList". As its name suggests, it is understood to be called on individual, not classes.

As said before, Owlready does not support punned entities.

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Patricia Centeno
Hi I am quite new using OWLready2, following this question I have the same situation, in which I want to represent the relation between a class and an individual.

Following the reply above, I created the property "is_puchased_by" , showing the superclasses as domain and range.

class Semiconductor_product(Thing): pass
class Customer(Thing): pass

        class is_purchased_by(ObjectProperty):
            domain=[Semiconductor_product]
            range=[Customer]

Since I am exporting from a CSV file (input list), the code for assigning the triple looks like this:

            for i in input_list[1:]:
                onto[i[0]].is_purchased_by.append(onto[i[1]])


Here the onto[i[0]] represents a subclass of Semiconductor product, lets call it "SLE95100-0005" and the onto[i[1]] represent an individual of the class Customer, lets call it "Eureka".
Therefore my triple has the structure:

Subclass.is_purchased_by.Individual

The code works, my question is once I am visualizing this in Protégé, the window looks like this for the individual "Eureka":


Protégé visualization for individual

Is this normal? Why the relation is of the SLE95100-0005 is purchased by Eureka, doesn´t appear in the object property assertions?

Following the object properties between individuals, this are correctly shown as object property assertions.

Thank you in advance.
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Jiba
Administrator
Hi,

This is normal, because OWL does not allow to assert triples between a class and an individual (or between two classes). Relations can only by asserted as triples between two individuals.

Relations involving one or two classes are more complex, and are asserted as restriction (value restriction, some restriction or only restriction).

Owlready accepts to access to these restriction as class properties, but they are managed internally as OWL restrictions (and thus they appear as such in Protégé).

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Mustafa
Hello Jiba,
How can i create subproperties of a object property dynamically??
Reply | Threaded
Open this post in threaded view
|

Re: can't assign an object property to instances of a class.

Jiba
Administrator
Hi,

You can do that in the same way you create classes dynamically:

import types

with onto:
    NewProp = types.new_class("NewPropName", (SuperProp,))

Jiba