Skip to content

Introducing Iolanta ontology
Assignment for MC-1 Fall 2025 © Anatoly Scherbakov

Problem & Use Cases

The semantic web contains vast amounts of machine-readable RDF data, but this data is often difficult for humans to understand and navigate.

  • Iolanta is a tool that aims to provide a uniform way to make Linked Data human friendly,
  • which capability is underpinned by the Iolanta ontology described in this document.

Use cases we're going to focus on are as follows:

  • Visualize Linked Data


    Different output formats require different visualization approaches. Iolanta's facet system adapts rendering based on output datatype, allowing the same data to be rendered as text, HTML, diagrams, or other formats.

  • Browse & Discover Linked Data


    Iolanta implements text-based terminal interface to browse Linked Data on the Web.

Serialization: YAML-LD

The Iolanta ontology is implemented using YAML-LD, a human-friendly serialization format for JSON-LD that makes RDF data more readable and maintainable. Each class and property is defined in separate .yamlld files with a shared context, which is provided below.

context.yamlld
"@context":
  # Use $keywords instead of @keywords in the ontology & data files.
  # This will allow to avoid extra quotes.
  "@import": https://json-ld.org/contexts/dollar-convenience.jsonld

  # Make well known ontologies usable
  rdfs: http://www.w3.org/2000/01/rdf-schema#
  owl: http://www.w3.org/2002/07/owl#
  foaf: http://xmlns.com/foaf/0.1/
  schema: https://schema.org/
  vann: http://purl.org/vocab/vann/
  rdfg: http://www.w3.org/2009/rdfg#
  xsd: http://www.w3.org/2001/XMLSchema#

  $: rdfs:label

  # I have a weakness for Unicode symbols and YAML-LD permits me an indulgence ☺
  :
    "@type": "@id"
    "@id": rdfs:subClassOf

  domain:
    "@id": rdfs:domain
    "@type": "@id"

  range:
    "@id": rdfs:range
    "@type": "@id"

  :
    "@id": iolanta:outputs
    "@type": "@id"

  :
    "@id": iolanta:matches

Facet class

facet.yamlld
"@context": context.yamlld

$id: iolanta:Facet
$type: owl:Class

$: Facet

rdfs:comment: |
  A Facet is a visualization component that transforms RDF nodes into human-readable formats.
  Facets are the core mechanism by which Iolanta makes Linked Data accessible to users.
  Each facet is designed to handle specific types of RDF nodes and render them appropriately
  for different output formats (terminal, web, etc.).
