Visualizing the Graph Relationships - DDMAL/linkedmusic-datalake GitHub Wiki

Having a visual of the relationships between entities within a graph is useful for both debugging graph structure and generating/debugging SPARQL queries. Once a graph structure is finalized, the visual will not need to be recreated and thus automation of this process would be overkill.

1. Find the general relationships between entities

Visualizing a graph first requires the general relationships between entities. In the Virtuoso SPARQL endpoint, write the following SPARQL command

CONSTRUCT {
  ?stype ?p ?otype .
}
WHERE {
  VALUES ?g { <<Graph URI>> }

  {
    SELECT DISTINCT ?stype ?p ?otype
    WHERE {
      {
        GRAPH ?g {
          ?s ?p ?o .
          ?s rdf:type ?stype .
          ?o rdf:type ?otype .
        }
      } UNION {
        GRAPH ?g {
          ?s rdfs:label ?o .
          ?s rdf:type ?stype .
          BIND(rdfs:label AS ?p)
          BIND("label" AS ?otype)
        }
      } UNION {
        GRAPH ?g {
          ?s skos:altLabel ?o .
          ?s rdf:type ?stype .
          BIND(skos:altLabel AS ?p)
          BIND("alt label" AS ?otype)
        }
      } UNION {
        GRAPH ?g {
          ?s ?p ?o .
          ?s rdf:type ?stype .
          FILTER(isLiteral(?o) || STRSTARTS(STR(?o), STR(wd:)))
        }
        {
          SELECT DISTINCT ?p ?otype
          WHERE {
            SERVICE <https://query.wikidata.org/sparql> {
              ?prop wikibase:directClaim ?p .
              ?prop rdfs:label ?otype .
              FILTER(LANG(?otype) = "en")
            }
          }
        }
      }
    }
  }
}

e.g., for DIAMM:

CONSTRUCT {
  ?stype ?p ?otype .
}
WHERE {
  VALUES ?g { diamm: }

  {
    SELECT DISTINCT ?stype ?p ?otype
    WHERE {
      {
        GRAPH ?g {
          ?s ?p ?o .
          ?s rdf:type ?stype .
          ?o rdf:type ?otype .
        }
      } UNION {
        GRAPH ?g {
          ?s rdfs:label ?o .
          ?s rdf:type ?stype .
          BIND(rdfs:label AS ?p)
          BIND("label" AS ?otype)
        }
      } UNION {
        GRAPH ?g {
          ?s skos:altLabel ?o .
          ?s rdf:type ?stype .
          BIND(skos:altLabel AS ?p)
          BIND("alt label" AS ?otype)
        }
      } UNION {
        GRAPH ?g {
          ?s ?p ?o .
          ?s rdf:type ?stype .
          FILTER(isLiteral(?o) || STRSTARTS(STR(?o), STR(wd:)))
        }
        {
          SELECT DISTINCT ?p ?otype
          WHERE {
            SERVICE <https://query.wikidata.org/sparql> {
              ?prop wikibase:directClaim ?p .
              ?prop rdfs:label ?otype .
              FILTER(LANG(?otype) = "en")
            }
          }
        }
      }
    }
  }
}

Download the results as turtle (this option will only appear once you have written a query containing "CONSTRUCT").

2. Remove Language Labels From the TTL file

Open the TTL from Step 1 into the text editor of your choice.

Replace all instances of @en with nothing.

3. Generate the graph visual

Copy the output from Step 2 and paste it into RDF Grapher.

Make sure the "From format:" is set to "Turtle" and the "To format:" is set to "SVG". If the dataset is large, it may be prudent to check the "Send form as HTTP POST (needed for large RDF data):" option.

Click "Visualize" to generate the graph visual.

4. Alternative Query to Generate Graph Ontology

PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>
PREFIX owl:  <http://www.w3.org/2002/07/owl#>
PREFIX wd:   <http://www.wikidata.org/entity/>
CONSTRUCT {
  ?property a rdf:Property ;
            rdfs:domain ?domain ;
            rdfs:range ?range .
  ?class a rdfs:Class .
  wd:Entity a rdfs:Class .
}
WHERE {
VALUES ?g {<<GRAPH URI>>}
  {
    GRAPH ?g {
      ?instance rdf:type ?class .
    }
  }
  UNION
  {
    GRAPH ?g {
      ?subject ?property ?object .
      ?subject rdf:type ?domain .
      OPTIONAL {
        ?object rdf:type ?oType .
      }
    }
    # Determine range
    BIND(
      IF(
        isIRI(?object),
        IF(
          STRSTARTS(STR(?object), "http://www.wikidata.org/entity/"),
          wd:Entity,
          COALESCE(?oType, owl:Thing)
        ),
        IF(
          isLiteral(?object),
          COALESCE(datatype(?object), rdfs:Literal),
          UNDEF
        )
      ) AS ?range
    )
  }
}

4.1 Experimental SPARQL Query

This SPARQL query should theoretically be quicker at generating the ontology, but it has not been tested

PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>
PREFIX owl:  <http://www.w3.org/2002/07/owl#>
PREFIX wd:   <http://www.wikidata.org/entity/>
CONSTRUCT {
  ?property a rdf:Property ;
            rdfs:domain ?domain ;
            rdfs:range ?range .
  ?class a rdfs:Class .
  wd:Entity a rdfs:Class .
}
WHERE {
  GRAPH <GRAPH_URI> {
    {
      SELECT DISTINCT ?class WHERE {
        ?instance rdf:type ?class .
      }
    }
    UNION
    {
      SELECT DISTINCT ?domain ?property ?range WHERE {
        ?subject ?property ?object .
        ?subject rdf:type ?domain .
        OPTIONAL {
          ?object rdf:type ?oType .
        }
        # Determine range
        BIND(
          IF(
            isIRI(?object),
            IF(
              STRSTARTS(STR(?object), "http://www.wikidata.org/entity/"),
              wd:Entity,
              COALESCE(?oType, owl:Thing)
            ),
            IF(
              isLiteral(?object),
              COALESCE(datatype(?object), rdfs:Literal),
              UNDEF
            )
          ) AS ?range
        )
      }
    }
  }
}
⚠️ **GitHub.com Fallback** ⚠️