From 8b248fdacf595b17f754a5eb30d2ebfca3802619 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 26 Nov 2021 09:54:14 +0100 Subject: [PATCH 01/29] Added first draft of excel2onto --- tools/excel2onto | 146 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100755 tools/excel2onto diff --git a/tools/excel2onto b/tools/excel2onto new file mode 100755 index 000000000..b96a86914 --- /dev/null +++ b/tools/excel2onto @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +"""Creates and ontology from an excelfile. + +The excel file must be in the formate provided by +ontology_template.xlsx +""" +import argparse +import sys +import pyparsing +import pandas as pd +from ontopy import World +from ontopy.utils import NoSuchLabelError +from ontopy.manchester import evaluate +import owlready2 # pylint: disable=C0411 + + +def english(string): + """Returns `string` as an English location string.""" + return owlready2.locstr(string, lang="en") + + +def main(): + """Main run function.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "excelpath", + help="path to excel book", + ) + parser.add_argument( + "--name", + "-n", + default="ontology.ttl", + help="Name of ontology, ´ontology.ttl´ is default", + ) + try: + args = parser.parse_args() + except SystemExit as exc: + sys.exit(exc.code) # Exit without traceback on invalid arguments + + # Read datafile + data = pd.read_excel(args.excelpath, skiprows=[0, 2]) + + # Make new ontology and import ontologies + world = World() + # base_iri to be added from excel (maybe also possibly argument?) + onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") + onto.base_iri = "http://emmo.info/emmo/domain/onto#" + + # imported ontologies to be added from excel + catalog = {} + imported_ontology_paths = [ + ( + "https://raw.githubusercontent.com/emmo-repo/" + "emmo-repo.github.io/master/versions/" + "1.0.0-beta/emmo-inferred-chemistry2.ttl" + ) + ] + + # Add imported ontologies + for path in imported_ontology_paths: + imported = world.get_ontology(path).load() + onto.imported_ontologies.append(imported) + catalog[imported.base_iri.rstrip("/")] = path + + onto.sync_python_names() + + with onto: + # loop through the rows until no more are added + new_loop = True + final_loop = False + while new_loop: + number_of_added_classes = 0 + for _, row in data.iterrows(): + name = row["prefLabel"] + try: + if isinstance( + onto.get_by_label(name), owlready2.ThingClass + ): + continue + except NoSuchLabelError: + pass + + parent_names = str(row["subClassOf"]).split(";") + + try: + parents = [onto.get_by_label(pn) for pn in parent_names] + except NoSuchLabelError: + if final_loop is True: + parents = onto.EMMO + + # make warning! + print("--------------------------------") + print( + "At least one of the defined parents do not exist" + ) + print( + "Concept:", name, "; Defined parents", parent_names + ) + print("--------------------------------") + new_loop = False + else: + continue + + concept = onto.new_entity(name, parents) + + elucidation = row["Elucidation"] + if isinstance(elucidation, str): + concept.elucidation.append(english(elucidation)) + + examples = row["Examples"] + if isinstance(examples, str): + example_list = examples.split(";") + for example in example_list: + concept.example.append(english(example)) + + comments = row["Comments"] + if isinstance(comments, str): + comment_list = comments.split(";") + for comment in comment_list: + concept.comment.append(english(comment)) + + number_of_added_classes += 1 + + if number_of_added_classes == 0: + final_loop = True + + # Add properties in a second loop + for _, row in data.iterrows(): + properties = row["Properties"] + if isinstance(properties, str): + concept = onto.get_by_label(row["Concept (prefLabel)"]) + props = properties.split(";") + for prop in props: + try: + concept.is_a.append(evaluate(onto, prop)) + except pyparsing.ParseException as err: + # make warning! + print("*******************************************") + print("Error in Property assignment for:", concept) + print("Property to be Evaluated: ", prop) + print(err) + print("*******************************************") + + +if __name__ == "__main__": + main() From eab047259d1d85c0c369983f60b950b98ae1bec9 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 09:22:47 +0100 Subject: [PATCH 02/29] Dummy example for make_microstructure_onto.py added. Much of what is in this file should go into the excel2onto tool. --- .../make_microstructure_onto.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100755 examples/ontology-from-excel/make_microstructure_onto.py diff --git a/examples/ontology-from-excel/make_microstructure_onto.py b/examples/ontology-from-excel/make_microstructure_onto.py new file mode 100755 index 000000000..931917e25 --- /dev/null +++ b/examples/ontology-from-excel/make_microstructure_onto.py @@ -0,0 +1,159 @@ +from ontopy import World, get_ontology +from ontopy.utils import NoSuchLabelError, write_catalog +from ontopy.manchester import evaluate +import owlready2 + +import pyparsing + +import pandas as pd +import os +import numpy as np + + +def en(s): + """Returns `s` as an English location string.""" + return owlready2.locstr(s, lang="en") + + +world = World() +chemistry_ontology_path = ( + "https://raw.githubusercontent.com/emmo-repo/" + "emmo-repo.github.io/master/versions/" + "1.0.0-beta/emmo-inferred-chemistry2.ttl" +) + +chemistry = world.get_ontology(chemistry_ontology_path).load() + +catalog = {chemistry.base_iri.rstrip("/"): chemistry_ontology_path} + + +# Create new ontology +onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") +onto.base_iri = "http://emmo.info/emmo/domain/onto#" +onto.imported_ontologies.append(chemistry) +onto.sync_python_names() + + +# Read datafile +data = pd.read_excel("onto.xlsx", skiprows=1) + + +with onto: + # loop through the rows until no more are added + new_loop = True + final_loop = False + while new_loop: + number_of_added_classes = 0 + for index, row in data.iterrows(): + name = row["Concept (prefLabel)"] + try: + if isinstance(onto.get_by_label(name), owlready2.ThingClass): + continue + except NoSuchLabelError: + pass + + parent_names = str(row["subClassOf"]).split(";") + + try: + parents = [onto.get_by_label(pn) for pn in parent_names] + except NoSuchLabelError: + if final_loop == True: + parents = onto.EMMO + print("--------------------------------") + print("At least one of the defined parents do not exist") + print("Concept:", name, "; Defined parents", parent_names) + print("--------------------------------") + new_loop = False + else: + continue + + Concept = onto.new_entity(name, parents) + + elucidation = row["Elucidation (definition intended for humans)"] + if isinstance(elucidation, str): + Concept.elucidation.append(en(elucidation)) + + example = row["Example"] + if isinstance(example, str): + Concept.example.append(en(example)) + + number_of_added_classes += 1 + + if number_of_added_classes == 0: + final_loop = True + + +# Add properties in a second loop +for index, row in data.iterrows(): + properties = row["Properties"] + if isinstance(properties, str): + Concept = onto.get_by_label(row["Concept (prefLabel)"]) + props = properties.split(";") + for p in props: + try: + r = evaluate(onto, p) + Concept.is_a.append(r) + except pyparsing.ParseException as err: + print("*******************************************") + print("Error in Property assignment for:", Concept) + print("Property to be Evaluated: ", p) + print(err) + print("*******************************************") + + +version = "0.1" + +onto.metadata.title.append(en("microstructureonto")) +onto.metadata.creator.append(en("Sylvain Gouttebroze")) +onto.metadata.creator.append(en("Jesper Friis")) +onto.metadata.creator.append(en("Francesca Lønstad Bleken")) +onto.metadata.contributor.append(en("SINTEF")) +onto.metadata.publisher.append(en("EMMC ASBL???")) +onto.metadata.license.append( + en("https://creativecommons.org/licenses/by/4.0/legalcode") +) +onto.metadata.versionInfo.append(en(version)) +onto.metadata.comment.append( + en( + "The EMMO requires FacT++ reasoner plugin in order to visualize all " + "inferences and class hierarchy (ctrl+R hotkey in Protege)." + ) +) +onto.metadata.comment.append( + en( + "This ontology is generated with EMMOntoPy using data from a dedicated" + "Excel sheet developed by the domain experts." + ) +) + +# Synchronise Python attributes to ontology +onto.sync_attributes( + name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" +) +onto.dir_label = False + +write_catalog(catalog, output="catalog-v001.xml") + +""" +# Hack to ensure that we import using versionURI +# FIXME: included this in sync_attributes() +d = {o.base_iri.rstrip('/#'): o.get_version(as_iri=True) + for o in onto.imported_ontologies} +for abbrev_iri in onto.world._get_obj_triples_sp_o( + onto.storid, owlready2.owl_imports): + iri = onto._unabbreviate(abbrev_iri) + version_iri = d[iri] + onto._del_obj_triple_spo( + onto.storid, + owlready2.owl_imports, + abbrev_iri) + onto._add_obj_triple_spo( + onto.storid, + owlready2.owl_imports, + onto._abbreviate(version_iri)) +""" + +# Save new ontology as turtle +onto.save( + os.path.join("microstructureonto.ttl"), format="turtle", overwrite=True +) From e7e2df37922dc39e5093df05d5086da54808063b Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 17:41:25 +0100 Subject: [PATCH 03/29] Added module excelparser which is used by excel2onto Added example folder --- .../ontology_template.xlsx | Bin 0 -> 20395 bytes examples/ontology-from-excel/tool/onto.xlsx | Bin 0 -> 23244 bytes ontopy/excelparser.py | 138 ++++++++++++++++++ setup.py | 1 + tools/excel2onto | 108 +------------- 5 files changed, 145 insertions(+), 102 deletions(-) create mode 100755 examples/ontology-from-excel/ontology_template.xlsx create mode 100755 examples/ontology-from-excel/tool/onto.xlsx create mode 100755 ontopy/excelparser.py diff --git a/examples/ontology-from-excel/ontology_template.xlsx b/examples/ontology-from-excel/ontology_template.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..cbbe020e3b4c992ebdc1f3980988e138cd5e5e59 GIT binary patch literal 20395 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 literal 0 HcmV?d00001 diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py new file mode 100755 index 000000000..a2d55b9c4 --- /dev/null +++ b/ontopy/excelparser.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +""" +Module from parsing an excelfile and creating an +ontology from it. + +The excelfile is read by pandas and the pandas +dataframe should have column names: +[ +""" +import argparse +import sys +import pyparsing +import pandas as pd +from ontopy import World +from ontopy.utils import NoSuchLabelError +from ontopy.manchester import evaluate +import owlready2 # pylint: disable=C0411 + + +def english(string): + """Returns `string` as an English location string.""" + return owlready2.locstr(string, lang="en") + +def create_ontology_from_excel(excelpath: str, base_iri: str = + "http://emmo.info/emmo/domain/onto#" ) -> pd.DataFrame: + # Read datafile + dataframe = pd.read_excel(excelpath, skiprows=[0, 2]) + # Some magic to identify the header row + return create_ontology_from_pandas(dataframe, base_iri) + + +def create_ontology_from_pandas(data: pd.DataFrame, base_iri: str = + "http://emmo.info/emmo/domain/onto#" ) -> owlready2.Ontology: + + # Make new ontology and import ontologies + world = World() + + # have to decide how to add metadata and imports etc. + # base_iri to be added from excel (maybe also possibly argument?) + onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") + onto.base_iri = "http://emmo.info/emmo/domain/onto#" + + # imported ontologies to be added from excel + catalog = {} + imported_ontology_paths = [ + ( + "https://raw.githubusercontent.com/emmo-repo/" + "emmo-repo.github.io/master/versions/" + "1.0.0-beta/emmo-inferred-chemistry2.ttl" + ) + ] + + # Add imported ontologies + for path in imported_ontology_paths: + imported = world.get_ontology(path).load() + onto.imported_ontologies.append(imported) + catalog[imported.base_iri.rstrip("/")] = path + + onto.sync_python_names() + + with onto: + # loop through the rows until no more are added + new_loop = True + final_loop = False + while new_loop: + number_of_added_classes = 0 + for _, row in data.iterrows(): + name = row["prefLabel"] + try: + if isinstance( + onto.get_by_label(name), owlready2.ThingClass + ): + continue + except NoSuchLabelError: + pass + + parent_names = str(row["subClassOf"]).split(";") + + try: + parents = [onto.get_by_label(pn) for pn in parent_names] + except NoSuchLabelError: + if final_loop is True: + parents = onto.EMMO + + # make warning! + print("--------------------------------") + print( + "At least one of the defined parents do not exist" + ) + print( + "Concept:", name, "; Defined parents", parent_names + ) + print("--------------------------------") + new_loop = False + else: + continue + + concept = onto.new_entity(name, parents) + + elucidation = row["Elucidation"] + if isinstance(elucidation, str): + concept.elucidation.append(english(elucidation)) + + examples = row["Examples"] + if isinstance(examples, str): + example_list = examples.split(";") + for example in example_list: + concept.example.append(english(example)) + + comments = row["Comments"] + if isinstance(comments, str): + comment_list = comments.split(";") + for comment in comment_list: + concept.comment.append(english(comment)) + + number_of_added_classes += 1 + + if number_of_added_classes == 0: + final_loop = True + + # Add properties in a second loop + for _, row in data.iterrows(): + properties = row["Properties"] + if isinstance(properties, str): + concept = onto.get_by_label(row["Concept (prefLabel)"]) + props = properties.split(";") + for prop in props: + try: + concept.is_a.append(evaluate(onto, prop)) + except pyparsing.ParseException as err: + # make warning! + print("*******************************************") + print("Error in Property assignment for:", concept) + print("Property to be Evaluated: ", prop) + print(err) + print("*******************************************") + + return onto diff --git a/setup.py b/setup.py index 228fe9b05..34b10fc30 100644 --- a/setup.py +++ b/setup.py @@ -108,6 +108,7 @@ def fglob(patt): "tools/emmocheck", "tools/ontoconvert", "tools/ontoversion", + "tools/excel2onto", ], package_data={ "ontopy.factpluspluswrapper.java.lib.so": ["*"], diff --git a/tools/excel2onto b/tools/excel2onto index b96a86914..9a3eb21ee 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -11,6 +11,7 @@ import pandas as pd from ontopy import World from ontopy.utils import NoSuchLabelError from ontopy.manchester import evaluate +from ontopy.excelparser import create_ontology_from_excel import owlready2 # pylint: disable=C0411 @@ -37,110 +38,13 @@ def main(): except SystemExit as exc: sys.exit(exc.code) # Exit without traceback on invalid arguments - # Read datafile - data = pd.read_excel(args.excelpath, skiprows=[0, 2]) - # Make new ontology and import ontologies - world = World() - # base_iri to be added from excel (maybe also possibly argument?) - onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") - onto.base_iri = "http://emmo.info/emmo/domain/onto#" - - # imported ontologies to be added from excel - catalog = {} - imported_ontology_paths = [ - ( - "https://raw.githubusercontent.com/emmo-repo/" - "emmo-repo.github.io/master/versions/" - "1.0.0-beta/emmo-inferred-chemistry2.ttl" - ) - ] - - # Add imported ontologies - for path in imported_ontology_paths: - imported = world.get_ontology(path).load() - onto.imported_ontologies.append(imported) - catalog[imported.base_iri.rstrip("/")] = path - - onto.sync_python_names() - - with onto: - # loop through the rows until no more are added - new_loop = True - final_loop = False - while new_loop: - number_of_added_classes = 0 - for _, row in data.iterrows(): - name = row["prefLabel"] - try: - if isinstance( - onto.get_by_label(name), owlready2.ThingClass - ): - continue - except NoSuchLabelError: - pass - - parent_names = str(row["subClassOf"]).split(";") - - try: - parents = [onto.get_by_label(pn) for pn in parent_names] - except NoSuchLabelError: - if final_loop is True: - parents = onto.EMMO - - # make warning! - print("--------------------------------") - print( - "At least one of the defined parents do not exist" - ) - print( - "Concept:", name, "; Defined parents", parent_names - ) - print("--------------------------------") - new_loop = False - else: - continue - - concept = onto.new_entity(name, parents) - - elucidation = row["Elucidation"] - if isinstance(elucidation, str): - concept.elucidation.append(english(elucidation)) - - examples = row["Examples"] - if isinstance(examples, str): - example_list = examples.split(";") - for example in example_list: - concept.example.append(english(example)) - - comments = row["Comments"] - if isinstance(comments, str): - comment_list = comments.split(";") - for comment in comment_list: - concept.comment.append(english(comment)) - - number_of_added_classes += 1 - - if number_of_added_classes == 0: - final_loop = True - - # Add properties in a second loop - for _, row in data.iterrows(): - properties = row["Properties"] - if isinstance(properties, str): - concept = onto.get_by_label(row["Concept (prefLabel)"]) - props = properties.split(";") - for prop in props: - try: - concept.is_a.append(evaluate(onto, prop)) - except pyparsing.ParseException as err: - # make warning! - print("*******************************************") - print("Error in Property assignment for:", concept) - print("Property to be Evaluated: ", prop) - print(err) - print("*******************************************") + onto = create_ontology_from_excel(args.excelpath) + # Save new ontology as turtle + onto.save( + os.path.join(arg.name), format="turtle", overwrite=True + ) if __name__ == "__main__": main() From 8db19da41d11352216cd096f80baa1c2a6ee2bc9 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 17:52:50 +0100 Subject: [PATCH 04/29] Added choice for sheetname for Concepts --- ontopy/excelparser.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index a2d55b9c4..5e379bcad 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -21,10 +21,10 @@ def english(string): """Returns `string` as an English location string.""" return owlready2.locstr(string, lang="en") -def create_ontology_from_excel(excelpath: str, base_iri: str = +def create_ontology_from_excel(excelpath: str, sheet_name: str = "Concepts", base_iri: str = "http://emmo.info/emmo/domain/onto#" ) -> pd.DataFrame: # Read datafile - dataframe = pd.read_excel(excelpath, skiprows=[0, 2]) + dataframe = pd.read_excel(excelpath, sheet_name=sheet_name, skiprows=[0, 2]) # Some magic to identify the header row return create_ontology_from_pandas(dataframe, base_iri) @@ -57,7 +57,6 @@ def create_ontology_from_pandas(data: pd.DataFrame, base_iri: str = catalog[imported.base_iri.rstrip("/")] = path onto.sync_python_names() - with onto: # loop through the rows until no more are added new_loop = True From dd5794adf56e4d1d1efd5a58ead6ceef5239abcf Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 18:32:36 +0100 Subject: [PATCH 05/29] Cleaned up dataframe to be analysed removed rows with missing value in prefLabel Convert prefLabel to string --- docs/api_reference/ontopy/excelparser.md | 3 ++ examples/ontology-from-excel/tool/onto.xlsx | Bin 23244 -> 23267 bytes ontopy/excelparser.py | 34 ++++++++++++++------ tools/excel2onto | 14 +++----- 4 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 docs/api_reference/ontopy/excelparser.md diff --git a/docs/api_reference/ontopy/excelparser.md b/docs/api_reference/ontopy/excelparser.md new file mode 100644 index 000000000..9883971c0 --- /dev/null +++ b/docs/api_reference/ontopy/excelparser.md @@ -0,0 +1,3 @@ +# excelparser + +::: ontopy.excelparser diff --git a/examples/ontology-from-excel/tool/onto.xlsx b/examples/ontology-from-excel/tool/onto.xlsx index 81a421a99342ef8b08128ca7a78da84353364900..bf696633e12fb1a8df051e984f8d49006344f98f 100755 GIT binary patch delta 4288 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 Y{{t-k27k2w0c=3EF_Z+X_wPRc0vF;oJOBUy delta 4299 zcmZ8kcQD+I*4`z0ZwV_{tC#345p}f?qO(f0NaBqiQ9}H*2!gObC0I4;vZ4i%=maZz z*|5P1ubv=k)cfB1ee>O!@BDG*ne&`Eb7synbIw`%0R8#_TEk97ap)JrR}FGei2@XR z41Yc6XlqEHt;7yBzDXx9wWat9n<&Qq0@~dS#sll^+(T^)Jw2KF9z7hUUtMVQde>?y zD>Hv1Anf4=>?iI0x?diJmml$F1y7;{9q+*A$6j6-Qk@ffx7%}lnuG5@y{Lj}DogI$ z;nn353(Gx>V&&&27)`{b><}(ud5J*bwX`&(afK&$x190FW17ui^% zV*@B3SHO^}36!HWw#H_Eus3JKt=8&O_=HB-*2fMIXetro2NOA`6}WiCx_`E`NIS`X(lu`9$SPE71FXH=U^dN;YmBJd(LJ*eaN zd}qy{!N;7%iXK8yq!%nhYQFXRulEuZ_ro))^-eBSJ*-M$j!*jG_2@fxQUQD!VMqyA=w~%$0Uj|DEu6| zBD__+QsDbD<3dqRtFT7Xi3CU_7RU8JZ|1L?)*JiEa@}%37H*cypvcm&TJu&%M9hN< zX(iTGy&e1|_m=dB7eDDKz3dA{PHmQ=(+2$J&ZuNTZQcF|<{|H|BLLI2V1c4mXP@Fx z(jU3jsN%WQYXZ?W%d2Wisk>k}S)(&&7sQ1?6ci#@MuA)l};9_Jo`Q9%`T_<5zN z3Y%z47|(TF6kfM}v6DA8v{NncVX~2_O5zWtLx+0#<-wl6Jdb*f`7~T-E6Z7K`&?_r zf+111k=%x0z&}Ihn0f%P!^(MkpBA>GX5<2Pkm2q>d&Cj&*aueuuV^ zl12i@TQN)lfmnj?S@;2apII69@cf2L=0CZD!%0_Ct=VIzJ(wn{N51%VAd=;Y>{yS> z7k!M8h6ZU?i0dM|K{xyO?rt*`?dH85cW4yq3Xi)zZI0RvbS&aq$b5G_WHzM{k>rVr z&&$#~3ff*UJ~H<@h?QM}A}fs=WJ`0dM3!<3#~r%&*#%n|3B>`C_8%An$~Y^o8z^Y8 z$D-iWK4v2_W=+2REh}j^1m|d`v-5OnV>x%;D}SCK&najcr73Fs~Y8S{XA)+bQA)<-xDx%X{?|^ z!yfwM5HeypMwA2=_j@>U2Yx7{-9_Y7r4(m&u{uCqSgO!Eg6Bnl=74CH{^H||;`%Yq zGv-A}Ag-S5Qa5NKp__(SeY?{>=qTQpio)tD*xMWo zV^EUM2{@wj;bGk%HK`0bd9b(mYnJQ7rNS^VGZN%5K0nhp%_@hWD9`HUgiLW~1(Ij- zsRrHx(^l$qJ=OG;SxHk8Z8x7EAEhllR%TZM*;RJd;ToZ%jAtmM3@piuy1N$h}P_^D36*8QKI|%xAD^bfvW!$5UU$ z63(pCcIQvqd%x52kfVWv=#0B?dyYo?2e!@J0xr8Rtd@#Q3zJq~3W+*Al&f;zG}=9| zSo*7gxVC1PVDECn-Zo)74bPQu*QzRI&4*)gZi6A zi@UHMbUEEQy5Fe5@Em|0G38pB_pYn_y4SZ}@j|_3S~r(xy5WR(ufUm*G-J&? zlW#}pi*KM$gUxch)yhr@~a zL%rz+f51dNdg{$5B`D`R$l%b@_1^QZb#>l5ruS_s3LM8ul7^e7vWM048SqNvD_*w( zXWjv`4*C;x8_q06kEU|ySMA~%)D9R#LVL@NCrN^&DgVYr!@sph=>&WpUuyBtty0bT z3ovSIa#%<|Z!KSpZQ{uDPV)1q z6!@`wKDu>E8I=CA$z6za+!-3yzkifkm>zWOigQh>I5XX#DEmV{%$Xo(%6vVv(B8So2?Dis404B{L6rCCZ+B zAL>x))dTc%VML;iqqF~?v$9K7b#(-ndgw8~umj%^qe&>?6YIKScLEaA&@?c?z*Amj zrA1<0C2^fRw%-hl7RdJMM2?eB)hUEDTJ`xQv`ciZN4DaPq1&_!LnK3wTENWrWhJ}B z7|7V#y<91u>Ze{vN%hJy>-iLpnB~PtTgV}-+b(bvkG~0ZHws7$&N^(;N%x(ZQYTa* z%olx=&E{PpnTj*}->1|})=IIqR7vVygQJY6*D8Y3cbs~kL!fh9vLR!rSEbStmns_f zr(4Bk_D-ty%_=Wi+J6@X=#=>F9o;oi6ZR)Cg*mwtDZ>liaQiKNb!OsTMBR#DOx`$HAe=1)VWbVB|8MAn04i(F0KEmD+~oX zO_pSsW48@HBbP%rR7`v9yi%N}*bF4hdJ=MKU;XfMwLeTtQ6`?YaR!c;;xxC0mj0X% zecjG-Y*l`CNU8q#$x4hdEjlvQ+M_-jeDyb?T@a<|l2(q3ytxifsodCqAk33F-7W3I z6FkXWXCN18q%872F4+RMETMq7Ths;gEWbWT>fk)#c&1(5OZynbeyst@Zdg!2^Y&A! zL8F0?elhX5g-Y~JVJsy*C0;o3*9Yo08YlHNc`Ce~+v<CoB*=RKFbGb%wwf*Uj2c(mqb<;#0O3|u$x zblc}g#a2tK;#=MZ3!zKG=!fY_W|Y2JOa=AMtjpO{;rN)YB>_QlJX^WOu+ef_z4pit z`*YE_ESKxAZ2_Us%vTD0+J>ze0)l*(ym*#!9yIHT!7r3AC}bP)2?Kk)>o#7WrTrSNW?HazW}TKr|h z_wPZ2&ryu^;|3q;{`W0Uu{6K3NDG0W>0oFpai|6;VI{%+f5$%u1j6~xR{O7If__%I z&>XPIN)rkLkFDU`|9=DiH`fl7x7H#P7X_WgxWQCw1u{vof1nV!Wi3u7Ee?9w2!gk5 zq@f0&r_C*}!4?L!13PVm!3-Tn#{U+9K#d<^J9i;{h1Se3MWYfl=i``X_ m&x97tv1SH!?O@RFptGG3*^=3R2uX8VaLA6Ca>L@^o%{=thZ)ZR diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 5e379bcad..a9bfcc0a2 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -7,8 +7,6 @@ dataframe should have column names: [ """ -import argparse -import sys import pyparsing import pandas as pd from ontopy import World @@ -21,24 +19,39 @@ def english(string): """Returns `string` as an English location string.""" return owlready2.locstr(string, lang="en") -def create_ontology_from_excel(excelpath: str, sheet_name: str = "Concepts", base_iri: str = - "http://emmo.info/emmo/domain/onto#" ) -> pd.DataFrame: + +def create_ontology_from_excel( + excelpath: str, + sheet_name: str = "Concepts", + base_iri: str = "http://emmo.info/emmo/domain/onto#", +) -> pd.DataFrame: + """ + Creates an ontology from an excelfile. + """ # Read datafile dataframe = pd.read_excel(excelpath, sheet_name=sheet_name, skiprows=[0, 2]) + dataframe = dataframe[dataframe["prefLabel"].notna()] # Some magic to identify the header row return create_ontology_from_pandas(dataframe, base_iri) -def create_ontology_from_pandas(data: pd.DataFrame, base_iri: str = - "http://emmo.info/emmo/domain/onto#" ) -> owlready2.Ontology: +def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-branches,too-many-statements + data: pd.DataFrame, base_iri: str = "http://emmo.info/emmo/domain/onto#" +) -> owlready2.Ontology: + """ + Create an ontology from a pandas DataFrame + """ + # Remove Concepts without prefLabel and make all to string + data = data[data["prefLabel"].notna()] + data = data.astype({"prefLabel": "str"}) # Make new ontology and import ontologies world = World() # have to decide how to add metadata and imports etc. # base_iri to be added from excel (maybe also possibly argument?) onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") - onto.base_iri = "http://emmo.info/emmo/domain/onto#" + onto.base_iri = base_iri # imported ontologies to be added from excel catalog = {} @@ -119,9 +132,12 @@ def create_ontology_from_pandas(data: pd.DataFrame, base_iri: str = # Add properties in a second loop for _, row in data.iterrows(): - properties = row["Properties"] + properties = row["Relations"] if isinstance(properties, str): - concept = onto.get_by_label(row["Concept (prefLabel)"]) + try: + concept = onto.get_by_label(row["prefLabel"]) + except NoSuchLabelError: + pass props = properties.split(";") for prop in props: try: diff --git a/tools/excel2onto b/tools/excel2onto index 9a3eb21ee..1db6c0e21 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -6,11 +6,7 @@ ontology_template.xlsx """ import argparse import sys -import pyparsing -import pandas as pd -from ontopy import World -from ontopy.utils import NoSuchLabelError -from ontopy.manchester import evaluate +import os from ontopy.excelparser import create_ontology_from_excel import owlready2 # pylint: disable=C0411 @@ -38,13 +34,11 @@ def main(): except SystemExit as exc: sys.exit(exc.code) # Exit without traceback on invalid arguments - - onto = create_ontology_from_excel(args.excelpath) + onto = create_ontology_from_excel(args.excelpath) # Save new ontology as turtle - onto.save( - os.path.join(arg.name), format="turtle", overwrite=True - ) + onto.save(os.path.join(args.name), format="turtle", overwrite=True) + if __name__ == "__main__": main() From 7db9a8e84b139c38cdb7d91fca8ac4894ea613e7 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 22:16:12 +0100 Subject: [PATCH 06/29] Added option to read base_iri from metadata --- .../make_microstructure_onto.py | 159 +----------------- examples/ontology-from-excel/onto.xlsx | Bin 0 -> 23396 bytes .../ontology_template.xlsx | Bin 20395 -> 0 bytes ontopy/excelparser.py | 37 ++-- tools/excel2onto | 6 +- 5 files changed, 34 insertions(+), 168 deletions(-) create mode 100755 examples/ontology-from-excel/onto.xlsx delete mode 100755 examples/ontology-from-excel/ontology_template.xlsx diff --git a/examples/ontology-from-excel/make_microstructure_onto.py b/examples/ontology-from-excel/make_microstructure_onto.py index 931917e25..dae12d6e6 100755 --- a/examples/ontology-from-excel/make_microstructure_onto.py +++ b/examples/ontology-from-excel/make_microstructure_onto.py @@ -1,159 +1,6 @@ -from ontopy import World, get_ontology -from ontopy.utils import NoSuchLabelError, write_catalog -from ontopy.manchester import evaluate -import owlready2 - -import pyparsing - -import pandas as pd -import os -import numpy as np - - -def en(s): - """Returns `s` as an English location string.""" - return owlready2.locstr(s, lang="en") - - -world = World() -chemistry_ontology_path = ( - "https://raw.githubusercontent.com/emmo-repo/" - "emmo-repo.github.io/master/versions/" - "1.0.0-beta/emmo-inferred-chemistry2.ttl" -) - -chemistry = world.get_ontology(chemistry_ontology_path).load() - -catalog = {chemistry.base_iri.rstrip("/"): chemistry_ontology_path} - - -# Create new ontology -onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") -onto.base_iri = "http://emmo.info/emmo/domain/onto#" -onto.imported_ontologies.append(chemistry) -onto.sync_python_names() - - -# Read datafile -data = pd.read_excel("onto.xlsx", skiprows=1) - - -with onto: - # loop through the rows until no more are added - new_loop = True - final_loop = False - while new_loop: - number_of_added_classes = 0 - for index, row in data.iterrows(): - name = row["Concept (prefLabel)"] - try: - if isinstance(onto.get_by_label(name), owlready2.ThingClass): - continue - except NoSuchLabelError: - pass - - parent_names = str(row["subClassOf"]).split(";") - - try: - parents = [onto.get_by_label(pn) for pn in parent_names] - except NoSuchLabelError: - if final_loop == True: - parents = onto.EMMO - print("--------------------------------") - print("At least one of the defined parents do not exist") - print("Concept:", name, "; Defined parents", parent_names) - print("--------------------------------") - new_loop = False - else: - continue - - Concept = onto.new_entity(name, parents) - - elucidation = row["Elucidation (definition intended for humans)"] - if isinstance(elucidation, str): - Concept.elucidation.append(en(elucidation)) - - example = row["Example"] - if isinstance(example, str): - Concept.example.append(en(example)) - - number_of_added_classes += 1 - - if number_of_added_classes == 0: - final_loop = True - - -# Add properties in a second loop -for index, row in data.iterrows(): - properties = row["Properties"] - if isinstance(properties, str): - Concept = onto.get_by_label(row["Concept (prefLabel)"]) - props = properties.split(";") - for p in props: - try: - r = evaluate(onto, p) - Concept.is_a.append(r) - except pyparsing.ParseException as err: - print("*******************************************") - print("Error in Property assignment for:", Concept) - print("Property to be Evaluated: ", p) - print(err) - print("*******************************************") - - -version = "0.1" - -onto.metadata.title.append(en("microstructureonto")) -onto.metadata.creator.append(en("Sylvain Gouttebroze")) -onto.metadata.creator.append(en("Jesper Friis")) -onto.metadata.creator.append(en("Francesca Lønstad Bleken")) -onto.metadata.contributor.append(en("SINTEF")) -onto.metadata.publisher.append(en("EMMC ASBL???")) -onto.metadata.license.append( - en("https://creativecommons.org/licenses/by/4.0/legalcode") -) -onto.metadata.versionInfo.append(en(version)) -onto.metadata.comment.append( - en( - "The EMMO requires FacT++ reasoner plugin in order to visualize all " - "inferences and class hierarchy (ctrl+R hotkey in Protege)." - ) -) -onto.metadata.comment.append( - en( - "This ontology is generated with EMMOntoPy using data from a dedicated" - "Excel sheet developed by the domain experts." - ) -) - -# Synchronise Python attributes to ontology -onto.sync_attributes( - name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" -) -onto.dir_label = False - -write_catalog(catalog, output="catalog-v001.xml") - """ -# Hack to ensure that we import using versionURI -# FIXME: included this in sync_attributes() -d = {o.base_iri.rstrip('/#'): o.get_version(as_iri=True) - for o in onto.imported_ontologies} -for abbrev_iri in onto.world._get_obj_triples_sp_o( - onto.storid, owlready2.owl_imports): - iri = onto._unabbreviate(abbrev_iri) - version_iri = d[iri] - onto._del_obj_triple_spo( - onto.storid, - owlready2.owl_imports, - abbrev_iri) - onto._add_obj_triple_spo( - onto.storid, - owlready2.owl_imports, - onto._abbreviate(version_iri)) +python example for creating ontology from excel """ +from ontopy.excelparser import create_ontology_from_excel -# Save new ontology as turtle -onto.save( - os.path.join("microstructureonto.ttl"), format="turtle", overwrite=True -) +ontology, catalog = create_ontology_from_excel("onto.xlsx") diff --git a/examples/ontology-from-excel/onto.xlsx b/examples/ontology-from-excel/onto.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..2cf918f1387714e4a04e829bad792a34b803d046 GIT binary patch literal 23396 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 pd.DataFrame: +) -> (owlready2.Ontology, dict): """ Creates an ontology from an excelfile. """ - # Read datafile - dataframe = pd.read_excel(excelpath, sheet_name=sheet_name, skiprows=[0, 2]) - dataframe = dataframe[dataframe["prefLabel"].notna()] - # Some magic to identify the header row - return create_ontology_from_pandas(dataframe, base_iri) + # Read datafile TODO: Some magic to identify the header row + conceptdata = pd.read_excel( + excelpath, sheet_name=concept_sheet_name, skiprows=[0, 2] + ) + metadata = pd.read_excel(excelpath, sheet_name=metadata_sheet_name) + return create_ontology_from_pandas(conceptdata, metadata, base_iri) def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-branches,too-many-statements - data: pd.DataFrame, base_iri: str = "http://emmo.info/emmo/domain/onto#" -) -> owlready2.Ontology: + data: pd.DataFrame, + metadata: pd.DataFrame, + base_iri: str = "http://emmo.info/emmo/domain/onto#", + base_iri_from_metadata: bool = True, +) -> (owlready2.Ontology, dict): """ Create an ontology from a pandas DataFrame """ @@ -45,6 +50,18 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra # Remove Concepts without prefLabel and make all to string data = data[data["prefLabel"].notna()] data = data.astype({"prefLabel": "str"}) + # base_iri from metadata if it exists and base_iri_from_metadata + if base_iri_from_metadata: + try: + base_iri = ( + metadata.loc[metadata["Metadata name"] == "Ontology IRI"][ + "Value" + ].item() + + "#" + ) + except (TypeError, ValueError): + pass + # Make new ontology and import ontologies world = World() @@ -150,4 +167,4 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra print(err) print("*******************************************") - return onto + return onto, catalog diff --git a/tools/excel2onto b/tools/excel2onto index 1db6c0e21..47b8d51bd 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -8,6 +8,7 @@ import argparse import sys import os from ontopy.excelparser import create_ontology_from_excel +from ontopy.utils import write_catalog import owlready2 # pylint: disable=C0411 @@ -34,10 +35,11 @@ def main(): except SystemExit as exc: sys.exit(exc.code) # Exit without traceback on invalid arguments - onto = create_ontology_from_excel(args.excelpath) + ontology, catalog = create_ontology_from_excel(args.excelpath) # Save new ontology as turtle - onto.save(os.path.join(args.name), format="turtle", overwrite=True) + ontology.save(os.path.join(args.name), format="turtle", overwrite=True) + write_catalog(catalog) if __name__ == "__main__": From 991278f224cd433bdc584a9e45ddf77cc0cff3df Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 1 Dec 2021 23:17:32 +0100 Subject: [PATCH 07/29] Added import ontologies from excel --- .../make_microstructure_onto.py | 4 ++ examples/ontology-from-excel/tool/onto.xlsx | Bin 23267 -> 23380 bytes ontopy/excelparser.py | 58 ++++++++++-------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/examples/ontology-from-excel/make_microstructure_onto.py b/examples/ontology-from-excel/make_microstructure_onto.py index dae12d6e6..87a1b799c 100755 --- a/examples/ontology-from-excel/make_microstructure_onto.py +++ b/examples/ontology-from-excel/make_microstructure_onto.py @@ -2,5 +2,9 @@ python example for creating ontology from excel """ from ontopy.excelparser import create_ontology_from_excel +from ontopy.utils import write_catalog ontology, catalog = create_ontology_from_excel("onto.xlsx") + +ontology.save("microstructure_ontology.ttl", format="turtle", overwrite=True) +write_catalog(catalog) diff --git a/examples/ontology-from-excel/tool/onto.xlsx b/examples/ontology-from-excel/tool/onto.xlsx index bf696633e12fb1a8df051e984f8d49006344f98f..9ffc4c43bc838de6517f7bdd4e014096fb8babc9 100755 GIT binary patch delta 4727 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 mKsyEiuN5nha*q}$v6KWI8veJrX{i7@GyV% (owlready2.Ontology, dict): """ Creates an ontology from an excelfile. + + catalog is dict of imported ontologies with key name and value path """ # Read datafile TODO: Some magic to identify the header row conceptdata = pd.read_excel( excelpath, sheet_name=concept_sheet_name, skiprows=[0, 2] ) metadata = pd.read_excel(excelpath, sheet_name=metadata_sheet_name) - return create_ontology_from_pandas(conceptdata, metadata, base_iri) + return create_ontology_from_pandas( + conceptdata, metadata, base_iri, base_iri_from_metadata, catalog + ) def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-branches,too-many-statements @@ -42,6 +49,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra metadata: pd.DataFrame, base_iri: str = "http://emmo.info/emmo/domain/onto#", base_iri_from_metadata: bool = True, + catalog: dict = None, ) -> (owlready2.Ontology, dict): """ Create an ontology from a pandas DataFrame @@ -50,6 +58,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra # Remove Concepts without prefLabel and make all to string data = data[data["prefLabel"].notna()] data = data.astype({"prefLabel": "str"}) + # base_iri from metadata if it exists and base_iri_from_metadata if base_iri_from_metadata: try: @@ -67,20 +76,22 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra # have to decide how to add metadata and imports etc. # base_iri to be added from excel (maybe also possibly argument?) - onto = world.get_ontology("http://emmo.info/emmo/domain/onto#") + onto = world.get_ontology(base_iri) onto.base_iri = base_iri - # imported ontologies to be added from excel - catalog = {} - imported_ontology_paths = [ - ( - "https://raw.githubusercontent.com/emmo-repo/" - "emmo-repo.github.io/master/versions/" - "1.0.0-beta/emmo-inferred-chemistry2.ttl" + # Get imported ontologies from metadata + try: + imported_ontology_paths = ( + metadata.loc[metadata["Metadata name"] == "Imported ontologies"][ + "Value" + ] + .item() + .split(";") ) - ] - + except (TypeError, ValueError, AttributeError): + imported_ontology_paths = [] # Add imported ontologies + catalog = {} if catalog is None else catalog for path in imported_ontology_paths: imported = world.get_ontology(path).load() onto.imported_ontologies.append(imported) @@ -111,15 +122,10 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra if final_loop is True: parents = onto.EMMO - # make warning! - print("--------------------------------") - print( - "At least one of the defined parents do not exist" - ) - print( - "Concept:", name, "; Defined parents", parent_names + warnings.warn( + "At least one of the defined parents do not exist. " + f"Concept: {name}; Defined parents: {parent_names}" ) - print("--------------------------------") new_loop = False else: continue @@ -160,11 +166,9 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra try: concept.is_a.append(evaluate(onto, prop)) except pyparsing.ParseException as err: - # make warning! - print("*******************************************") - print("Error in Property assignment for:", concept) - print("Property to be Evaluated: ", prop) - print(err) - print("*******************************************") - + warnings.warn( + f"Error in Property assignment for: {concept}. " + f"Property to be Evaluated: {prop}. " + f"Error is {err}." + ) return onto, catalog From ed11bcfd7e822d73d609a094b07286b5f465b561 Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 2 Dec 2021 10:30:19 +0100 Subject: [PATCH 08/29] Try to fix documentation --- docs/api_reference/emmopy/.pages | 2 -- docs/api_reference/emmopy/emmocheck.md | 5 ----- docs/api_reference/emmopy/emmopy.md | 3 --- docs/api_reference/ontopy/.pages | 2 -- docs/api_reference/ontopy/colortest.md | 3 --- docs/api_reference/ontopy/excelparser.md | 3 --- docs/api_reference/ontopy/factpluspluswrapper/.pages | 2 -- docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md | 3 --- .../ontopy/factpluspluswrapper/owlapi_interface.md | 3 --- docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md | 3 --- docs/api_reference/ontopy/graph.md | 3 --- docs/api_reference/ontopy/manchester.md | 3 --- docs/api_reference/ontopy/nadict.md | 3 --- docs/api_reference/ontopy/ontodoc.md | 3 --- docs/api_reference/ontopy/ontograph.md | 3 --- docs/api_reference/ontopy/ontology.md | 3 --- docs/api_reference/ontopy/patch.md | 3 --- docs/api_reference/ontopy/utils.md | 3 --- 18 files changed, 53 deletions(-) delete mode 100644 docs/api_reference/emmopy/.pages delete mode 100644 docs/api_reference/emmopy/emmocheck.md delete mode 100644 docs/api_reference/emmopy/emmopy.md delete mode 100644 docs/api_reference/ontopy/.pages delete mode 100644 docs/api_reference/ontopy/colortest.md delete mode 100644 docs/api_reference/ontopy/excelparser.md delete mode 100644 docs/api_reference/ontopy/factpluspluswrapper/.pages delete mode 100644 docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md delete mode 100644 docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md delete mode 100644 docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md delete mode 100644 docs/api_reference/ontopy/graph.md delete mode 100644 docs/api_reference/ontopy/manchester.md delete mode 100644 docs/api_reference/ontopy/nadict.md delete mode 100644 docs/api_reference/ontopy/ontodoc.md delete mode 100644 docs/api_reference/ontopy/ontograph.md delete mode 100644 docs/api_reference/ontopy/ontology.md delete mode 100644 docs/api_reference/ontopy/patch.md delete mode 100644 docs/api_reference/ontopy/utils.md diff --git a/docs/api_reference/emmopy/.pages b/docs/api_reference/emmopy/.pages deleted file mode 100644 index 1f6fed708..000000000 --- a/docs/api_reference/emmopy/.pages +++ /dev/null @@ -1,2 +0,0 @@ -title: "emmopy" -collapse_single_pages: false diff --git a/docs/api_reference/emmopy/emmocheck.md b/docs/api_reference/emmopy/emmocheck.md deleted file mode 100644 index 17c16dc05..000000000 --- a/docs/api_reference/emmopy/emmocheck.md +++ /dev/null @@ -1,5 +0,0 @@ -# emmocheck - -::: emmopy.emmocheck - rendering: - show_bases: false diff --git a/docs/api_reference/emmopy/emmopy.md b/docs/api_reference/emmopy/emmopy.md deleted file mode 100644 index 04fdb26a0..000000000 --- a/docs/api_reference/emmopy/emmopy.md +++ /dev/null @@ -1,3 +0,0 @@ -# emmopy - -::: emmopy.emmopy diff --git a/docs/api_reference/ontopy/.pages b/docs/api_reference/ontopy/.pages deleted file mode 100644 index 01e236003..000000000 --- a/docs/api_reference/ontopy/.pages +++ /dev/null @@ -1,2 +0,0 @@ -title: "ontopy" -collapse_single_pages: false diff --git a/docs/api_reference/ontopy/colortest.md b/docs/api_reference/ontopy/colortest.md deleted file mode 100644 index 74a6d3bd1..000000000 --- a/docs/api_reference/ontopy/colortest.md +++ /dev/null @@ -1,3 +0,0 @@ -# colortest - -::: ontopy.colortest diff --git a/docs/api_reference/ontopy/excelparser.md b/docs/api_reference/ontopy/excelparser.md deleted file mode 100644 index 9883971c0..000000000 --- a/docs/api_reference/ontopy/excelparser.md +++ /dev/null @@ -1,3 +0,0 @@ -# excelparser - -::: ontopy.excelparser diff --git a/docs/api_reference/ontopy/factpluspluswrapper/.pages b/docs/api_reference/ontopy/factpluspluswrapper/.pages deleted file mode 100644 index a117fa2ee..000000000 --- a/docs/api_reference/ontopy/factpluspluswrapper/.pages +++ /dev/null @@ -1,2 +0,0 @@ -title: "factpluspluswrapper" -collapse_single_pages: false diff --git a/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md b/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md deleted file mode 100644 index bc85098da..000000000 --- a/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md +++ /dev/null @@ -1,3 +0,0 @@ -# factppgraph - -::: ontopy.factpluspluswrapper.factppgraph diff --git a/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md b/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md deleted file mode 100644 index f12d7b42a..000000000 --- a/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md +++ /dev/null @@ -1,3 +0,0 @@ -# owlapi_interface - -::: ontopy.factpluspluswrapper.owlapi_interface diff --git a/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md b/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md deleted file mode 100644 index 328310a79..000000000 --- a/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md +++ /dev/null @@ -1,3 +0,0 @@ -# sync_factpp - -::: ontopy.factpluspluswrapper.sync_factpp diff --git a/docs/api_reference/ontopy/graph.md b/docs/api_reference/ontopy/graph.md deleted file mode 100644 index c11ae62c6..000000000 --- a/docs/api_reference/ontopy/graph.md +++ /dev/null @@ -1,3 +0,0 @@ -# graph - -::: ontopy.graph diff --git a/docs/api_reference/ontopy/manchester.md b/docs/api_reference/ontopy/manchester.md deleted file mode 100644 index 4ed8fc363..000000000 --- a/docs/api_reference/ontopy/manchester.md +++ /dev/null @@ -1,3 +0,0 @@ -# manchester - -::: ontopy.manchester diff --git a/docs/api_reference/ontopy/nadict.md b/docs/api_reference/ontopy/nadict.md deleted file mode 100644 index 25160ea6a..000000000 --- a/docs/api_reference/ontopy/nadict.md +++ /dev/null @@ -1,3 +0,0 @@ -# nadict - -::: ontopy.nadict diff --git a/docs/api_reference/ontopy/ontodoc.md b/docs/api_reference/ontopy/ontodoc.md deleted file mode 100644 index 63461576e..000000000 --- a/docs/api_reference/ontopy/ontodoc.md +++ /dev/null @@ -1,3 +0,0 @@ -# ontodoc - -::: ontopy.ontodoc diff --git a/docs/api_reference/ontopy/ontograph.md b/docs/api_reference/ontopy/ontograph.md deleted file mode 100644 index de409c8c5..000000000 --- a/docs/api_reference/ontopy/ontograph.md +++ /dev/null @@ -1,3 +0,0 @@ -# ontograph - -::: ontopy.ontograph diff --git a/docs/api_reference/ontopy/ontology.md b/docs/api_reference/ontopy/ontology.md deleted file mode 100644 index 981ea539a..000000000 --- a/docs/api_reference/ontopy/ontology.md +++ /dev/null @@ -1,3 +0,0 @@ -# ontology - -::: ontopy.ontology diff --git a/docs/api_reference/ontopy/patch.md b/docs/api_reference/ontopy/patch.md deleted file mode 100644 index 8a8addf05..000000000 --- a/docs/api_reference/ontopy/patch.md +++ /dev/null @@ -1,3 +0,0 @@ -# patch - -::: ontopy.patch diff --git a/docs/api_reference/ontopy/utils.md b/docs/api_reference/ontopy/utils.md deleted file mode 100644 index 6d810e6a4..000000000 --- a/docs/api_reference/ontopy/utils.md +++ /dev/null @@ -1,3 +0,0 @@ -# utils - -::: ontopy.utils From 8d69516356dc3be3fe47346d2dde44835d39bd68 Mon Sep 17 00:00:00 2001 From: francescalb Date: Tue, 7 Dec 2021 09:51:19 +0100 Subject: [PATCH 09/29] Fixed documentation error --- docs/api_reference/emmopy/.pages | 2 ++ docs/api_reference/emmopy/emmocheck.md | 5 +++++ docs/api_reference/emmopy/emmopy.md | 3 +++ docs/api_reference/ontopy/.pages | 2 ++ docs/api_reference/ontopy/colortest.md | 3 +++ docs/api_reference/ontopy/excelparser.md | 3 +++ docs/api_reference/ontopy/factpluspluswrapper/.pages | 2 ++ docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md | 3 +++ .../ontopy/factpluspluswrapper/owlapi_interface.md | 3 +++ docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md | 3 +++ docs/api_reference/ontopy/graph.md | 3 +++ docs/api_reference/ontopy/manchester.md | 3 +++ docs/api_reference/ontopy/nadict.md | 3 +++ docs/api_reference/ontopy/ontodoc.md | 3 +++ docs/api_reference/ontopy/ontograph.md | 3 +++ docs/api_reference/ontopy/ontology.md | 3 +++ docs/api_reference/ontopy/patch.md | 3 +++ docs/api_reference/ontopy/utils.md | 3 +++ 18 files changed, 53 insertions(+) create mode 100644 docs/api_reference/emmopy/.pages create mode 100644 docs/api_reference/emmopy/emmocheck.md create mode 100644 docs/api_reference/emmopy/emmopy.md create mode 100644 docs/api_reference/ontopy/.pages create mode 100644 docs/api_reference/ontopy/colortest.md create mode 100644 docs/api_reference/ontopy/excelparser.md create mode 100644 docs/api_reference/ontopy/factpluspluswrapper/.pages create mode 100644 docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md create mode 100644 docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md create mode 100644 docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md create mode 100644 docs/api_reference/ontopy/graph.md create mode 100644 docs/api_reference/ontopy/manchester.md create mode 100644 docs/api_reference/ontopy/nadict.md create mode 100644 docs/api_reference/ontopy/ontodoc.md create mode 100644 docs/api_reference/ontopy/ontograph.md create mode 100644 docs/api_reference/ontopy/ontology.md create mode 100644 docs/api_reference/ontopy/patch.md create mode 100644 docs/api_reference/ontopy/utils.md diff --git a/docs/api_reference/emmopy/.pages b/docs/api_reference/emmopy/.pages new file mode 100644 index 000000000..1f6fed708 --- /dev/null +++ b/docs/api_reference/emmopy/.pages @@ -0,0 +1,2 @@ +title: "emmopy" +collapse_single_pages: false diff --git a/docs/api_reference/emmopy/emmocheck.md b/docs/api_reference/emmopy/emmocheck.md new file mode 100644 index 000000000..17c16dc05 --- /dev/null +++ b/docs/api_reference/emmopy/emmocheck.md @@ -0,0 +1,5 @@ +# emmocheck + +::: emmopy.emmocheck + rendering: + show_bases: false diff --git a/docs/api_reference/emmopy/emmopy.md b/docs/api_reference/emmopy/emmopy.md new file mode 100644 index 000000000..04fdb26a0 --- /dev/null +++ b/docs/api_reference/emmopy/emmopy.md @@ -0,0 +1,3 @@ +# emmopy + +::: emmopy.emmopy diff --git a/docs/api_reference/ontopy/.pages b/docs/api_reference/ontopy/.pages new file mode 100644 index 000000000..01e236003 --- /dev/null +++ b/docs/api_reference/ontopy/.pages @@ -0,0 +1,2 @@ +title: "ontopy" +collapse_single_pages: false diff --git a/docs/api_reference/ontopy/colortest.md b/docs/api_reference/ontopy/colortest.md new file mode 100644 index 000000000..74a6d3bd1 --- /dev/null +++ b/docs/api_reference/ontopy/colortest.md @@ -0,0 +1,3 @@ +# colortest + +::: ontopy.colortest diff --git a/docs/api_reference/ontopy/excelparser.md b/docs/api_reference/ontopy/excelparser.md new file mode 100644 index 000000000..9883971c0 --- /dev/null +++ b/docs/api_reference/ontopy/excelparser.md @@ -0,0 +1,3 @@ +# excelparser + +::: ontopy.excelparser diff --git a/docs/api_reference/ontopy/factpluspluswrapper/.pages b/docs/api_reference/ontopy/factpluspluswrapper/.pages new file mode 100644 index 000000000..a117fa2ee --- /dev/null +++ b/docs/api_reference/ontopy/factpluspluswrapper/.pages @@ -0,0 +1,2 @@ +title: "factpluspluswrapper" +collapse_single_pages: false diff --git a/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md b/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md new file mode 100644 index 000000000..bc85098da --- /dev/null +++ b/docs/api_reference/ontopy/factpluspluswrapper/factppgraph.md @@ -0,0 +1,3 @@ +# factppgraph + +::: ontopy.factpluspluswrapper.factppgraph diff --git a/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md b/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md new file mode 100644 index 000000000..f12d7b42a --- /dev/null +++ b/docs/api_reference/ontopy/factpluspluswrapper/owlapi_interface.md @@ -0,0 +1,3 @@ +# owlapi_interface + +::: ontopy.factpluspluswrapper.owlapi_interface diff --git a/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md b/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md new file mode 100644 index 000000000..328310a79 --- /dev/null +++ b/docs/api_reference/ontopy/factpluspluswrapper/sync_factpp.md @@ -0,0 +1,3 @@ +# sync_factpp + +::: ontopy.factpluspluswrapper.sync_factpp diff --git a/docs/api_reference/ontopy/graph.md b/docs/api_reference/ontopy/graph.md new file mode 100644 index 000000000..c11ae62c6 --- /dev/null +++ b/docs/api_reference/ontopy/graph.md @@ -0,0 +1,3 @@ +# graph + +::: ontopy.graph diff --git a/docs/api_reference/ontopy/manchester.md b/docs/api_reference/ontopy/manchester.md new file mode 100644 index 000000000..4ed8fc363 --- /dev/null +++ b/docs/api_reference/ontopy/manchester.md @@ -0,0 +1,3 @@ +# manchester + +::: ontopy.manchester diff --git a/docs/api_reference/ontopy/nadict.md b/docs/api_reference/ontopy/nadict.md new file mode 100644 index 000000000..25160ea6a --- /dev/null +++ b/docs/api_reference/ontopy/nadict.md @@ -0,0 +1,3 @@ +# nadict + +::: ontopy.nadict diff --git a/docs/api_reference/ontopy/ontodoc.md b/docs/api_reference/ontopy/ontodoc.md new file mode 100644 index 000000000..63461576e --- /dev/null +++ b/docs/api_reference/ontopy/ontodoc.md @@ -0,0 +1,3 @@ +# ontodoc + +::: ontopy.ontodoc diff --git a/docs/api_reference/ontopy/ontograph.md b/docs/api_reference/ontopy/ontograph.md new file mode 100644 index 000000000..de409c8c5 --- /dev/null +++ b/docs/api_reference/ontopy/ontograph.md @@ -0,0 +1,3 @@ +# ontograph + +::: ontopy.ontograph diff --git a/docs/api_reference/ontopy/ontology.md b/docs/api_reference/ontopy/ontology.md new file mode 100644 index 000000000..981ea539a --- /dev/null +++ b/docs/api_reference/ontopy/ontology.md @@ -0,0 +1,3 @@ +# ontology + +::: ontopy.ontology diff --git a/docs/api_reference/ontopy/patch.md b/docs/api_reference/ontopy/patch.md new file mode 100644 index 000000000..8a8addf05 --- /dev/null +++ b/docs/api_reference/ontopy/patch.md @@ -0,0 +1,3 @@ +# patch + +::: ontopy.patch diff --git a/docs/api_reference/ontopy/utils.md b/docs/api_reference/ontopy/utils.md new file mode 100644 index 000000000..6d810e6a4 --- /dev/null +++ b/docs/api_reference/ontopy/utils.md @@ -0,0 +1,3 @@ +# utils + +::: ontopy.utils From 912ad2bfd0b584fafe39cfc77ad63686c6dd9b8e Mon Sep 17 00:00:00 2001 From: francescalb Date: Tue, 7 Dec 2021 10:38:22 +0100 Subject: [PATCH 10/29] Added pandas to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 35acf5858..0d1356b5e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ defusedxml>=0.7.1,<1 graphviz>=0.16,<0.20 Owlready2>=0.28,<0.36,!=0.32,!=0.34 packaging>=21.0<22 +pandas>=1.2,<1.4 pydot>=1.4.1,<2 Pygments>=2.7.4,<3 pyparsing>=2.4.7 From ce0476ba015b86986b6b82d0cc3e468d7d05e148 Mon Sep 17 00:00:00 2001 From: francescalb Date: Tue, 7 Dec 2021 10:48:35 +0100 Subject: [PATCH 11/29] Corrected google docstring for returning Tuple with typing --- ontopy/excelparser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index e776451d4..ad2c1ad21 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -8,6 +8,7 @@ [ """ import warnings +from typing import Tuple import pyparsing import pandas as pd from ontopy import World @@ -50,7 +51,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra base_iri: str = "http://emmo.info/emmo/domain/onto#", base_iri_from_metadata: bool = True, catalog: dict = None, -) -> (owlready2.Ontology, dict): +) -> Tuple[owlready2.Ontology, dict]: """ Create an ontology from a pandas DataFrame """ @@ -171,4 +172,4 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra f"Property to be Evaluated: {prop}. " f"Error is {err}." ) - return onto, catalog + return Tuple[onto, catalog] From 9bd9e835846b6995d6e875d9cb55ac89f05c0524 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 06:59:52 +0100 Subject: [PATCH 12/29] Fixed typing error --- .../make_microstructure_onto.py | 2 +- examples/ontology-from-excel/onto.xlsx | Bin 23396 -> 0 bytes ontopy/excelparser.py | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) delete mode 100755 examples/ontology-from-excel/onto.xlsx diff --git a/examples/ontology-from-excel/make_microstructure_onto.py b/examples/ontology-from-excel/make_microstructure_onto.py index 87a1b799c..418d812b7 100755 --- a/examples/ontology-from-excel/make_microstructure_onto.py +++ b/examples/ontology-from-excel/make_microstructure_onto.py @@ -4,7 +4,7 @@ from ontopy.excelparser import create_ontology_from_excel from ontopy.utils import write_catalog -ontology, catalog = create_ontology_from_excel("onto.xlsx") +ontology, catalog = create_ontology_from_excel("tool/onto.xlsx") ontology.save("microstructure_ontology.ttl", format="turtle", overwrite=True) write_catalog(catalog) diff --git a/examples/ontology-from-excel/onto.xlsx b/examples/ontology-from-excel/onto.xlsx deleted file mode 100755 index 2cf918f1387714e4a04e829bad792a34b803d046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23396 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 (owlready2.Ontology, dict): +) -> Tuple[owlready2.Ontology, dict]: """ Creates an ontology from an excelfile. @@ -172,4 +172,4 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra f"Property to be Evaluated: {prop}. " f"Error is {err}." ) - return Tuple[onto, catalog] + return onto, catalog From d74681225eb7c8f783d0c8030bc76abb32983308 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 07:10:22 +0100 Subject: [PATCH 13/29] Added openpyxl to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 0d1356b5e..b7358e668 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ blessings>=1.7,<2 Cython>=0.29.21,<0.30 defusedxml>=0.7.1,<1 graphviz>=0.16,<0.20 +openpyxl>=3.0.9,<3.1 Owlready2>=0.28,<0.36,!=0.32,!=0.34 packaging>=21.0<22 pandas>=1.2,<1.4 From 83f48b859613ffb87fa622418fffcad46c122538 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 08:24:52 +0100 Subject: [PATCH 14/29] Added first test for adding metadata authors and contributors Metadata should be factored out later --- ontopy/excelparser.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 60454afcb..4e58be975 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -124,7 +124,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra parents = onto.EMMO warnings.warn( - "At least one of the defined parents do not exist. " + "Missing at least one of the defined parents. " f"Concept: {name}; Defined parents: {parent_names}" ) new_loop = False @@ -172,4 +172,35 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra f"Property to be Evaluated: {prop}. " f"Error is {err}." ) + + # Add metadata + try: + authors = ( + metadata.loc[metadata["Metadata name"] == "Author"]["Value"] + .item() + .split(";") + ) + for author in authors: + onto.metadata.creator.append(english(author)) + + except (TypeError, ValueError): + warnings.warn("No authors or creators added.") + + try: + contributors = ( + metadata.loc[metadata["Metadata name"] == "Contributor"]["Value"] + .item() + .split(";") + ) + for contributor in contributors: + onto.metadata.contributor.append(english(contributor)) + except (TypeError, ValueError, AttributeError): + warnings.warn("No contributors added.") + + # Synchronise Python attributes to ontology + onto.sync_attributes( + name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" + ) + onto.dir_label = False + return onto, catalog From b4f436c2c36afb7b12e25ba8a69866a4b11b02fe Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 12:33:58 +0100 Subject: [PATCH 15/29] Added own function for metadata --- ontopy/excelparser.py | 108 ++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 4e58be975..aa8652eee 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -11,7 +11,7 @@ from typing import Tuple import pyparsing import pandas as pd -from ontopy import World +from ontopy import World, get_ontology from ontopy.utils import NoSuchLabelError from ontopy.manchester import evaluate import owlready2 # pylint: disable=C0411 @@ -60,43 +60,19 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra data = data[data["prefLabel"].notna()] data = data.astype({"prefLabel": "str"}) - # base_iri from metadata if it exists and base_iri_from_metadata - if base_iri_from_metadata: - try: - base_iri = ( - metadata.loc[metadata["Metadata name"] == "Ontology IRI"][ - "Value" - ].item() - + "#" - ) - except (TypeError, ValueError): - pass - - # Make new ontology and import ontologies + # Make new ontology world = World() + onto = world.get_ontology(base_iri) + + onto, catalog = get_metadata_from_dataframe(metadata, onto) + + # base_iri from metadata if it exists and base_iri_from_metadata + if not base_iri_from_metadata: + onto.base_iri = base_iri # have to decide how to add metadata and imports etc. # base_iri to be added from excel (maybe also possibly argument?) - onto = world.get_ontology(base_iri) - onto.base_iri = base_iri - - # Get imported ontologies from metadata - try: - imported_ontology_paths = ( - metadata.loc[metadata["Metadata name"] == "Imported ontologies"][ - "Value" - ] - .item() - .split(";") - ) - except (TypeError, ValueError, AttributeError): - imported_ontology_paths = [] - # Add imported ontologies - catalog = {} if catalog is None else catalog - for path in imported_ontology_paths: - imported = world.get_ontology(path).load() - onto.imported_ontologies.append(imported) - catalog[imported.base_iri.rstrip("/")] = path + # onto = world.get_ontology(base_iri) onto.sync_python_names() with onto: @@ -173,7 +149,62 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra f"Error is {err}." ) - # Add metadata + onto, catalog = get_metadata_from_dataframe(metadata, onto) + # Synchronise Python attributes to ontology + onto.sync_attributes( + name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" + ) + onto.dir_label = False + + return onto, catalog + + +# To test: with and without ontology as input +def get_metadata_from_dataframe( + metadata: pd.DataFrame, + onto: owlready2.Ontology = None, + base_iri_from_metadata: bool = True, + catalog: dict = None, +) -> Tuple[owlready2.Ontology, dict]: + """ + Populate ontology with metada from pd.DataFrame + """ + + if onto is None: + onto = get_ontology() + + # base_iri from metadata if it exists and base_iri_from_metadata + if base_iri_from_metadata: + try: + base_iri = ( + metadata.loc[metadata["Metadata name"] == "Ontology IRI"][ + "Value" + ].item() + + "#" + ) + onto.base_iri = base_iri + except (TypeError, ValueError): + pass + + # Get imported ontologies from metadata + try: + imported_ontology_paths = ( + metadata.loc[metadata["Metadata name"] == "Imported ontologies"][ + "Value" + ] + .item() + .split(";") + ) + except (TypeError, ValueError, AttributeError): + imported_ontology_paths = [] + # Add imported ontologies + catalog = {} if catalog is None else catalog + for path in imported_ontology_paths: + imported = onto.world.get_ontology(path).load() + onto.imported_ontologies.append(imported) + catalog[imported.base_iri.rstrip("/")] = path + + # Add authors try: authors = ( metadata.loc[metadata["Metadata name"] == "Author"]["Value"] @@ -186,6 +217,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra except (TypeError, ValueError): warnings.warn("No authors or creators added.") + # Add contributors try: contributors = ( metadata.loc[metadata["Metadata name"] == "Contributor"]["Value"] @@ -197,10 +229,4 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra except (TypeError, ValueError, AttributeError): warnings.warn("No contributors added.") - # Synchronise Python attributes to ontology - onto.sync_attributes( - name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" - ) - onto.dir_label = False - return onto, catalog From 38199f10c8982fc0b5091e65c16560d05cd13542 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 21:23:21 +0100 Subject: [PATCH 16/29] Added more metadata and altLabels --- ontopy/excelparser.py | 85 +++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index aa8652eee..8826d83b5 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -125,6 +125,12 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra for comment in comment_list: concept.comment.append(english(comment)) + altlabels = row["altLabel"] + if isinstance(altlabels, str): + altlabel_list = altlabels.split(";") + for altlabel in altlabel_list: + concept.altlabel.append(english(altlabel)) + number_of_added_classes += 1 if number_of_added_classes == 0: @@ -160,7 +166,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra # To test: with and without ontology as input -def get_metadata_from_dataframe( +def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-branches,too-many-statements metadata: pd.DataFrame, onto: owlready2.Ontology = None, base_iri_from_metadata: bool = True, @@ -176,24 +182,20 @@ def get_metadata_from_dataframe( # base_iri from metadata if it exists and base_iri_from_metadata if base_iri_from_metadata: try: - base_iri = ( - metadata.loc[metadata["Metadata name"] == "Ontology IRI"][ - "Value" - ].item() - + "#" - ) + base_iris = _parse_metadata_string(metadata, "Ontology IRI") + if len(base_iris) > 1: + warnings.warn( + "More than one Ontology IRI given. " "The first was chosen." + ) + base_iri = base_iris[0] + "#" onto.base_iri = base_iri except (TypeError, ValueError): pass # Get imported ontologies from metadata try: - imported_ontology_paths = ( - metadata.loc[metadata["Metadata name"] == "Imported ontologies"][ - "Value" - ] - .item() - .split(";") + imported_ontology_paths = _parse_metadata_string( + metadata, "Imported ontologies" ) except (TypeError, ValueError, AttributeError): imported_ontology_paths = [] @@ -204,29 +206,64 @@ def get_metadata_from_dataframe( onto.imported_ontologies.append(imported) catalog[imported.base_iri.rstrip("/")] = path - # Add authors + # Add title try: - authors = ( - metadata.loc[metadata["Metadata name"] == "Author"]["Value"] - .item() - .split(";") + titles = _parse_metadata_string(metadata, "Title") + if len(titles) > 1: + warnings.warn( + "More than one title is given. " "The first was chosen." + ) + onto.metadata.title.append(english(titles[0])) + except (TypeError, ValueError): + pass + + # Add versionINFO + try: + version_infos = _parse_metadata_string( + metadata, "Ontology version Info" ) + if len(titles) > 1: + warnings.warn( + "More than one versionINFO is given. " "The first was chosen." + ) + onto.metadata.versionInfo.append(english(version_infos[0])) + except (TypeError, ValueError): + pass + + # Add versionINFO + try: + licenses = _parse_metadata_string(metadata, "License") + if len(licenses) > 1: + warnings.warn( + "More than one license is given. " "The first was chosen." + ) + onto.metadata.license.append(english(licenses[0])) + except (TypeError, ValueError): + pass + + # Add authors + try: + authors = _parse_metadata_string(metadata, "Author") for author in authors: onto.metadata.creator.append(english(author)) - except (TypeError, ValueError): warnings.warn("No authors or creators added.") # Add contributors try: - contributors = ( - metadata.loc[metadata["Metadata name"] == "Contributor"]["Value"] - .item() - .split(";") - ) + contributors = _parse_metadata_string(metadata, "Contributor") for contributor in contributors: onto.metadata.contributor.append(english(contributor)) except (TypeError, ValueError, AttributeError): warnings.warn("No contributors added.") return onto, catalog + + +def _parse_metadata_string(metadata: pd.DataFrame, name: str) -> list: + """Helper function to make list ouf strings from ';'-delimited + strings in one string. + """ + return str( + metadata.loc[metadata["Metadata name"] == name]["Value"].item() + ).split(";") From b81fd0aebb94c74606c1dd8aed370d3532f62888 Mon Sep 17 00:00:00 2001 From: francescalb Date: Wed, 8 Dec 2021 21:37:56 +0100 Subject: [PATCH 17/29] Added altLabel --- examples/ontology-from-excel/tool/onto.xlsx | Bin 23380 -> 23424 bytes ontopy/excelparser.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ontology-from-excel/tool/onto.xlsx b/examples/ontology-from-excel/tool/onto.xlsx index 9ffc4c43bc838de6517f7bdd4e014096fb8babc9..01ad4a91dd3c610583bc5d3c1b71fd16a3810116 100755 GIT binary patch delta 4889 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