graph LR
  iolanta_Facet("Facet")
  click iolanta_Facet "iolanta:Facet"
  http___www_w3_org_2002_07_owl_Class("Class")
  click http___www_w3_org_2002_07_owl_Class "http://www.w3.org/2002/07/owl#Class"
  Literal_0161428b8153[["A Facet is a visualization component that transforms RDF nodes into human-readable formats.
  Facets are the core mechanism by which Iolanta makes Linked Data accessible to users.
  Each facet is designed to handle specific types of RDF nodes and render them appropriately
  for different output formats (terminal, web, etc.).
  "]]
  iolanta_Facet --- Edge_8ef46633b9a9(["∈ type"])--> http___www_w3_org_2002_07_owl_Class
  click Edge_8ef46633b9a9 "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  iolanta_Facet --- Edge_1f01064c56b1(["comment"])--> Literal_0161428b8153
  click Edge_1f01064c56b1 "http://www.w3.org/2000/01/rdf-schema#comment"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_8ef46633b9a9,Edge_1f01064c56b1 predicate

Graph rendering

One of the Facets that Iolanta implements is a Mermaid renderer, which was responsible for generation of the graph above. Below, we will look a bit deeper into how that works.

OutputDatatype class

output-datatype.yamlld
"@context": context.yamlld

$id: iolanta:OutputDatatype
$type: owl:Class

$: Output Datatype

: rdfs:Datatype

rdfs:comment: |
  Output format where visualization applications render their results.
  Examples: terminal text, HTML, Mermaid diagrams.
graph LR
  iolanta_OutputDatatype("Output Datatype")
  click iolanta_OutputDatatype "iolanta:OutputDatatype"
  Literal_53d3f4c1edd7[["Output format where visualization applications render their results.
  Examples: terminal text, HTML, Mermaid diagrams.
  "]]
  http___www_w3_org_2002_07_owl_Class("Class")
  click http___www_w3_org_2002_07_owl_Class "http://www.w3.org/2002/07/owl#Class"
  http___www_w3_org_2000_01_rdf_schema_Datatype("⊤ Datatype")
  click http___www_w3_org_2000_01_rdf_schema_Datatype "http://www.w3.org/2000/01/rdf-schema#Datatype"
  iolanta_OutputDatatype --- Edge_905cb2360eae(["comment"])--> Literal_53d3f4c1edd7
  click Edge_905cb2360eae "http://www.w3.org/2000/01/rdf-schema#comment"
  iolanta_OutputDatatype --- Edge_bab53b5875b3(["∈ type"])--> http___www_w3_org_2002_07_owl_Class
  click Edge_bab53b5875b3 "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  iolanta_OutputDatatype --- Edge_20ca01fb95be(["subClassOf"])--> http___www_w3_org_2000_01_rdf_schema_Datatype
  click Edge_20ca01fb95be "http://www.w3.org/2000/01/rdf-schema#subClassOf"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_905cb2360eae,Edge_bab53b5875b3,Edge_20ca01fb95be predicate

SPARQLText class

sparql-text.yamlld
"@context": context.yamlld

$id: iolanta:SPARQLText
$type: owl:Class

$: SPARQL Text

: rdfs:Datatype

comment: |
  Datatype for SPARQL query text.
  Must be valid SPARQL syntax.
graph LR
  iolanta_SPARQLText("SPARQL Text")
  click iolanta_SPARQLText "iolanta:SPARQLText"
  http___www_w3_org_2002_07_owl_Class("Class")
  click http___www_w3_org_2002_07_owl_Class "http://www.w3.org/2002/07/owl#Class"
  http___www_w3_org_2000_01_rdf_schema_Datatype("⊤ Datatype")
  click http___www_w3_org_2000_01_rdf_schema_Datatype "http://www.w3.org/2000/01/rdf-schema#Datatype"
  iolanta_SPARQLText --- Edge_6e423e8a5cbd(["∈ type"])--> http___www_w3_org_2002_07_owl_Class
  click Edge_6e423e8a5cbd "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  iolanta_SPARQLText --- Edge_8f9205099227(["subClassOf"])--> http___www_w3_org_2000_01_rdf_schema_Datatype
  click Edge_8f9205099227 "http://www.w3.org/2000/01/rdf-schema#subClassOf"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_6e423e8a5cbd,Edge_8f9205099227 predicate

matches datatype property

matches.yamlld
"@context": context.yamlld

$id: iolanta:matches
$type: owl:DatatypeProperty

$: matches
domain: iolanta:Facet
range: iolanta:SPARQLText

comment: |
  Maps a Facet instance to a SPARQL <code>ASK</code>
  query pattern that can use <code>$this</code>
  bound variable. If the query returns True,
  this Facet can visualize the node denoted as
  <code>$this</code> in the query.
graph LR
  iolanta_matches("matches")
  click iolanta_matches "iolanta:matches"
  iolanta_Facet("Facet")
  click iolanta_Facet "iolanta:Facet"
  iolanta_SPARQLText("SPARQL Text")
  click iolanta_SPARQLText "iolanta:SPARQLText"
  http___www_w3_org_2002_07_owl_DatatypeProperty("DatatypeProperty")
  click http___www_w3_org_2002_07_owl_DatatypeProperty "http://www.w3.org/2002/07/owl#DatatypeProperty"
  iolanta_matches --- Edge_ced4624fbf8e(["domain"])--> iolanta_Facet
  click Edge_ced4624fbf8e "http://www.w3.org/2000/01/rdf-schema#domain"
  iolanta_matches --- Edge_1fb9453a6bfd(["range"])--> iolanta_SPARQLText
  click Edge_1fb9453a6bfd "http://www.w3.org/2000/01/rdf-schema#range"
  iolanta_matches --- Edge_7dff95a0c771(["∈ type"])--> http___www_w3_org_2002_07_owl_DatatypeProperty
  click Edge_7dff95a0c771 "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_ced4624fbf8e,Edge_1fb9453a6bfd,Edge_7dff95a0c771 predicate

outputs object property

outputs.yamlld
"@context": context.yamlld

$id: iolanta:outputs
$type: owl:ObjectProperty

$: outputs

domain: iolanta:Facet
range: iolanta:OutputDatatype

comment: |
  Links a facet to its supported output formats.
  Examples: terminal, HTML, Mermaid.
graph LR
  iolanta_outputs("outputs")
  click iolanta_outputs "iolanta:outputs"
  iolanta_Facet("Facet")
  click iolanta_Facet "iolanta:Facet"
  http___www_w3_org_2002_07_owl_ObjectProperty("ObjectProperty")
  click http___www_w3_org_2002_07_owl_ObjectProperty "http://www.w3.org/2002/07/owl#ObjectProperty"
  iolanta_OutputDatatype("Output Datatype")
  click iolanta_OutputDatatype "iolanta:OutputDatatype"
  iolanta_outputs --- Edge_e5ce58eefcc6(["domain"])--> iolanta_Facet
  click Edge_e5ce58eefcc6 "http://www.w3.org/2000/01/rdf-schema#domain"
  iolanta_outputs --- Edge_318dc62ce4e6(["∈ type"])--> http___www_w3_org_2002_07_owl_ObjectProperty
  click Edge_318dc62ce4e6 "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  iolanta_outputs --- Edge_5cbb08f9224d(["range"])--> iolanta_OutputDatatype
  click Edge_5cbb08f9224d "http://www.w3.org/2000/01/rdf-schema#range"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_e5ce58eefcc6,Edge_318dc62ce4e6,Edge_5cbb08f9224d predicate

Identifier Strategy

We use slash-terminated URIs under https://iolanta.tech/ so every resource is dereferenceable to its own page.

Facet identifiers with Package URL (purl)

Facets use pkg: URIs per the purl spec.

  • Format: pkg:pypi/<package>#<facet>
  • Examples:
    • pkg:pypi/iolanta#mermaid-graph for Mermaid rendering;
    • pkg:pypi/iolanta#textual-graph for text user interface graph triple lists;
    • pkg:pypi/iolanta#title-foaf-person for the name of a person
  • Benefits: unique package-scoped IDs; version-agnostic; standards-based

Graph Representation Choice

Since the domain is Linked Data visualization, we use RDF with OWL semantics, and SPARQL as the query language.

  • Native URIs and vocabularies; broad reuse and interoperability.
  • LPG is out of scope for this document.

Querying the Knowledge Graph & Visualizing it

There are at least two ways to get a Mermaid representation of the Facet class description:

{{ (docs / 'blog/knowledge-graph-assignment/facet.yamlld') | as('mermaid') }}
iolanta docs/blog/knowledge-graph-assignment/facet.yamlld --as mermaid

Stage 0: What is mermaid exactly?

It is a shortened form of https://iolanta.tech/datatypes/mermaid, an instance of OutputDatatype defined as follows:

mermaid.yamlld
"@context":
  "@import": https://json-ld.org/contexts/dollar-convenience.jsonld
  iolanta: https://iolanta.tech/
  rdfs: http://www.w3.org/2000/01/rdf-schema#

  $: rdfs:label
  :
    "@type": "@id"
    "@id": iolanta:outputs

  :
    "@id": iolanta:matches
    "@type": iolanta:SPARQLText

$id: pkg:pypi/iolanta#mermaid-graph
$: Mermaid Graph

:
  $id: https://iolanta.tech/datatypes/mermaid
  $: Mermaid
  $type: iolanta:OutputDatatype

:
  - ASK WHERE { GRAPH $this { ?s ?p ?o } }
  - ASK WHERE { $this iolanta:has-sub-graph ?subgraph }
graph LR
  pkg_pypi_iolanta_mermaid_graph("Mermaid Graph")
  click pkg_pypi_iolanta_mermaid_graph "pkg:pypi/iolanta#mermaid-graph"
  Literal_e6835a48474d[["ASK WHERE { $this iolanta:has-sub-graph ?subgraph }"]]
  https___iolanta_tech_datatypes_mermaid("Ⓜ Mermaid")
  click https___iolanta_tech_datatypes_mermaid "https://iolanta.tech/datatypes/mermaid"
  Literal_ee9b155b26d2[["Mermaid"]]
  https___iolanta_tech_OutputDatatype("▤ iolanta.tech/OutputDatatype")
  click https___iolanta_tech_OutputDatatype "https://iolanta.tech/OutputDatatype"
  Literal_c68220abab4f[["ASK WHERE { GRAPH $this { ?s ?p ?o } }"]]
  pkg_pypi_iolanta_mermaid_graph --- Edge_d8a450804116(["▾ iolanta.tech/matches"])--> Literal_e6835a48474d
  click Edge_d8a450804116 "https://iolanta.tech/matches"
  https___iolanta_tech_datatypes_mermaid --- Edge_8660be92ee28(["label"])--> Literal_ee9b155b26d2
  click Edge_8660be92ee28 "http://www.w3.org/2000/01/rdf-schema#label"
  pkg_pypi_iolanta_mermaid_graph --- Edge_890effb8fce0(["→ outputs"])--> https___iolanta_tech_datatypes_mermaid
  click Edge_890effb8fce0 "https://iolanta.tech/outputs"
  https___iolanta_tech_datatypes_mermaid --- Edge_7a5cb3e461f1(["∈ type"])--> https___iolanta_tech_OutputDatatype
  click Edge_7a5cb3e461f1 "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  pkg_pypi_iolanta_mermaid_graph --- Edge_25a9735ec6fb(["▾ iolanta.tech/matches"])--> Literal_c68220abab4f
  click Edge_25a9735ec6fb "https://iolanta.tech/matches"
  classDef predicate fill:#1f2233,stroke:transparent,color:#f8fafc,stroke-width:0px;
  classDef hidden fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  classDef nanopubdot fill:#0f172a,stroke:#0f172a,color:transparent,stroke-width:2px;
  classDef transparent fill:transparent,stroke:transparent,color:transparent,stroke-width:0px;
  class Edge_d8a450804116,Edge_8660be92ee28,Edge_890effb8fce0,Edge_7a5cb3e461f1,Edge_25a9735ec6fb predicate

Stage 1: Which facets can output a visualization of this iolanta:OutputDatatype?

To ascertain that, Iolanta will execute get-query-to-facet.sparql binding $as_datatype to iolanta:mermaid.

SELECT ?facet ?match WHERE {
    ?facet
        iolanta:matches ?match ;
        iolanta:outputs $as_datatype .
}
facet match
pkg:pypi/iolanta#mermaid-graph ASK WHERE { GRAPH $this { ?s ?p ?o } }
pkg:pypi/iolanta#mermaid-graph ASK WHERE { $this iolanta:has-sub-graph ?subgraph }

For each facet returned, Iolanta evaluates its ASK pattern binding $this to the target node. The mermaid facet matches with:

ASK WHERE {
  GRAPH $this { ?s ?p ?o }
}

⇒ which evaluates to: ✅ True

  • This matches because facet.yamlld is interpreted by Iolanta as an RDF named graph when loading this file;
  • We won't delve into iolanta:has-sub-graph, that's rather sketchy right now.

Stage 2: Resolve Facet

We'll not delve into this here, but just to mention:

  • The pkg: URI has a straightforward mapping to a Python object,
  • which is a Python class addressable as iolanta.mermaid.facet:Mermaid.

Where from is this class?

This particular class is bundled with Iolanta, but facet classes can also come with other Python packages — Iolanta plugins.

Here's an abridged version of the class:

class Mermaid(Facet[str]):
    """Mermaid diagram."""

    # …

    def construct_mermaid_for_graph(self, graph: URIRef) -> Iterable[MermaidScalar]:
        """Render graph as mermaid."""
        rows = self.stored_query('graph.sparql', this=graph)
        # …

    def show(self) -> str:
        """Render mermaid diagram."""
        # …
        return str(Diagram(children=[*direct_children, *subgraphs]))

Full version: see the Mermaid facet.

Now, facet class is able to run arbitrary SPARQL queries against the graph, retrieving the information necessary for the visualization.

Stage 3: Retrieving Graph Data

In particular, the Mermaid facet executes graph.sparql to fetch all triples in the named graph, substituting $this to the URI of facet.yamlld:

graph.sparql
SELECT * WHERE {
    GRAPH $this {
        ?s ?p ?o .
    }
}
Triples for facet.yamlld (too many of them)

| this s p o | | --- --- --- --- | | file:///home/runner/work/iolanta/iolanta/docs/blog/knowledge-graph-assignment/facet.yamlld iolanta:Facet http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.w3.org/2002/07/owl#Class | | file:///home/runner/work/iolanta/iolanta/docs/blog/knowledge-graph-assignment/facet.yamlld iolanta:Facet http://www.w3.org/2000/01/rdf-schema#label Facet | | file:///home/runner/work/iolanta/iolanta/docs/blog/knowledge-graph-assignment/facet.yamlld iolanta:Facet http://www.w3.org/2000/01/rdf-schema#comment A Facet is a visualization component that transforms RDF nodes into human-readable formats. Facets are the core mechanism by which Iolanta makes Linked Data accessible to users. Each facet is designed to handle specific types of RDF nodes and render them appropriately for different output formats (terminal, web, etc.). |

These triples are formatted as Mermaid nodes and edges by the facet, producing the diagram, which:

  • Either gets printed in the console, and you can save it to a file or copy it,
  • Or embedded into software which Iolanta is working with.

Other examples

  • An ORCID profile

    iolanta https://orcid.org/0000-0002-1825-0097
    
  • RDFS label

    iolanta http://www.w3.org/2000/01/rdf-schema#label
    
  • OWL vocabulary terms

    iolanta https://www.w3.org/2002/07/owl#
    

While rendering Linked Data, Iolanta will try to fetch references from the Web to other pieces of Linked Data. Thus, we are trying to get the most complete visualization.

Conclusion

The Iolanta ontology provides a framework for Linked Data visualization and browsing with:

  • Clear domain focus on semantic web usability
  • Well-structured RDF/OWL implementation
  • Professional URI strategy following Linked Data best practices
  • Full SPARQL support with real-world applications
  • Integration with existing semantic web resources