Create custom graph view over your RDF data

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

How it works?

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 colors. 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 an ?image binding is found in the results, the value is used as an image source.

By using these four queries, you may override the default configuration and adapt the knowledge base visualization to:

  • Integrate custom ontology schema and the preferred label;

  • Hide provenance or another metadata 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

The 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 are added manually. Significant revisions and additions have been 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 be 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. To start exploring, first import the airports.ttl dataset which contains the data in RDF.

Configured queries

Find how airports are connected with flights

Let’s find out how the airports are 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 Visual button in the SPARQL editor, we can see the results of this query as a visual graph.

We can also save the graph and expand to more airports. To do this, 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 can also select a different airport to start from every time by making the starting point a search box.

Find which airlines fly to airports

The power of the visual graph is that we can create multiple Graph views on top of the same data. 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 domain. It collates information from across the research landscape, such as 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 do not 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 a sg:publishedName predicate. The retrieved result will be contributions by given names in the search box.

Now let’s create the graph config. We need to configure an expansion for contribution since this is our starting point for both subjects and 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 .
    }
}

However, 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 fetching 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 do not have RDF types. Now let’s configure the way 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

But what if we 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