Create custom graph view over your RDF data

RDF is the most popular format for exchanging semantic data. Unlike, the logical database models the ontologies are optimised to represent the knowledge in a particular business domain correctly. This means that often their structure is verbose, includes abstract entities to express OWL axioms, contains implicit statements and complex N-ary relationship with provenance information. Graph View is a user interface optimised for mapping knowledge base models to simpler edge and vertex models configured by a list of SPARQL queries.

How it works?

In GraphDB 8.3 release, Graph View interface accepts four different SPARQL queries to retrieve data from the knowledge base:

  • Node expansion determines how new nodes and links are added to the visual graph when the user expands an existing node.
  • Node type, size and label control the node appearance. Types correspond to different colours. Each binding is optional.
  • Vertex (i.e. predicate) label determines where to read the name.
  • Node info controls all data visible for the resource displayed in tabular format. If ?image binding is found in the results the value is used as an image source.

By using these four queries, the user may override the default configuration and adapt the knowledge base visualisation to display:

  • Integrate custom ontology schema and what’s the preferred label;
  • Hide provenance or another meta-data related information;
  • Combine nodes, so you can skip relation objects and show them as a direct link;
  • Filter instances with all sorts of tools offered by the SPARQL language;
  • Generate RDF resources on the fly from existing literals.

World airport, airline and route data

OpenFlights Airports Database contains over 10,000 airports, train stations and ferry terminals spanning the globe. Airport base data was generated by from DAFIF (October 2006 cycle) and OurAirports, plus time zone information from EarthTools. All DST information added manually. Significant revisions and additions made by the users of OpenFlights. Airline data was extracted directly from Wikipedia’s gargantuan List of airlines. The dataset can easily link to DBPedia and integrated with the rest of linked open data cloud.

Data model

left to right direction

node "Airport" as AP
node "Airline" as AL
node "Route" as RT

RT --> AP : source
RT --> AP : destination
RT --> AL : airline

All OpenFlight CSV files are converted by using OntoRefine. Import the airports.ttl dataset which contains the data in RDF.

Configured queries

Find how airports are connected with flights

Lets find how are the airports connected by skipping the route relation and model a new relation hasFlightTo.

left to right direction

node "Airport" as AP
node "Airport" as RT

RT --> AP : hasFlightTo

In SPARQL this can be done with the following query:

PREFIX onto: <http://www.ontotext.com/>
construct {
  ?source onto:hasFlightTo ?destination .
}  where {
    ?flight <http://openflights.org/resource/route/sourceId> ?source .
    ?flight <http://openflights.org/resource/route/destinationId> ?destination
}

Using the new Visual button in the SPARQL editor we can now see the results of this query as a visual graph. But what if we want to save it and also expand more airports? Navigate to Explore -> Visual graph and click Create graph config.

First you are asked to select the initial state of your graph. For simplicity we choose to start with a query and enter from above. Now let’s make this graph expandable by configuring the Graph expansion query:

PREFIX onto: <http://www.ontotext.com/>
construct {
  ?node onto:hasFlightTo ?destination .
}  where {
    ?flight <http://openflights.org/resource/route/sourceId> ?node .
    ?flight <http://openflights.org/resource/route/destinationId> ?destination .
} limit 100

You may want to select each time a different airport to start from by making the starting point a search box.

Find which airlines fly to airports

The power of the visual graph is that on top of the same data we can create multiple Graph views. Let’s create a new one using the following query.

PREFIX onto: <http://www.ontotext.com/>
construct {
  ?airport onto:hasFlightFromWithAirline ?airline .
}  where {
    ?route <http://openflights.org/resource/route/sourceId> ?airport .
    ?route <http://openflights.org/resource/route/airlineId> ?airline .
} limit 100

And let’s create a visual graph with the following expand query:

# Note that ?node is the node you clicked and must be used in the query
PREFIX rank: <http://www.ontotext.com/owlim/RDFRank#>
PREFIX onto: <http://www.ontotext.com/>

CONSTRUCT {
    # The triples that will be added to the visual graph when you expand airports
    ?node onto:hasFlightFromWithAirline ?airline1 .
    ?node onto:hasFlightToWithAirline ?airline2 .

    # The triples to be added when you expand airlines
    ?airport1 onto:hasFlightFromWithAirline ?node .
    ?airport2 onto:hasFlightToWithAirline ?node .
} WHERE {
    {
        # Incoming flights for airport
        ?route <http://openflights.org/resource/route/sourceId> ?node .
        ?route <http://openflights.org/resource/route/airlineId> ?airline1 .

    } UNION {
        # Outgoing flights for airport
        ?route <http://openflights.org/resource/route/destinationId> ?node .
        ?route <http://openflights.org/resource/route/airlineId> ?airline2 .
    } UNION
    {
        # Incoming flights for airline
        ?route <http://openflights.org/resource/route/sourceId> ?airport1 .
        ?route <http://openflights.org/resource/route/airlineId> ?node .

    } UNION {
        # Outgoing flights for airline
        ?route <http://openflights.org/resource/route/destinationId> ?airport2 .
        ?route <http://openflights.org/resource/route/airlineId> ?node .
    }
}
../_images/devhub-visgraph-airlines-airports.png