P zsoH-{?J8h;^*Zp@f|mV1>VonAgNo?>f*65g3kk?9Gk|Ai1eDPzFdFbcbF=^FdQyWx z4F9eBH_G4xQuvsF4m1j~gajsq*#L;8G-O5iZzurRSfU_nDB!ClKTvHc0X_!^mgW!| z3E<{E73i@92%uA80G{2G0P6v5_wGP>RQ}Dd0*qEDumy0(>JAtKL|BRZ?_dJ;R*c}s zz>t+P*bKOWQG%ch08NYvB;E+%v}OWQj1WKx1_e$5@ECn?Cct5R<4V5yzn%UMN1!Tf delta 4882 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 X3q1l4L*UAS9 Date: Wed, 8 Dec 2021 21:45:53 +0100 Subject: [PATCH 18/29] Corrected so that empty fields are not included --- ontopy/excelparser.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 17972d9a5..1b1d2ab10 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -189,7 +189,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra ) base_iri = base_iris[0] + "#" onto.base_iri = base_iri - except (TypeError, ValueError): + except (TypeError, ValueError, AttributeError): pass # Get imported ontologies from metadata @@ -214,7 +214,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra "More than one title is given. " "The first was chosen." ) onto.metadata.title.append(english(titles[0])) - except (TypeError, ValueError): + except (TypeError, ValueError, AttributeError): pass # Add versionINFO @@ -227,7 +227,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra "More than one versionINFO is given. " "The first was chosen." ) onto.metadata.versionInfo.append(english(version_infos[0])) - except (TypeError, ValueError): + except (TypeError, ValueError, AttributeError): pass # Add versionINFO @@ -238,7 +238,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra "More than one license is given. " "The first was chosen." ) onto.metadata.license.append(english(licenses[0])) - except (TypeError, ValueError): + except (TypeError, ValueError, AttributeError): pass # Add authors @@ -246,7 +246,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra authors = _parse_metadata_string(metadata, "Author") for author in authors: onto.metadata.creator.append(english(author)) - except (TypeError, ValueError): + except (TypeError, ValueError, AttributeError): warnings.warn("No authors or creators added.") # Add contributors @@ -264,6 +264,4 @@ def _parse_metadata_string(metadata: pd.DataFrame, name: str) -> list: """Helper function to make list ouf strings from ';'-delimited strings in one string. """ - return str( - metadata.loc[metadata["Metadata name"] == name]["Value"].item() - ).split(";") + return metadata.loc[metadata["Metadata name"] == name]["Value"].item().split(";") From 9f89d10cc0068a2f0b0886672e5abf851e99d1f7 Mon Sep 17 00:00:00 2001 From: "Francesca L. Bleken" <48128015+francescalb@users.noreply.github.com> Date: Thu, 9 Dec 2021 09:49:53 +0100 Subject: [PATCH 19/29] owlready2.Ontology->ontopy.Ontology Co-authored-by: Jesper Friis --- ontopy/excelparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 1b1d2ab10..907af6679 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -29,7 +29,7 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments base_iri: str = "http://emmo.info/emmo/domain/onto#", base_iri_from_metadata: bool = True, catalog: dict = None, -) -> Tuple[owlready2.Ontology, dict]: +) -> Tuple[ontopy.Ontology, dict]: """ Creates an ontology from an excelfile. From 8dca4b207e9008fedc0b33c947d6713b47c0a029 Mon Sep 17 00:00:00 2001 From: "Francesca L. Bleken" <48128015+francescalb@users.noreply.github.com> Date: Thu, 9 Dec 2021 09:51:08 +0100 Subject: [PATCH 20/29] parent=owl:Thing if parents missing in parser Co-authored-by: Jesper Friis --- ontopy/excelparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 907af6679..739f56891 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -97,7 +97,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra parents = [onto.get_by_label(pn) for pn in parent_names] except NoSuchLabelError: if final_loop is True: - parents = onto.EMMO + parents = owlready2.ThingClass warnings.warn( "Missing at least one of the defined parents. " From a51dcb1a30de0f66c7f3b70db0b53311bab8a3ec Mon Sep 17 00:00:00 2001 From: "Francesca L. Bleken" <48128015+francescalb@users.noreply.github.com> Date: Thu, 9 Dec 2021 09:51:52 +0100 Subject: [PATCH 21/29] typo Co-authored-by: Jesper Friis --- ontopy/excelparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 739f56891..eadeedd87 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -222,7 +222,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra version_infos = _parse_metadata_string( metadata, "Ontology version Info" ) - if len(titles) > 1: + if len(version_infos) > 1: warnings.warn( "More than one versionINFO is given. " "The first was chosen." ) From 091d2cb622f10498c232bf4d917db14daa2053cf Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 9 Dec 2021 11:00:36 +0100 Subject: [PATCH 22/29] Changed owlready.Ontology to ontopy.ontology.Ontology --- ontopy/excelparser.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index eadeedd87..e6f6946f3 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -1,16 +1,19 @@ -#!/usr/bin/env python3 """ Module from parsing an excelfile and creating an ontology from it. The excelfile is read by pandas and the pandas dataframe should have column names: -[ +prefLabel, altLabel, Elucidation, Comments, Examples, +subClassOf, Relations. + +Note that correct case is mandatory. """ import warnings from typing import Tuple import pyparsing import pandas as pd +import ontopy from ontopy import World, get_ontology from ontopy.utils import NoSuchLabelError from ontopy.manchester import evaluate @@ -29,7 +32,7 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments base_iri: str = "http://emmo.info/emmo/domain/onto#", base_iri_from_metadata: bool = True, catalog: dict = None, -) -> Tuple[ontopy.Ontology, dict]: +) -> Tuple[ontopy.ontology.Ontology, dict]: """ Creates an ontology from an excelfile. @@ -51,7 +54,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra base_iri: str = "http://emmo.info/emmo/domain/onto#", base_iri_from_metadata: bool = True, catalog: dict = None, -) -> Tuple[owlready2.Ontology, dict]: +) -> Tuple[ontopy.ontology.Ontology, dict]: """ Create an ontology from a pandas DataFrame """ @@ -171,7 +174,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra onto: owlready2.Ontology = None, base_iri_from_metadata: bool = True, catalog: dict = None, -) -> Tuple[owlready2.Ontology, dict]: +) -> Tuple[ontopy.ontology.Ontology, dict]: """ Populate ontology with metada from pd.DataFrame """ @@ -233,11 +236,8 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra # Add versionINFO try: licenses = _parse_metadata_string(metadata, "License") - if len(licenses) > 1: - warnings.warn( - "More than one license is given. " "The first was chosen." - ) - onto.metadata.license.append(english(licenses[0])) + for lic in licenses: + onto.metadata.license.append(english(lic)) except (TypeError, ValueError, AttributeError): pass @@ -264,4 +264,8 @@ def _parse_metadata_string(metadata: pd.DataFrame, name: str) -> list: """Helper function to make list ouf strings from ';'-delimited strings in one string. """ - return metadata.loc[metadata["Metadata name"] == name]["Value"].item().split(";") + return ( + metadata.loc[metadata["Metadata name"] == name]["Value"] + .item() + .split(";") + ) From b3b7c2248022f0f71edad19a3c71073d1d0f64df Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 9 Dec 2021 22:44:09 +0100 Subject: [PATCH 23/29] Added helper function for adding metadata --- ontopy/excelparser.py | 115 ++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index e6f6946f3..1a3083bb4 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -100,7 +100,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra parents = [onto.get_by_label(pn) for pn in parent_names] except NoSuchLabelError: if final_loop is True: - parents = owlready2.ThingClass + parents = owlready2.Thing warnings.warn( "Missing at least one of the defined parents. " @@ -158,13 +158,11 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra f"Error is {err}." ) - onto, catalog = get_metadata_from_dataframe(metadata, onto) # Synchronise Python attributes to ontology onto.sync_attributes( name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" ) onto.dir_label = False - return onto, catalog @@ -185,10 +183,12 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra # base_iri from metadata if it exists and base_iri_from_metadata if base_iri_from_metadata: try: - base_iris = _parse_metadata_string(metadata, "Ontology IRI") + base_iris = _parse_data_string( + metadata, "Ontology IRI", metadata=True + ) if len(base_iris) > 1: warnings.warn( - "More than one Ontology IRI given. " "The first was chosen." + "More than one Ontology IRI given. The first was chosen." ) base_iri = base_iris[0] + "#" onto.base_iri = base_iri @@ -197,8 +197,10 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra # Get imported ontologies from metadata try: - imported_ontology_paths = _parse_metadata_string( - metadata, "Imported ontologies" + imported_ontology_paths = _parse_data_string( + metadata, + "Imported ontologies", + metadata=True, ) except (TypeError, ValueError, AttributeError): imported_ontology_paths = [] @@ -209,63 +211,64 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra onto.imported_ontologies.append(imported) catalog[imported.base_iri.rstrip("/")] = path - # Add title - try: - titles = _parse_metadata_string(metadata, "Title") - if len(titles) > 1: - warnings.warn( - "More than one title is given. " "The first was chosen." - ) - onto.metadata.title.append(english(titles[0])) - except (TypeError, ValueError, AttributeError): - pass - - # Add versionINFO - try: - version_infos = _parse_metadata_string( - metadata, "Ontology version Info" + with onto: + # Add title + _add_data( + metadata, onto.metadata.title, "Title", metadata=True, only_one=True ) - if len(version_infos) > 1: - warnings.warn( - "More than one versionINFO is given. " "The first was chosen." - ) - onto.metadata.versionInfo.append(english(version_infos[0])) - except (TypeError, ValueError, AttributeError): - pass - # Add versionINFO - try: - licenses = _parse_metadata_string(metadata, "License") - for lic in licenses: - onto.metadata.license.append(english(lic)) - except (TypeError, ValueError, AttributeError): - pass + # Add license + _add_data(metadata, onto.metadata.license, "License", metadata=True) - # Add authors - try: - authors = _parse_metadata_string(metadata, "Author") - for author in authors: - onto.metadata.creator.append(english(author)) - except (TypeError, ValueError, AttributeError): - warnings.warn("No authors or creators added.") + # Add authors onto.metadata.author does not work! + _add_data(metadata, onto.metadata.contributor, "Author", metadata=True) - # Add contributors - try: - contributors = _parse_metadata_string(metadata, "Contributor") - for contributor in contributors: - onto.metadata.contributor.append(english(contributor)) - except (TypeError, ValueError, AttributeError): - warnings.warn("No contributors added.") + # Add contributors + _add_data( + metadata, onto.metadata.contributor, "Contributor", metadata=True + ) + + # Add versionInfo + _add_data( + metadata, + onto.metadata.versionInfo, + "Ontology version Info", + metadata=True, + only_one=True, + ) return onto, catalog -def _parse_metadata_string(metadata: pd.DataFrame, name: str) -> list: +def _parse_data_string( + data: pd.DataFrame, name: str, metadata: bool = False +) -> list: """Helper function to make list ouf strings from ';'-delimited strings in one string. """ - return ( - metadata.loc[metadata["Metadata name"] == name]["Value"] - .item() - .split(";") - ) + + if metadata is True: + values = data.loc[data["Metadata name"] == name]["Value"].item() + if not pd.isna(values): + return str(values).split(";") + return values.split(";") + + +def _add_data( # onto: ontopy.ontology.Ontology, + data: pd.DataFrame, + destination: owlready2.prop.IndividualValueList, # Check this for metadata + name: str, + metadata: bool = False, + only_one: bool = False, +) -> None: + try: + name_list = _parse_data_string(data, name, metadata=metadata) + if only_one is True and len(name_list) > 1: + warnings.warn( + f"More than one {name} is given. The first was chosen." + ) + destination.append(english(name_list[0])) + else: + destination.extend([english(nm) for nm in name_list]) + except (TypeError, ValueError, AttributeError): + warnings.warn(f"No {name} added.") From 0e62f86eaa313f6ff4f5e139adab9ed48a4c4509 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 07:54:37 +0100 Subject: [PATCH 24/29] Use function for adding literals also on concepts --- ontopy/excelparser.py | 67 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 1a3083bb4..a1702bad9 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -111,28 +111,19 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra continue concept = onto.new_entity(name, parents) + # Add elucidation + _add_literal( + row, concept.elucidation, "Elucidation", only_one=True + ) - elucidation = row["Elucidation"] - if isinstance(elucidation, str): - concept.elucidation.append(english(elucidation)) - - examples = row["Examples"] - if isinstance(examples, str): - example_list = examples.split(";") - for example in example_list: - concept.example.append(english(example)) + # Add examples + _add_literal(row, concept.example, "Examples") - comments = row["Comments"] - if isinstance(comments, str): - comment_list = comments.split(";") - for comment in comment_list: - concept.comment.append(english(comment)) + # Add comments + _add_literal(row, concept.comment, "Comments") - altlabels = row["altLabel"] - if isinstance(altlabels, str): - altlabel_list = altlabels.split(";") - for altlabel in altlabel_list: - concept.altLabel.append(english(altlabel)) + # Add altLAbels + _add_literal(row, concept.altLabel, "altLabel") number_of_added_classes += 1 @@ -183,9 +174,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra # base_iri from metadata if it exists and base_iri_from_metadata if base_iri_from_metadata: try: - base_iris = _parse_data_string( - metadata, "Ontology IRI", metadata=True - ) + base_iris = _parse_literal(metadata, "Ontology IRI", metadata=True) if len(base_iris) > 1: warnings.warn( "More than one Ontology IRI given. The first was chosen." @@ -197,7 +186,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra # Get imported ontologies from metadata try: - imported_ontology_paths = _parse_data_string( + imported_ontology_paths = _parse_literal( metadata, "Imported ontologies", metadata=True, @@ -213,23 +202,25 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra with onto: # Add title - _add_data( + _add_literal( metadata, onto.metadata.title, "Title", metadata=True, only_one=True ) # Add license - _add_data(metadata, onto.metadata.license, "License", metadata=True) + _add_literal(metadata, onto.metadata.license, "License", metadata=True) # Add authors onto.metadata.author does not work! - _add_data(metadata, onto.metadata.contributor, "Author", metadata=True) + _add_literal( + metadata, onto.metadata.contributor, "Author", metadata=True + ) # Add contributors - _add_data( + _add_literal( metadata, onto.metadata.contributor, "Contributor", metadata=True ) # Add versionInfo - _add_data( + _add_literal( metadata, onto.metadata.versionInfo, "Ontology version Info", @@ -240,8 +231,11 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra return onto, catalog -def _parse_data_string( - data: pd.DataFrame, name: str, metadata: bool = False +def _parse_literal( + data: pd.DataFrame, + name: str, + metadata: bool = False, + sep: str = ";", ) -> list: """Helper function to make list ouf strings from ';'-delimited strings in one string. @@ -249,20 +243,23 @@ def _parse_data_string( if metadata is True: values = data.loc[data["Metadata name"] == name]["Value"].item() - if not pd.isna(values): - return str(values).split(";") - return values.split(";") + else: + values = data[name] + if not pd.isna(values): + return str(values).split(sep) + return values.split(sep) -def _add_data( # onto: ontopy.ontology.Ontology, +def _add_literal( # pylint: disable=too-many-arguments data: pd.DataFrame, destination: owlready2.prop.IndividualValueList, # Check this for metadata name: str, metadata: bool = False, only_one: bool = False, + sep: str = ";", ) -> None: try: - name_list = _parse_data_string(data, name, metadata=metadata) + name_list = _parse_literal(data, name, metadata=metadata, sep=sep) if only_one is True and len(name_list) > 1: warnings.warn( f"More than one {name} is given. The first was chosen." From b527856193bdaa1d417bbab2cee93e5e8e08d495 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 08:13:50 +0100 Subject: [PATCH 25/29] _add_literal/_parse_literal accespt pd.Series and pd.DataFrame for data data argument can either be metadata (pd.DataFrame) or a row for a concept (pd.Series) --- ontopy/excelparser.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index a1702bad9..3557ea11a 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -10,7 +10,7 @@ Note that correct case is mandatory. """ import warnings -from typing import Tuple +from typing import Tuple, Union import pyparsing import pandas as pd import ontopy @@ -36,7 +36,7 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments """ Creates an ontology from an excelfile. - catalog is dict of imported ontologies with key name and value path + Catalog is dict of imported ontologies with key name and value path. """ # Read datafile TODO: Some magic to identify the header row conceptdata = pd.read_excel( @@ -56,7 +56,7 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra catalog: dict = None, ) -> Tuple[ontopy.ontology.Ontology, dict]: """ - Create an ontology from a pandas DataFrame + Create an ontology from a pandas DataFrame. """ # Remove Concepts without prefLabel and make all to string @@ -73,10 +73,6 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra if not base_iri_from_metadata: onto.base_iri = base_iri - # have to decide how to add metadata and imports etc. - # base_iri to be added from excel (maybe also possibly argument?) - # onto = world.get_ontology(base_iri) - onto.sync_python_names() with onto: # loop through the rows until no more are added @@ -157,7 +153,6 @@ def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-bra return onto, catalog -# To test: with and without ontology as input def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-branches,too-many-statements metadata: pd.DataFrame, onto: owlready2.Ontology = None, @@ -232,7 +227,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra def _parse_literal( - data: pd.DataFrame, + data: Union[pd.DataFrame, pd.Series], name: str, metadata: bool = False, sep: str = ";", @@ -251,8 +246,8 @@ def _parse_literal( def _add_literal( # pylint: disable=too-many-arguments - data: pd.DataFrame, - destination: owlready2.prop.IndividualValueList, # Check this for metadata + data: Union[pd.DataFrame, pd.Series], + destination: owlready2.prop.IndividualValueList, # name: str, metadata: bool = False, only_one: bool = False, From 8a59622bb796983af5dd292bdbaa53816c3ae0ee Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 08:39:35 +0100 Subject: [PATCH 26/29] Added a test for the excel_parser --- tests/test_excelparser.py | 16 +++ tests/testonto/excelparser/catalog-v001.xml | 6 + tests/testonto/excelparser/fromexcelonto.ttl | 116 +++++++++++++++++++ tests/testonto/excelparser/onto.xlsx | Bin 0 -> 23424 bytes 4 files changed, 138 insertions(+) create mode 100644 tests/test_excelparser.py create mode 100644 tests/testonto/excelparser/catalog-v001.xml create mode 100644 tests/testonto/excelparser/fromexcelonto.ttl create mode 100755 tests/testonto/excelparser/onto.xlsx diff --git a/tests/test_excelparser.py b/tests/test_excelparser.py new file mode 100644 index 000000000..d4182f3aa --- /dev/null +++ b/tests/test_excelparser.py @@ -0,0 +1,16 @@ +from ontopy import get_ontology +from ontopy.excelparser import create_ontology_from_excel +from ontopy.utils import write_catalog + +onto = get_ontology("testonto/excelparser/fromexcelonto.ttl").load() + + +def test_excelparser(): + ontology, catalog = create_ontology_from_excel( + "testonto/excelparser/onto.xlsx" + ) + assert onto == ontology + + +if __name__ == "__main__": + test_excelparser() diff --git a/tests/testonto/excelparser/catalog-v001.xml b/tests/testonto/excelparser/catalog-v001.xml new file mode 100644 index 000000000..597de9fa0 --- /dev/null +++ b/tests/testonto/excelparser/catalog-v001.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/testonto/excelparser/fromexcelonto.ttl b/tests/testonto/excelparser/fromexcelonto.ttl new file mode 100644 index 000000000..87408df9c --- /dev/null +++ b/tests/testonto/excelparser/fromexcelonto.ttl @@ -0,0 +1,116 @@ +@prefix : . +@prefix core: . +@prefix emmo: . +@prefix owl: . +@prefix rdfs: . +@prefix term: . + + a owl:Ontology ; + term:contributor "Astrid Marthinsen"@en, + "Georg Schmidt"@en, + "Jesper Friis"@en, + "Sylvain Gouttebroze"@en, + "Tomas Manik"@en, + "Ulrike Cihak-Bayr"@en ; + term:title "Microstructure ontology based on EMMO - Top concepts"@en ; + owl:imports ; + owl:versionInfo "0.01"@en . + +:EMMO_0264be35-e8ad-5b35-a1a3-84b37bde22d1 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Temporal pattern occurring in a time interval"@en ; + emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Light house during one night"@en ; + rdfs:subClassOf [ a owl:Restriction ; + owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ; + owl:someValuesFrom emmo:EMMO_d4f7d378_5e3b_468a_baa1_a7e98358cda7 ], + [ a owl:Restriction ; + owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; + owl:someValuesFrom :EMMO_b41c9cb3-3b2d-509f-9c93-aa04da134307 ], + :EMMO_138590b8-3333-515d-87ab-717aac8434e6, + :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8 ; + core:prefLabel "FiniteTemporalPattern"@en . + +:EMMO_70269d17-fbaa-54a6-8905-ce4dee45e0dd a owl:Class ; + rdfs:subClassOf owl:Thing ; + core:prefLabel "Particle"@en . + +:EMMO_76b2eb15-3ab7-52b3-ade2-755aa390d63e a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Spatial pattern localized in a volume of space"@en ; + emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Textured surface after etching"@en ; + rdfs:subClassOf [ a owl:Restriction ; + owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; + owl:someValuesFrom :EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 ], + [ a owl:Restriction ; + owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ; + owl:someValuesFrom emmo:EMMO_f1a51559_aa3d_43a0_9327_918039f0dfed ], + :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8, + :EMMO_5f50f77e-f321-53e3-af76-fe5b0a347479 ; + core:prefLabel "FiniteSpatialPattern"@en . + +:EMMO_903bf818-c0b4-56ef-9673-799ba204795d a owl:Class ; + rdfs:subClassOf owl:Thing ; + core:prefLabel "Precipitate"@en . + +:EMMO_b0f0e57e-464d-562f-80ec-b216c92d5e88 a owl:Class ; + rdfs:subClassOf owl:Thing ; + core:prefLabel "Grain"@en . + +:EMMO_d35b8f2a-64c0-5f57-a569-308bc8f8a1c5 a owl:Class ; + rdfs:subClassOf owl:Thing ; + core:prefLabel "Phase"@en . + +:EMMO_e0b20a22-7e6f-5c81-beca-35bc5358e11b a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ; + rdfs:subClassOf :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8, + :EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ; + core:prefLabel "FiniteSpatioTemporalPattern"@en . + +:EMMO_138590b8-3333-515d-87ab-717aac8434e6 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Pattern with only temporal aspect"@en ; + emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Voltage in AC plug"@en ; + rdfs:subClassOf :EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ; + core:prefLabel "TemporalPattern"@en . + +:EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ; + rdfs:subClassOf :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ; + core:prefLabel "SpatialBoundary"@en . + +:EMMO_5f50f77e-f321-53e3-af76-fe5b0a347479 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Spatial pattern without regular temporal variations"@en ; + emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Infinite grid"@en ; + rdfs:subClassOf :EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ; + core:prefLabel "SpatialPattern"@en . + +:EMMO_b41c9cb3-3b2d-509f-9c93-aa04da134307 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ; + rdfs:subClassOf :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ; + core:prefLabel "TemporalBoundary"@en . + +:EMMO_cd254842-c697-55f6-917d-9805c77b9187 a owl:Class ; + emmo:EMMO_21ae69b4_235e_479d_8dd8_4f756f694c1b "A"@en, + "Just"@en, + "Test"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "everything that can be perceived or measured"@en ; + rdfs:comment " this definition is much broader than definition of pattern such as \"the regular and repeated way in which something happens or is\""@en, + "a pattern is defined from a contrast"@en ; + rdfs:subClassOf emmo:EMMO_649bf97b_4397_4005_90d9_219755d92e34 ; + core:prefLabel "Pattern"@en . + +:EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ; + rdfs:subClassOf emmo:EMMO_649bf97b_4397_4005_90d9_219755d92e34 ; + core:prefLabel "Boundary"@en . + +:EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Pattern occuring within a boundary in the 4D space"@en ; + rdfs:comment "Every physical patterns are FinitePattern"@en ; + rdfs:subClassOf [ a owl:Restriction ; + owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; + owl:someValuesFrom :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ], + :EMMO_cd254842-c697-55f6-917d-9805c77b9187 ; + core:prefLabel "FinitePattern"@en . + +:EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 a owl:Class ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ; + rdfs:subClassOf :EMMO_cd254842-c697-55f6-917d-9805c77b9187 ; + core:prefLabel "SpatioTemporalPattern"@en . diff --git a/tests/testonto/excelparser/onto.xlsx b/tests/testonto/excelparser/onto.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..01ad4a91dd3c610583bc5d3c1b71fd16a3810116 GIT binary patch literal 23424 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 MglB-Pc_APk0FJNekN^Mx literal 0 HcmV?d00001 From c44a63b602112550f80f0ed737c3eb27558821a8 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 10:28:03 +0100 Subject: [PATCH 27/29] Corrected path in test --- tests/test_excelparser.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_excelparser.py b/tests/test_excelparser.py index d4182f3aa..22d871e9a 100644 --- a/tests/test_excelparser.py +++ b/tests/test_excelparser.py @@ -2,13 +2,14 @@ from ontopy.excelparser import create_ontology_from_excel from ontopy.utils import write_catalog -onto = get_ontology("testonto/excelparser/fromexcelonto.ttl").load() - -def test_excelparser(): - ontology, catalog = create_ontology_from_excel( - "testonto/excelparser/onto.xlsx" +def test_excelparser(repo_dir: "Path") -> None: + ontopath = ( + repo_dir / "tests" / "testonto" / "excelparser" / "fromexcelonto.ttl" ) + onto = get_ontology(str(ontopath)).load() + xlspath = repo_dir / "tests" / "testonto" / "excelparser" / "onto.xlsx" + ontology, catalog = create_ontology_from_excel(xlspath) assert onto == ontology From 862eabe5aa8485cf0af5386f6cb7f0f149196251 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 13:45:58 +0100 Subject: [PATCH 28/29] Added creator instead of author and changed excel2onto arg to --output --- ontopy/excelparser.py | 4 +--- tools/excel2onto | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 3557ea11a..db09a790e 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -205,9 +205,7 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra _add_literal(metadata, onto.metadata.license, "License", metadata=True) # Add authors onto.metadata.author does not work! - _add_literal( - metadata, onto.metadata.contributor, "Author", metadata=True - ) + _add_literal(metadata, onto.metadata.creator, "Author", metadata=True) # Add contributors _add_literal( diff --git a/tools/excel2onto b/tools/excel2onto index 47b8d51bd..6aee6a601 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -25,10 +25,10 @@ def main(): help="path to excel book", ) parser.add_argument( - "--name", - "-n", + "--output", + "-o", default="ontology.ttl", - help="Name of ontology, ´ontology.ttl´ is default", + help="Name of output ontology, ´ontology.ttl´ is default", ) try: args = parser.parse_args() @@ -38,7 +38,7 @@ def main(): ontology, catalog = create_ontology_from_excel(args.excelpath) # Save new ontology as turtle - ontology.save(os.path.join(args.name), format="turtle", overwrite=True) + ontology.save(os.path.join(args.output), format="turtle", overwrite=True) write_catalog(catalog) From ee6621e92207e9134fdf8e95a5a0391da15bad54 Mon Sep 17 00:00:00 2001 From: francescalb Date: Fri, 10 Dec 2021 14:10:58 +0100 Subject: [PATCH 29/29] Updated excelparser ontology for comparison --- tests/testonto/excelparser/fromexcelonto.ttl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/testonto/excelparser/fromexcelonto.ttl b/tests/testonto/excelparser/fromexcelonto.ttl index 87408df9c..f3434c173 100644 --- a/tests/testonto/excelparser/fromexcelonto.ttl +++ b/tests/testonto/excelparser/fromexcelonto.ttl @@ -6,7 +6,7 @@ @prefix term: . a owl:Ontology ; - term:contributor "Astrid Marthinsen"@en, + term:creator "Astrid Marthinsen"@en, "Georg Schmidt"@en, "Jesper Friis"@en, "Sylvain Gouttebroze"@en, @@ -20,11 +20,11 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Temporal pattern occurring in a time interval"@en ; emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Light house during one night"@en ; rdfs:subClassOf [ a owl:Restriction ; - owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ; - owl:someValuesFrom emmo:EMMO_d4f7d378_5e3b_468a_baa1_a7e98358cda7 ], - [ a owl:Restriction ; owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; owl:someValuesFrom :EMMO_b41c9cb3-3b2d-509f-9c93-aa04da134307 ], + [ a owl:Restriction ; + owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ; + owl:someValuesFrom emmo:EMMO_d4f7d378_5e3b_468a_baa1_a7e98358cda7 ], :EMMO_138590b8-3333-515d-87ab-717aac8434e6, :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8 ; core:prefLabel "FiniteTemporalPattern"@en . @@ -37,11 +37,11 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Spatial pattern localized in a volume of space"@en ; emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Textured surface after etching"@en ; rdfs:subClassOf [ a owl:Restriction ; - owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; - owl:someValuesFrom :EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 ], - [ a owl:Restriction ; owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ; owl:someValuesFrom emmo:EMMO_f1a51559_aa3d_43a0_9327_918039f0dfed ], + [ a owl:Restriction ; + owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ; + owl:someValuesFrom :EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 ], :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8, :EMMO_5f50f77e-f321-53e3-af76-fe5b0a347479 ; core:prefLabel "FiniteSpatialPattern"@en .