diff --git a/docs/explanations/shapes-and-templates.md b/docs/explanations/shapes-and-templates.md index 412ae75c..1933540f 100644 --- a/docs/explanations/shapes-and-templates.md +++ b/docs/explanations/shapes-and-templates.md @@ -21,7 +21,9 @@ a **Template** is a function that generates an RDF graph. ## Converting Shapes to Templates -BuildingMOTIF automatically converts shapes to templates. +### When Loading a Library + +BuildingMOTIF can automatically convert shapes to templates when loading a Library. Evaluating the resulting template will generate a graph that validates against the shape. When BuildingMOTIF loads a Library, it makes an attempt to find any shapes defined within it. @@ -49,6 +51,51 @@ BuildingMOTIF currently uses the name of the SHACL shape as the name of the gene All other parameters (i.e., nodes corresponding to `sh:property`) are given invented names *unless* there is a `sh:name` attribute on the property shape. +This feature can be disabled by setting `infer_templates=False` when calling `Library.load` + +### From Shape Collections + +It is also possible to convert the shapes defined in a Shape Collection to templates. +This is done by calling the `infer_templates` method on the Shape Collection. +If `infer_templates` is True when calling `Library.load`, then BuildingMOTIF will automatically call `infer_templates` on the Shape Collection +within that Library. + +Being able to call `infer_templates` on a Shape Collection is useful when you have +a graph of shapes that you programmatically created or loaded without packaging them +in a Library. + +```{code-cell} python3 +from buildingmotif import BuildingMOTIF +from buildingmotif.dataclasses import Library, ShapeCollection + +# in-memory instance +bm = BuildingMOTIF("sqlite://") + +my_shapes_source = """ +@prefix sh: . +@prefix owl: . +@prefix brick: . +@prefix ex: . + +ex:SimpleShape a sh:NodeShape, owl:Class ; + sh:property [ + sh:path ex:hasPoint ; + sh:qualifiedValueShape [ sh:class brick:Sensor ] ; + sh:qualifiedMinCount 1 ; + ] . +""" + +# create a ShapeCollection to hold the shapes +my_shapes = ShapeCollection.create() +my_shapes.graph.parse(data=my_shapes_source, format="ttl") + +# create a Library to hold the generated templates +lib = Library.create("my-library") +my_shapes.infer_templates(lib) + +print(lib.get_templates()) +``` + ### Example Consider the following shape which has been loaded into BuildingMOTIF as part of a Library: diff --git a/libraries/ZonePAC/shapes.ttl b/libraries/ZonePAC/shapes.ttl index 365e559c..83359971 100644 --- a/libraries/ZonePAC/shapes.ttl +++ b/libraries/ZonePAC/shapes.ttl @@ -23,7 +23,7 @@ owl:imports ; . -:zonepac-zone a sh:NodeShape ; +:zonepac-zone a sh:NodeShape, owl:Class ; sh:targetClass brick:HVAC_Zone ; sh:property [ sh:path brick:hasPoint ; @@ -37,7 +37,7 @@ ] ; . -:zonepac-vav a sh:NodeShape ; +:zonepac-vav a sh:NodeShape, owl:Class ; sh:targetClass brick:Terminal_Unit ; sh:property [ sh:path brick:hasPart ; @@ -56,7 +56,7 @@ ] ; . -:heating-coil a sh:NodeShape ; +:heating-coil a sh:NodeShape, owl:Class ; sh:targetClass brick:Heating_Coil ; sh:property [ sh:path brick:hasPoint ;