Springer Nature SciGraph

SciGraph is a linked Open Data platform for the scholarly domain. The dataset aggregates data sources from Springer Nature and key partners from the scholarly domain. It collates information from across the research landscape, for example, funders, research projects, conferences, affiliations and publications.

Data model

This is the full data model...

../_images/scigraph-public-release-2017-02-15-latest.png

but let’s say we are only interested in articles, contributions and subjects.

left to right direction

node "Article" as ART
node "Contribution" as CN
node "Researcher (String)" as RS
node "Subject" as SBJ

ART --> CN : sg:hasContribution
CN --> RS : sg:publishedName
ART --> SBJ : sg:hasSubject

From this we can say that a researcher contributes to a subject and create a virtual URI for the researcher since it is a Literal.

left to right direction

node "Researcher" as RS
node "Subject" as SBJ

RS --> SBJ : onto:contributesTo

Find researchers that contribute to the same subjects

We don’t have a URI for a researcher. How can we search for researchers?

left to right direction

node "Contribution" as CN
node "Researcher (String)" as RS

CN --> RS : sg:publishedName

Navigate to Setup -> Autocomplete and add sg:publishedName predicate and as a result we will find contributions by given names in the search box.

Now let’s create the graph config. We need to configure expansion for contribution since this is our starting point, for subjects and for researchers.

PREFIX sg: <http://www.springernature.com/scigraph/ontologies/core/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX onto: <http://www.ontotext.com/>
PREFIX : <http://www.grid.ac/ontology/>
construct {
     ?node onto:publishedNameURI ?researcherNameUri1 .
     ?node onto:isContributorFor ?subject .
     ?researcherNameUri2 onto:isContributorFor ?node .
}
where {
    #BIND (onto:Declan_Butler as ?node)
    #BIND (<http://www.springernature.com/scigraph/things/subjects/policy> as ?node)

    {
        BIND( IRI(CONCAT("http://www.ontotext.com/", REPLACE(STR(?researcherName)," ","_"))) as ?researcherNameUri1)
        ?node sg:publishedName ?researcherName .
    } UNION {
        BIND( REPLACE(REPLACE(STR(?node),"_"," "), "http://www.ontotext.com/" , "") as ?researcherName)
        ?contribution a sg:Contribution .
        ?contribution sg:publishedName ?researcherName .
        ?article sg:hasContribution ?contribution .
        ?article sg:hasSubject ?subject .
    }
    UNION {
        BIND( IRI(CONCAT("http://www.ontotext.com/", REPLACE(STR(?researcherName)," ","_"))) as ?researcherNameUri2)
        ?contribution a sg:Contribution .
        ?contribution sg:publishedName ?researcherName .
        ?article sg:hasContribution ?contribution .
        ?article sg:hasSubject ?node .
    }
}

Okay. But not all researchers have contributions to articles with subjects. Let’s use an initial query that will fetch some researchers that have such relations. This is just a simplified version of the QUERY above to fetch some researchers and subjects.

PREFIX sg: <http://www.springernature.com/scigraph/ontologies/core/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX onto: <http://www.ontotext.com/>
PREFIX : <http://www.grid.ac/ontology/>
construct {
    ?researcherNameUri2 onto:isContriborFor ?node .
}
where {

 {
        BIND( IRI(CONCAT("http://www.ontotext.com/", REPLACE(STR(?researcherName)," ","_"))) as ?researcherNameUri2)
        ?contribution a sg:Contribution .
        ?contribution sg:publishedName ?researcherName .
        ?article sg:hasContribution ?contribution .
        ?article sg:hasSubject ?node .
    }
} limit 100

But the nodes in our graph are all the same since they don’t have RDF types. Now let’s configure how the types of the nodes are obtained.

PREFIX sesame: <http://www.openrdf.org/schema/sesame#>

SELECT distinct ?type  {
  #  BIND (<http://www.ontotext.com/S._R._Arnold> as ?node)
#    # Get node type
    OPTIONAL {?node ?p ?o}
    BIND(IF (strStarts(STR(?node), "http://www.ontotext.com/"), "Researcher", "Subject") as ?type)


} ORDER BY ?type

Cool. But what if I want to see additional data for each node, i.e which university has a researcher contribution for:

PREFIX sg: <http://www.springernature.com/scigraph/ontologies/core/>
SELECT distinct ?property ?value where {
#    BIND (<http://www.ontotext.com/Kevin_J._Gaston> as ?node)
    BIND (<http://www.ontotext.com/hasContributionIn> as ?property)
    BIND( REPLACE(REPLACE(STR(?node),"_"," "), "http://www.ontotext.com/" , "") as ?researcherName)
    optional {?node ?p ?o}
    ?contribution sg:publishedName ?researcherName .
    ?contribution sg:hasAffiliation ?affiliation .
    ?affiliation sg:publishedName ?value .
} limit 100
../_images/devhub-scigraph-result.png