├── README.md ├── object_onto.owl └── owlready2_crash.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # onto_python 2 | An Introductory Jupyter Notebook to Manipulate Ontologies with Owlready2 3 | 4 | ## Requirements 5 | - owlready2 6 | - graphviz 7 | 8 | ## Additional Note 9 | Nothing for now. 10 | -------------------------------------------------------------------------------- /object_onto.owl: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | -------------------------------------------------------------------------------- /owlready2_crash.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Owlready2 Crash Notebook\n", 8 | "Owlready2 is a Python package to construct and manipulate ontology under Python syntax, while Protege is a Java software to construct and manipulate ontologies with various plugins.\n", 9 | "\n", 10 | "This is a notebook to manipulate owl files pre-constructed in Protege, and to utilize some APIs from Owlready2 for information retrieval." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "# All necessary imports\n", 20 | "import os\n", 21 | "import difflib\n", 22 | "import graphviz\n", 23 | "import owlready2 as owl" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "## Part 1: Load a local *.owl file\n", 31 | "Owlready2 natively supports RDF/XML format ontology file. \n", 32 | "\n", 33 | "Refer to \"https://pythonhosted.org/Owlready2/onto.html\" for more details in ontology manipulation with Owlready2." 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 2, 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "name": "stdout", 43 | "output_type": "stream", 44 | "text": [ 45 | "Loaded owl file at: file:///mnt/c/Users/Zone/Desktop/Workspace/onto_python/object_onto.owl\n" 46 | ] 47 | } 48 | ], 49 | "source": [ 50 | "# Here, we load a local ontology file, created earlier in Protege.\n", 51 | "# A prefix of \"file://\" is needed.\n", 52 | "onto_path = 'file://' + os.path.abspath('object_onto.owl')\n", 53 | "onto = owl.get_ontology(onto_path).load()\n", 54 | "print('Loaded owl file at:', onto_path)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "## Part 2: Invoke a reasoner\n", 62 | "Reasoners are useful when checking the consistency of an ontology or deducing logical facts. Owlready2 includes a modified version of the HermiT reasoner.\n", 63 | "\n", 64 | "Refer to \"https://pythonhosted.org/Owlready2/reasoning.html\" for more details in reasoning." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 3, 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "name": "stderr", 74 | "output_type": "stream", 75 | "text": [ 76 | "* Owlready2 * Running HermiT...\n", 77 | " java -Xmx2000M -cp /usr/local/lib/python3.6/dist-packages/owlready2/hermit:/usr/local/lib/python3.6/dist-packages/owlready2/hermit/HermiT.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -I file:////tmp/tmp8udl3gcv\n", 78 | "* Owlready2 * HermiT took 0.6661009788513184 seconds\n", 79 | "* Owlready * Reparenting object_onto.hasMaterial: {object_onto.topClassProperty, owl.FunctionalProperty, owl.ObjectProperty} => {object_onto.topClassProperty, owl.FunctionalProperty}\n", 80 | "* Owlready * Reparenting object_onto.canWithstandTemperature: {object_onto.topClassProperty, owl.ObjectProperty} => {object_onto.topClassProperty}\n", 81 | "* Owlready * Reparenting object_onto.canGrasp: {object_onto.topActionRelation, owl.ObjectProperty} => {object_onto.topActionRelation}\n", 82 | "* Owlready * (NB: only changes on entities loaded in Python are shown, other changes are done but not listed)\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "# Invoke reasoner\n", 88 | "# NOTE: New facts will be appended into the current onto\n", 89 | "owl.sync_reasoner()" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "## Part 3: Some basic APIs exploration\n", 97 | "Some APIs that are useful to retrieve information in classes, object properties, etc." 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "Reference: https://pythonhosted.org/Owlready/class.html" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 4, 110 | "metadata": { 111 | "scrolled": false 112 | }, 113 | "outputs": [ 114 | { 115 | "name": "stdout", 116 | "output_type": "stream", 117 | "text": [ 118 | "All classes\n", 119 | "--------------------\n", 120 | "object_onto.Operator\n", 121 | "object_onto.Container\n", 122 | "object_onto.MaterialPartition\n", 123 | "object_onto.TemperatureValuePartition\n", 124 | "object_onto.Bottle\n", 125 | "object_onto.Cold\n", 126 | "object_onto.DomainThing\n", 127 | "object_onto.Partition\n", 128 | "object_onto.Glass\n", 129 | "object_onto.Hot\n", 130 | "object_onto.Mild\n", 131 | "object_onto.Plastic\n", 132 | "object_onto.GlassBottle\n", 133 | "object_onto.Human\n", 134 | "object_onto.PlasticBottle\n", 135 | "\n", 136 | "object_onto.PlasticBottle\n", 137 | "{'namespace': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': 324, '_name': 'PlasticBottle', 'is_a': [object_onto.Bottle, object_onto.isGraspableBy.some(object_onto.Human)], '_equivalent_to': None, '__module__': 'owlready2.entity', '__doc__': None}\n", 138 | "\n", 139 | "name(string): PlasticBottle\n", 140 | "module_type: owlready2.entity\n", 141 | "equivalent_to: [object_onto.Bottle & object_onto.hasMaterial.some(object_onto.Plastic)]\n", 142 | "is_a: [object_onto.Bottle, object_onto.isGraspableBy.some(object_onto.Human)]\n" 143 | ] 144 | } 145 | ], 146 | "source": [ 147 | "# Manipulation over Classes\n", 148 | "# --------------------\n", 149 | "# Retrieve all classes inside onto\n", 150 | "classes = list(onto.classes())\n", 151 | "print('All classes\\n'+'-'*20)\n", 152 | "for x in classes: \n", 153 | " print(x)\n", 154 | "print()\n", 155 | " \n", 156 | "# Get a random class in collection\n", 157 | "# Access dict to retrieve more info\n", 158 | "cls = classes[-1]\n", 159 | "print(cls)\n", 160 | "print(cls.__dict__)\n", 161 | "print()\n", 162 | "\n", 163 | "# Some useful APIs here\n", 164 | "print('name(string):', cls.name)\n", 165 | "print('module_type:', cls.__module__)\n", 166 | "print('equivalent_to:', cls.equivalent_to)\n", 167 | "print('is_a:', cls.is_a)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 5, 173 | "metadata": {}, 174 | "outputs": [ 175 | { 176 | "name": "stdout", 177 | "output_type": "stream", 178 | "text": [ 179 | "\n", 180 | "All object properties\n", 181 | "--------------------\n", 182 | "object_onto.canGrasp\n", 183 | "object_onto.topActionRelation\n", 184 | "object_onto.isGraspableBy\n", 185 | "object_onto.canWithstandTemperature\n", 186 | "object_onto.topClassProperty\n", 187 | "object_onto.hasMaterial\n", 188 | "\n", 189 | "object_onto.hasMaterial\n", 190 | "{'namespace': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'is_a': [owl.FunctionalProperty, object_onto.topClassProperty], 'storid': 312, '_name': 'hasMaterial', '_equivalent_to': [], '__module__': 'owlready2.entity', '__doc__': None, '_domain': None, '_range': None, '_property_chain': None, '_inverse_property': None, '_python_name': 'hasMaterial', '_class_property_type': [], '_class_property_some': True, '_class_property_only': False, '_class_property_relation': False, '_inverse_storid': 0}\n", 191 | "\n", 192 | "name(string): hasMaterial\n", 193 | "module_type: owlready2.entity\n", 194 | "is_a: [owl.FunctionalProperty, object_onto.topClassProperty]\n", 195 | "\n", 196 | "class_property_some: True\n", 197 | "class_property_only: False\n", 198 | "class_property_relation: False\n" 199 | ] 200 | } 201 | ], 202 | "source": [ 203 | "# Retrieve all object properties\n", 204 | "properties = list(onto.object_properties())\n", 205 | "print('\\nAll object properties\\n'+'-'*20)\n", 206 | "for x in properties: \n", 207 | " print(x)\n", 208 | "print()\n", 209 | " \n", 210 | "rel = properties[-1]\n", 211 | "print(rel)\n", 212 | "print(rel.__dict__)\n", 213 | "print()\n", 214 | "\n", 215 | "# Some useful APIs here\n", 216 | "print('name(string):', rel.name)\n", 217 | "print('module_type:', rel.__module__)\n", 218 | "print('is_a:', rel.is_a)\n", 219 | "print()\n", 220 | "\n", 221 | "\"\"\"\n", 222 | "The .class_property_type attribute of Properties allows to indicate how to handle class properties:\n", 223 | " “some”: handle class properties as existential restrictions (i.e. SOME restrictions and VALUES restrictions).\n", 224 | " “only”: handle class properties as universal restrictions (i.e. ONLY restrictions).\n", 225 | " “relation”: handle class properties as relations (i.e. simple RDF triple, as in Linked Data).\n", 226 | "\"\"\"\n", 227 | "print('class_property_some:', rel._class_property_some)\n", 228 | "print('class_property_only:', rel._class_property_only)\n", 229 | "print('class_property_relation:', rel._class_property_relation)" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 6, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "\n", 242 | "All disjoints\n", 243 | "--------------------\n", 244 | "AllDisjoint([object_onto.Cold, object_onto.Hot, object_onto.Mild])\n", 245 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': -26, '_list_bnode': -27, 'entities': [object_onto.Cold, object_onto.Hot, object_onto.Mild]}\n", 246 | "\n", 247 | "AllDisjoint([object_onto.Container, object_onto.Operator])\n", 248 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': (307, 88, 306), 'entities': [object_onto.Container, object_onto.Operator]}\n", 249 | "\n", 250 | "AllDisjoint([object_onto.DomainThing, object_onto.Partition])\n", 251 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': (316, 88, 317), 'entities': [object_onto.DomainThing, object_onto.Partition]}\n", 252 | "\n", 253 | "AllDisjoint([object_onto.Glass, object_onto.Plastic])\n", 254 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': (318, 88, 321), 'entities': [object_onto.Glass, object_onto.Plastic]}\n", 255 | "\n", 256 | "AllDisjoint([object_onto.GlassBottle, object_onto.PlasticBottle])\n", 257 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': (322, 88, 324), 'entities': [object_onto.GlassBottle, object_onto.PlasticBottle]}\n", 258 | "\n", 259 | "AllDisjoint([object_onto.MaterialPartition, object_onto.TemperatureValuePartition])\n", 260 | "{'ontology': get_ontology(\"http://www.semanticweb.org/zone/ontologies/2019/11/object_onto#\"), 'storid': (310, 88, 311), 'entities': [object_onto.MaterialPartition, object_onto.TemperatureValuePartition]}\n", 261 | "\n" 262 | ] 263 | } 264 | ], 265 | "source": [ 266 | "# Retrieve all disjoint sets\n", 267 | "disjoints = list(onto.disjoints())\n", 268 | "print('\\nAll disjoints\\n'+'-'*20)\n", 269 | "for x in disjoints: \n", 270 | " # NOTE: Retreive all disjoint individual entity objects, stored in the dict\n", 271 | " print(x)\n", 272 | " print(x.__dict__)\n", 273 | " print()" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "## Part 4: Higher-level API exploration\n", 281 | "Some helper functions to retrieve useful info given an entity to search for. This is a mimic of ontograf plugin feature from Protege." 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 7, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [ 290 | "# Default type2str from owlready2\n", 291 | "type2str_restriction = owl.class_construct._restriction_type_2_label\n", 292 | "\n", 293 | "def _process_entity(entity, job_name, orig_entity, graph):\n", 294 | " \"\"\"Helper: Append entity for the specified job.\n", 295 | " \"\"\"\n", 296 | " edge = (orig_entity, job_name, entity)\n", 297 | " if edge not in graph:\n", 298 | " graph.append(edge)\n", 299 | " return graph\n", 300 | "\n", 301 | "def _process_restriction(restriction, entity, graph):\n", 302 | " \"\"\"Helper: Append restriction.\n", 303 | " \"\"\"\n", 304 | " assert restriction.__module__ == 'owlready2.class_construct'\n", 305 | " \n", 306 | " # Grab object_property --type--> value\n", 307 | " object_property, value = restriction.property, restriction.value\n", 308 | " restriction_type = type2str_restriction[restriction.type]\n", 309 | " \n", 310 | " # Separate logical or for 'only'\n", 311 | " if restriction_type == 'only':\n", 312 | " for or_value in value.Classes:\n", 313 | " edge = (entity, '{},{}'.format(object_property.name, restriction_type), or_value)\n", 314 | " if edge not in graph:\n", 315 | " graph.append(edge)\n", 316 | " \n", 317 | " # No more processing for 'some'\n", 318 | " else:\n", 319 | " edge = (entity, '{},{}'.format(object_property.name, restriction_type), value)\n", 320 | " if edge not in graph:\n", 321 | " graph.append(edge)\n", 322 | " \n", 323 | " return graph\n", 324 | "\n", 325 | "def _process_subclasses(entity, graph):\n", 326 | " \"\"\"Helper: Append subclasses.\n", 327 | " \"\"\"\n", 328 | " # Safely grab all subclasses\n", 329 | " try:\n", 330 | " subclses = list(entity.subclasses())\n", 331 | " except:\n", 332 | " subclses = []\n", 333 | "\n", 334 | " for subcls in subclses:\n", 335 | " if (entity, 'has_subclass', subcls) not in graph:\n", 336 | " graph.append((entity, 'has_subclass', subcls))\n", 337 | " if (subcls, 'subclass_of', entity) not in graph:\n", 338 | " graph.append((subcls, 'subclass_of', entity))\n", 339 | "\n", 340 | " return graph\n", 341 | "\n", 342 | "def _populate_subclass_rel(graph):\n", 343 | " \"\"\"Helper: Ensure 'subclass_of' and 'has_subclass' always appear in pairs.\n", 344 | " \"\"\"\n", 345 | " for edge in graph:\n", 346 | " if edge[1] == 'subclass_of' and (edge[2], 'has_subclass', edge[0]) not in graph:\n", 347 | " graph.append((edge[2], 'has_subclass', edge[0]))\n", 348 | " elif edge[1] == 'has_subclass' and (edge[2], 'subclass_of', edge[0]) not in graph:\n", 349 | " graph.append((edge[2], 'subclass_of', edge[0]))\n", 350 | " return graph\n", 351 | "\n", 352 | "def _process_instances(entity, graph):\n", 353 | " \"\"\"Helper: Append individuals.\n", 354 | " \"\"\"\n", 355 | " # Safely grab all individuals\n", 356 | " try:\n", 357 | " instances = entity.instances()\n", 358 | " except:\n", 359 | " instances = []\n", 360 | "\n", 361 | " for instance in instances:\n", 362 | " if instance.is_a[0] == entity:\n", 363 | " if (entity, 'has_individual', instance) not in graph:\n", 364 | " graph.append((entity, 'has_individual', instance))\n", 365 | "\n", 366 | " return graph\n", 367 | "\n", 368 | "def generate_knowledge_graph(entity):\n", 369 | " \"\"\"Helper function to grab entity-relation from onto and \n", 370 | " return as knowledge graph.\n", 371 | " \"\"\"\n", 372 | " graph = []\n", 373 | "\n", 374 | " # Part 1: Append subclasses\n", 375 | " graph = _process_subclasses(entity, graph)\n", 376 | "\n", 377 | " # Part 2: Collect equivalent_to\n", 378 | " try:\n", 379 | " equivalent_to_list = entity.INDIRECT_equivalent_to # NOTE: Weird bug here, have to use INDIRECT\n", 380 | " except:\n", 381 | " equivalent_to_list = []\n", 382 | " for et in equivalent_to_list:\n", 383 | " # equivalent_to AND objects:\n", 384 | " if et.__module__ == 'owlready2.class_construct':\n", 385 | " for x in et.Classes:\n", 386 | " # For class restriction, retrieve relevant infos inside\n", 387 | " if x.__module__ == 'owlready2.class_construct':\n", 388 | " graph = _process_restriction(x, entity, graph)\n", 389 | " \n", 390 | " # Part 3: Look into is_a\n", 391 | " is_a_list = entity.is_a\n", 392 | " for x in is_a_list:\n", 393 | " # Entity: is_a indicates subclasses\n", 394 | " if x.__module__ == 'owlready2.entity':\n", 395 | " graph = _process_entity(x, 'subclass_of', entity, graph)\n", 396 | " \n", 397 | " # Restriction\n", 398 | " elif x.__module__ == 'owlready2.class_construct':\n", 399 | " graph = _process_restriction(x, entity, graph)\n", 400 | " \n", 401 | " # Part 4: Look into instances\n", 402 | " graph = _process_instances(entity, graph)\n", 403 | " \n", 404 | " # Part 5: Some additional filters\n", 405 | " graph = _populate_subclass_rel(graph)\n", 406 | " \n", 407 | " return graph\n", 408 | "\n", 409 | "def _filter_graph(graph, onto):\n", 410 | " \"\"\"Helper: filter graph from some ill-logical entries.\n", 411 | " \"\"\"\n", 412 | " filtered_graph = []\n", 413 | " # Grab all individuals\n", 414 | " individuals = list(onto.individuals())\n", 415 | "\n", 416 | " for edge in graph:\n", 417 | " passed = True\n", 418 | " # Ill-logical individuals\n", 419 | " if edge[0] in individuals:\n", 420 | " passed = False\n", 421 | " if passed:\n", 422 | " filtered_graph.append(edge)\n", 423 | " return filtered_graph\n", 424 | "\n", 425 | "def keyword_search_onto(keyword, onto):\n", 426 | " \"\"\"Search and index key entity from onto given keyword.\n", 427 | " \"\"\"\n", 428 | " classes = list(onto.classes())\n", 429 | " classes_str = [x.name for x in classes]\n", 430 | " all_res = difflib.get_close_matches(keyword, classes_str)\n", 431 | " # Only grab the most probable search keyword\n", 432 | " if len(all_res) > 0:\n", 433 | " res = all_res[0]\n", 434 | " return classes[classes_str.index(res)]\n", 435 | " else:\n", 436 | " return None\n", 437 | "\n", 438 | "def _to_string(graph):\n", 439 | " \"\"\"Helper: Convert everything collected inside graph list into\n", 440 | " string.\n", 441 | " \"\"\"\n", 442 | " for i in range(len(graph)):\n", 443 | " edge = list(graph[i])\n", 444 | " for k in range(len(edge)):\n", 445 | " if type(edge[k]) is not str:\n", 446 | " edge[k] = edge[k].name\n", 447 | " edge[k] = edge[k].replace(',', ', ')\n", 448 | " graph[i] = (edge[0], edge[1], edge[2])\n", 449 | " return graph\n", 450 | "\n", 451 | "def ontograf_simple(orig_entity, onto):\n", 452 | " \"\"\"Interface func to search and retrieve infor for a given\n", 453 | " entity inside onto.\n", 454 | " \"\"\"\n", 455 | " if orig_entity is None:\n", 456 | " return []\n", 457 | " \n", 458 | " # Initial graph search\n", 459 | " graph = generate_knowledge_graph(orig_entity)\n", 460 | " \n", 461 | " # Prep for other key entities given the initial graph\n", 462 | " entities = []\n", 463 | " for edge in graph:\n", 464 | " entities.append(edge[2])\n", 465 | "\n", 466 | " # 1st-level of filters, append more info from children and parent nodes\n", 467 | " for entity in entities:\n", 468 | " sub_graph = generate_knowledge_graph(entity)\n", 469 | " for edge in sub_graph:\n", 470 | " if edge[2] == orig_entity:\n", 471 | " if (entity, edge[1], orig_entity) not in graph and entity != orig_entity:\n", 472 | " graph.append((entity, edge[1], orig_entity))\n", 473 | "\n", 474 | " # 2nd-level of filters, filter some ill-logical nodes\n", 475 | " graph = _filter_graph(graph, onto)\n", 476 | "\n", 477 | " # Convert everything inside graph into str\n", 478 | " graph = _to_string(graph)\n", 479 | "\n", 480 | " return graph" 481 | ] 482 | }, 483 | { 484 | "cell_type": "code", 485 | "execution_count": 8, 486 | "metadata": {}, 487 | "outputs": [], 488 | "source": [ 489 | "def convert_to_graphviz(graph, name='KG'):\n", 490 | " \"\"\"Helper function to convert edge graph into graphviz.Digraph.\n", 491 | " \"\"\"\n", 492 | " e = graphviz.Digraph(name)\n", 493 | " e.attr('node', shape='box')\n", 494 | " for edge in graph:\n", 495 | " e.attr('node', shape='box')\n", 496 | " e.node(edge[0])\n", 497 | " e.node(edge[2])\n", 498 | " e.edge(edge[0], edge[2], label=edge[1])\n", 499 | " return e" 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "execution_count": 9, 505 | "metadata": {}, 506 | "outputs": [ 507 | { 508 | "name": "stdout", 509 | "output_type": "stream", 510 | "text": [ 511 | "--------------------\n", 512 | "True object_onto.PlasticBottle\n", 513 | "[('PlasticBottle', 'hasMaterial, some', 'Plastic'), ('PlasticBottle', 'subclass_of', 'Bottle'), ('PlasticBottle', 'isGraspableBy, some', 'Human'), ('PlasticBottle', 'has_individual', 'PlasticBottle1'), ('PlasticBottle', 'has_individual', 'PlasticBottle2'), ('Bottle', 'has_subclass', 'PlasticBottle'), ('Human', 'canGrasp, some', 'PlasticBottle')]\n" 514 | ] 515 | }, 516 | { 517 | "data": { 518 | "image/svg+xml": [ 519 | "\n", 520 | "\n", 522 | "\n", 524 | "\n", 525 | "\n", 527 | "\n", 528 | "KG\n", 529 | "\n", 530 | "\n", 531 | "\n", 532 | "PlasticBottle\n", 533 | "\n", 534 | "PlasticBottle\n", 535 | "\n", 536 | "\n", 537 | "\n", 538 | "Plastic\n", 539 | "\n", 540 | "Plastic\n", 541 | "\n", 542 | "\n", 543 | "\n", 544 | "PlasticBottle->Plastic\n", 545 | "\n", 546 | "\n", 547 | "hasMaterial, some\n", 548 | "\n", 549 | "\n", 550 | "\n", 551 | "Bottle\n", 552 | "\n", 553 | "Bottle\n", 554 | "\n", 555 | "\n", 556 | "\n", 557 | "PlasticBottle->Bottle\n", 558 | "\n", 559 | "\n", 560 | "subclass_of\n", 561 | "\n", 562 | "\n", 563 | "\n", 564 | "Human\n", 565 | "\n", 566 | "Human\n", 567 | "\n", 568 | "\n", 569 | "\n", 570 | "PlasticBottle->Human\n", 571 | "\n", 572 | "\n", 573 | "isGraspableBy, some\n", 574 | "\n", 575 | "\n", 576 | "\n", 577 | "PlasticBottle1\n", 578 | "\n", 579 | "PlasticBottle1\n", 580 | "\n", 581 | "\n", 582 | "\n", 583 | "PlasticBottle->PlasticBottle1\n", 584 | "\n", 585 | "\n", 586 | "has_individual\n", 587 | "\n", 588 | "\n", 589 | "\n", 590 | "PlasticBottle2\n", 591 | "\n", 592 | "PlasticBottle2\n", 593 | "\n", 594 | "\n", 595 | "\n", 596 | "PlasticBottle->PlasticBottle2\n", 597 | "\n", 598 | "\n", 599 | "has_individual\n", 600 | "\n", 601 | "\n", 602 | "\n", 603 | "Bottle->PlasticBottle\n", 604 | "\n", 605 | "\n", 606 | "has_subclass\n", 607 | "\n", 608 | "\n", 609 | "\n", 610 | "Human->PlasticBottle\n", 611 | "\n", 612 | "\n", 613 | "canGrasp, some\n", 614 | "\n", 615 | "\n", 616 | "\n" 617 | ], 618 | "text/plain": [ 619 | "" 620 | ] 621 | }, 622 | "execution_count": 9, 623 | "metadata": {}, 624 | "output_type": "execute_result" 625 | } 626 | ], 627 | "source": [ 628 | "print('-'*20)\n", 629 | "entity = keyword_search_onto('plasticbottle', onto)\n", 630 | "print(entity == onto.PlasticBottle, entity)\n", 631 | "kg = ontograf_simple(entity, onto)\n", 632 | "print(kg)\n", 633 | "convert_to_graphviz(kg)" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": 10, 639 | "metadata": {}, 640 | "outputs": [ 641 | { 642 | "name": "stdout", 643 | "output_type": "stream", 644 | "text": [ 645 | "--------------------\n", 646 | "False None\n", 647 | "[]\n" 648 | ] 649 | }, 650 | { 651 | "data": { 652 | "image/svg+xml": [ 653 | "\n", 654 | "\n", 656 | "\n", 658 | "\n", 659 | "\n", 661 | "\n", 662 | "KG\n", 663 | "\n", 664 | "\n", 665 | "\n" 666 | ], 667 | "text/plain": [ 668 | "" 669 | ] 670 | }, 671 | "execution_count": 10, 672 | "metadata": {}, 673 | "output_type": "execute_result" 674 | } 675 | ], 676 | "source": [ 677 | "print('-'*20)\n", 678 | "entity = keyword_search_onto('papercup', onto)\n", 679 | "print(entity == onto.GlassBottle, entity)\n", 680 | "kg = ontograf_simple(entity, onto)\n", 681 | "print(kg)\n", 682 | "convert_to_graphviz(kg)" 683 | ] 684 | }, 685 | { 686 | "cell_type": "code", 687 | "execution_count": 11, 688 | "metadata": {}, 689 | "outputs": [ 690 | { 691 | "name": "stdout", 692 | "output_type": "stream", 693 | "text": [ 694 | "--------------------\n", 695 | "True object_onto.Bottle\n", 696 | "[('Bottle', 'has_subclass', 'GlassBottle'), ('GlassBottle', 'subclass_of', 'Bottle'), ('Bottle', 'has_subclass', 'PlasticBottle'), ('PlasticBottle', 'subclass_of', 'Bottle'), ('Bottle', 'subclass_of', 'Container'), ('Container', 'has_subclass', 'Bottle')]\n" 697 | ] 698 | }, 699 | { 700 | "data": { 701 | "image/svg+xml": [ 702 | "\n", 703 | "\n", 705 | "\n", 707 | "\n", 708 | "\n", 710 | "\n", 711 | "KG\n", 712 | "\n", 713 | "\n", 714 | "\n", 715 | "Bottle\n", 716 | "\n", 717 | "Bottle\n", 718 | "\n", 719 | "\n", 720 | "\n", 721 | "GlassBottle\n", 722 | "\n", 723 | "GlassBottle\n", 724 | "\n", 725 | "\n", 726 | "\n", 727 | "Bottle->GlassBottle\n", 728 | "\n", 729 | "\n", 730 | "has_subclass\n", 731 | "\n", 732 | "\n", 733 | "\n", 734 | "PlasticBottle\n", 735 | "\n", 736 | "PlasticBottle\n", 737 | "\n", 738 | "\n", 739 | "\n", 740 | "Bottle->PlasticBottle\n", 741 | "\n", 742 | "\n", 743 | "has_subclass\n", 744 | "\n", 745 | "\n", 746 | "\n", 747 | "Container\n", 748 | "\n", 749 | "Container\n", 750 | "\n", 751 | "\n", 752 | "\n", 753 | "Bottle->Container\n", 754 | "\n", 755 | "\n", 756 | "subclass_of\n", 757 | "\n", 758 | "\n", 759 | "\n", 760 | "GlassBottle->Bottle\n", 761 | "\n", 762 | "\n", 763 | "subclass_of\n", 764 | "\n", 765 | "\n", 766 | "\n", 767 | "PlasticBottle->Bottle\n", 768 | "\n", 769 | "\n", 770 | "subclass_of\n", 771 | "\n", 772 | "\n", 773 | "\n", 774 | "Container->Bottle\n", 775 | "\n", 776 | "\n", 777 | "has_subclass\n", 778 | "\n", 779 | "\n", 780 | "\n" 781 | ], 782 | "text/plain": [ 783 | "" 784 | ] 785 | }, 786 | "execution_count": 11, 787 | "metadata": {}, 788 | "output_type": "execute_result" 789 | } 790 | ], 791 | "source": [ 792 | "print('-'*20)\n", 793 | "entity = keyword_search_onto('bottle', onto)\n", 794 | "print(entity == onto.Bottle, entity)\n", 795 | "kg = ontograf_simple(entity, onto)\n", 796 | "print(kg)\n", 797 | "convert_to_graphviz(kg)" 798 | ] 799 | }, 800 | { 801 | "cell_type": "code", 802 | "execution_count": 12, 803 | "metadata": {}, 804 | "outputs": [ 805 | { 806 | "name": "stdout", 807 | "output_type": "stream", 808 | "text": [ 809 | "--------------------\n", 810 | "True object_onto.Container\n", 811 | "[('Container', 'has_subclass', 'Bottle'), ('Bottle', 'subclass_of', 'Container'), ('Container', 'subclass_of', 'DomainThing'), ('DomainThing', 'has_subclass', 'Container')]\n" 812 | ] 813 | }, 814 | { 815 | "data": { 816 | "image/svg+xml": [ 817 | "\n", 818 | "\n", 820 | "\n", 822 | "\n", 823 | "\n", 825 | "\n", 826 | "KG\n", 827 | "\n", 828 | "\n", 829 | "\n", 830 | "Container\n", 831 | "\n", 832 | "Container\n", 833 | "\n", 834 | "\n", 835 | "\n", 836 | "Bottle\n", 837 | "\n", 838 | "Bottle\n", 839 | "\n", 840 | "\n", 841 | "\n", 842 | "Container->Bottle\n", 843 | "\n", 844 | "\n", 845 | "has_subclass\n", 846 | "\n", 847 | "\n", 848 | "\n", 849 | "DomainThing\n", 850 | "\n", 851 | "DomainThing\n", 852 | "\n", 853 | "\n", 854 | "\n", 855 | "Container->DomainThing\n", 856 | "\n", 857 | "\n", 858 | "subclass_of\n", 859 | "\n", 860 | "\n", 861 | "\n", 862 | "Bottle->Container\n", 863 | "\n", 864 | "\n", 865 | "subclass_of\n", 866 | "\n", 867 | "\n", 868 | "\n", 869 | "DomainThing->Container\n", 870 | "\n", 871 | "\n", 872 | "has_subclass\n", 873 | "\n", 874 | "\n", 875 | "\n" 876 | ], 877 | "text/plain": [ 878 | "" 879 | ] 880 | }, 881 | "execution_count": 12, 882 | "metadata": {}, 883 | "output_type": "execute_result" 884 | } 885 | ], 886 | "source": [ 887 | "print('-'*20)\n", 888 | "entity = keyword_search_onto('container', onto)\n", 889 | "print(entity == onto.Container, entity)\n", 890 | "kg = ontograf_simple(entity, onto)\n", 891 | "print(kg)\n", 892 | "convert_to_graphviz(kg)" 893 | ] 894 | }, 895 | { 896 | "cell_type": "code", 897 | "execution_count": 13, 898 | "metadata": {}, 899 | "outputs": [ 900 | { 901 | "name": "stdout", 902 | "output_type": "stream", 903 | "text": [ 904 | "--------------------\n", 905 | "True object_onto.Plastic\n", 906 | "[('Plastic', 'subclass_of', 'MaterialPartition'), ('Plastic', 'canWithstandTemperature, some', 'Cold'), ('Plastic', 'canWithstandTemperature, some', 'Mild'), ('MaterialPartition', 'has_subclass', 'Plastic')]\n" 907 | ] 908 | }, 909 | { 910 | "data": { 911 | "image/svg+xml": [ 912 | "\n", 913 | "\n", 915 | "\n", 917 | "\n", 918 | "\n", 920 | "\n", 921 | "KG\n", 922 | "\n", 923 | "\n", 924 | "\n", 925 | "Plastic\n", 926 | "\n", 927 | "Plastic\n", 928 | "\n", 929 | "\n", 930 | "\n", 931 | "MaterialPartition\n", 932 | "\n", 933 | "MaterialPartition\n", 934 | "\n", 935 | "\n", 936 | "\n", 937 | "Plastic->MaterialPartition\n", 938 | "\n", 939 | "\n", 940 | "subclass_of\n", 941 | "\n", 942 | "\n", 943 | "\n", 944 | "Cold\n", 945 | "\n", 946 | "Cold\n", 947 | "\n", 948 | "\n", 949 | "\n", 950 | "Plastic->Cold\n", 951 | "\n", 952 | "\n", 953 | "canWithstandTemperature, some\n", 954 | "\n", 955 | "\n", 956 | "\n", 957 | "Mild\n", 958 | "\n", 959 | "Mild\n", 960 | "\n", 961 | "\n", 962 | "\n", 963 | "Plastic->Mild\n", 964 | "\n", 965 | "\n", 966 | "canWithstandTemperature, some\n", 967 | "\n", 968 | "\n", 969 | "\n", 970 | "MaterialPartition->Plastic\n", 971 | "\n", 972 | "\n", 973 | "has_subclass\n", 974 | "\n", 975 | "\n", 976 | "\n" 977 | ], 978 | "text/plain": [ 979 | "" 980 | ] 981 | }, 982 | "execution_count": 13, 983 | "metadata": {}, 984 | "output_type": "execute_result" 985 | } 986 | ], 987 | "source": [ 988 | "print('-'*20)\n", 989 | "entity = keyword_search_onto('plastic', onto)\n", 990 | "print(entity == onto.Plastic, entity)\n", 991 | "kg = ontograf_simple(entity, onto)\n", 992 | "print(kg)\n", 993 | "convert_to_graphviz(kg)" 994 | ] 995 | }, 996 | { 997 | "cell_type": "code", 998 | "execution_count": 14, 999 | "metadata": {}, 1000 | "outputs": [ 1001 | { 1002 | "name": "stdout", 1003 | "output_type": "stream", 1004 | "text": [ 1005 | "--------------------\n", 1006 | "False object_onto.GlassBottle\n", 1007 | "[('GlassBottle', 'hasMaterial, some', 'Glass'), ('GlassBottle', 'subclass_of', 'Bottle'), ('GlassBottle', 'isGraspableBy, some', 'Human'), ('GlassBottle', 'has_individual', 'GlassBottle1'), ('Bottle', 'has_subclass', 'GlassBottle'), ('Human', 'canGrasp, some', 'GlassBottle')]\n" 1008 | ] 1009 | }, 1010 | { 1011 | "data": { 1012 | "image/svg+xml": [ 1013 | "\n", 1014 | "\n", 1016 | "\n", 1018 | "\n", 1019 | "\n", 1021 | "\n", 1022 | "KG\n", 1023 | "\n", 1024 | "\n", 1025 | "\n", 1026 | "GlassBottle\n", 1027 | "\n", 1028 | "GlassBottle\n", 1029 | "\n", 1030 | "\n", 1031 | "\n", 1032 | "Glass\n", 1033 | "\n", 1034 | "Glass\n", 1035 | "\n", 1036 | "\n", 1037 | "\n", 1038 | "GlassBottle->Glass\n", 1039 | "\n", 1040 | "\n", 1041 | "hasMaterial, some\n", 1042 | "\n", 1043 | "\n", 1044 | "\n", 1045 | "Bottle\n", 1046 | "\n", 1047 | "Bottle\n", 1048 | "\n", 1049 | "\n", 1050 | "\n", 1051 | "GlassBottle->Bottle\n", 1052 | "\n", 1053 | "\n", 1054 | "subclass_of\n", 1055 | "\n", 1056 | "\n", 1057 | "\n", 1058 | "Human\n", 1059 | "\n", 1060 | "Human\n", 1061 | "\n", 1062 | "\n", 1063 | "\n", 1064 | "GlassBottle->Human\n", 1065 | "\n", 1066 | "\n", 1067 | "isGraspableBy, some\n", 1068 | "\n", 1069 | "\n", 1070 | "\n", 1071 | "GlassBottle1\n", 1072 | "\n", 1073 | "GlassBottle1\n", 1074 | "\n", 1075 | "\n", 1076 | "\n", 1077 | "GlassBottle->GlassBottle1\n", 1078 | "\n", 1079 | "\n", 1080 | "has_individual\n", 1081 | "\n", 1082 | "\n", 1083 | "\n", 1084 | "Bottle->GlassBottle\n", 1085 | "\n", 1086 | "\n", 1087 | "has_subclass\n", 1088 | "\n", 1089 | "\n", 1090 | "\n", 1091 | "Human->GlassBottle\n", 1092 | "\n", 1093 | "\n", 1094 | "canGrasp, some\n", 1095 | "\n", 1096 | "\n", 1097 | "\n" 1098 | ], 1099 | "text/plain": [ 1100 | "" 1101 | ] 1102 | }, 1103 | "execution_count": 14, 1104 | "metadata": {}, 1105 | "output_type": "execute_result" 1106 | } 1107 | ], 1108 | "source": [ 1109 | "print('-'*20)\n", 1110 | "entity = keyword_search_onto('glassbottle', onto)\n", 1111 | "print(entity == onto.HumanHand, entity)\n", 1112 | "kg = ontograf_simple(entity, onto)\n", 1113 | "print(kg)\n", 1114 | "convert_to_graphviz(kg)" 1115 | ] 1116 | }, 1117 | { 1118 | "cell_type": "code", 1119 | "execution_count": 15, 1120 | "metadata": {}, 1121 | "outputs": [ 1122 | { 1123 | "name": "stdout", 1124 | "output_type": "stream", 1125 | "text": [ 1126 | "--------------------\n", 1127 | "False object_onto.Cold\n", 1128 | "[('Cold', 'subclass_of', 'TemperatureValuePartition'), ('TemperatureValuePartition', 'has_subclass', 'Cold')]\n" 1129 | ] 1130 | }, 1131 | { 1132 | "data": { 1133 | "image/svg+xml": [ 1134 | "\n", 1135 | "\n", 1137 | "\n", 1139 | "\n", 1140 | "\n", 1142 | "\n", 1143 | "KG\n", 1144 | "\n", 1145 | "\n", 1146 | "\n", 1147 | "Cold\n", 1148 | "\n", 1149 | "Cold\n", 1150 | "\n", 1151 | "\n", 1152 | "\n", 1153 | "TemperatureValuePartition\n", 1154 | "\n", 1155 | "TemperatureValuePartition\n", 1156 | "\n", 1157 | "\n", 1158 | "\n", 1159 | "Cold->TemperatureValuePartition\n", 1160 | "\n", 1161 | "\n", 1162 | "subclass_of\n", 1163 | "\n", 1164 | "\n", 1165 | "\n", 1166 | "TemperatureValuePartition->Cold\n", 1167 | "\n", 1168 | "\n", 1169 | "has_subclass\n", 1170 | "\n", 1171 | "\n", 1172 | "\n" 1173 | ], 1174 | "text/plain": [ 1175 | "" 1176 | ] 1177 | }, 1178 | "execution_count": 15, 1179 | "metadata": {}, 1180 | "output_type": "execute_result" 1181 | } 1182 | ], 1183 | "source": [ 1184 | "print('-'*20)\n", 1185 | "entity = keyword_search_onto('cold', onto)\n", 1186 | "print(entity == onto.HumanHand, entity)\n", 1187 | "kg = ontograf_simple(entity, onto)\n", 1188 | "print(kg)\n", 1189 | "convert_to_graphviz(kg)" 1190 | ] 1191 | }, 1192 | { 1193 | "cell_type": "code", 1194 | "execution_count": 16, 1195 | "metadata": {}, 1196 | "outputs": [ 1197 | { 1198 | "name": "stdout", 1199 | "output_type": "stream", 1200 | "text": [ 1201 | "--------------------\n", 1202 | "True None\n", 1203 | "[]\n" 1204 | ] 1205 | }, 1206 | { 1207 | "data": { 1208 | "image/svg+xml": [ 1209 | "\n", 1210 | "\n", 1212 | "\n", 1214 | "\n", 1215 | "\n", 1217 | "\n", 1218 | "KG\n", 1219 | "\n", 1220 | "\n", 1221 | "\n" 1222 | ], 1223 | "text/plain": [ 1224 | "" 1225 | ] 1226 | }, 1227 | "execution_count": 16, 1228 | "metadata": {}, 1229 | "output_type": "execute_result" 1230 | } 1231 | ], 1232 | "source": [ 1233 | "print('-'*20)\n", 1234 | "entity = keyword_search_onto('hello', onto)\n", 1235 | "print(entity == onto.HumanHand, entity)\n", 1236 | "kg = ontograf_simple(entity, onto)\n", 1237 | "print(kg)\n", 1238 | "convert_to_graphviz(kg)" 1239 | ] 1240 | } 1241 | ], 1242 | "metadata": { 1243 | "kernelspec": { 1244 | "display_name": "Python 3", 1245 | "language": "python", 1246 | "name": "python3" 1247 | }, 1248 | "language_info": { 1249 | "codemirror_mode": { 1250 | "name": "ipython", 1251 | "version": 3 1252 | }, 1253 | "file_extension": ".py", 1254 | "mimetype": "text/x-python", 1255 | "name": "python", 1256 | "nbconvert_exporter": "python", 1257 | "pygments_lexer": "ipython3", 1258 | "version": "3.6.9" 1259 | } 1260 | }, 1261 | "nbformat": 4, 1262 | "nbformat_minor": 2 1263 | } 1264 | --------------------------------------------------------------------------------