Debugging Ontologies using OWL Reasoning, Part 3: robot explain

This is the 3rd part in a series. See part two.

In the first part of this series, I covered the use of disjointness axioms to make it easier to detect logical errors in your ontologies, and how you could use robot reason as part of an ontology release workflow to avoid accidentally releasing incoherent ontologies.

In the second part I covered unintentional inference of equivalence axioms – something that is not inherently incoherent, yet is usually unintended, and how to configure robot to catch these.

In both cases, the standard operating procedure was:

  • Detect the incoherency using robot
  • Diagnose the incoherency using the “explain” feature in Protege
  • Repair the problem my removing or changing offending axioms, either in your ontology (or if you are unlucky, the issue is upstream and you need to coordinate with the developer of an upstream ontology)

In practice, repairing these issues can be very hard. This is compounded if the ontology uses complex hard-to-mentally-reason-over OWL axioms involving deep nesting and unusual features, or if the ontology has ad-hoc axioms not conforming to design patterns. Sometimes even experienced ontology developers can be confounded by long complex chains of axioms in explanations.

But never fear! Help is at hand, there are many in the OBO community who can help! I always recommend making an issue in GitHub as soon as you detect an incoherency. However, you want to avoid having other people do the duplicative work of diagnosing the incoherency. They may need to clone your repo, fire up Protege, wait for the reasoner to sync, etc. You can help people help you by providing as much information up-front as possible.

Previously my recommendation was to paste a screenshot of the Protege explanation in the ticket. This helps a lot as often I can look at one of these and immediately tell what the problem is and how to fix it.

But this was highly imperfect. Screenshots are not searchable by the GitHub search interface, they are not accessible, and the individual classes in the screenshot are not hyperlinked.

A relatively new feature of robot is the explain command, which allows you to generate explanations without firing up Protege. Furthermore, you can generate explanations in markdown format, and if you paste this markdown directly into a ticket it will render beautifully, with all terms clickable!

A recent example was debugging an issue related to fog in ENVO. As someone who lives in the Bay Area, I have a lot of familiarity with fog.

The explanation is rendered as nested lists:

Both the relations (object properties) and classes are hyperlinked, so if you want to find out more about rime just click on it.

In this case the issue is caused by the use of  results in formation of where the subject is a material entity, whereas it is intended for processes. This was an example of a “cryptic incoherency”. It went undetected because the complete set of RO axioms were not imported into ENVO (I will cover imports and their challenges in a future post)

The robot explain command is quite flexible, as can be seen from the online help. I usually use it set to report all incoherencies (unsatisfiable classes plus inconsistencies). Sometimes if you have an unsatisfiable class high up in the hierarchy (or high up in the existential dependency graph) then all subclasses/dependent classes will be unsastifiable. In these cases it can help to hone in on the root cause, so the “mode” option can help here.

File:Golden Fog, San Francisco.jpg - Wikimedia Commons

Edge properties, part 2: singleton property pattern (and why it doesn’t work)

In the first post in this series on edge properties, I outlined the common reification pattern for placing information on edges in RDF and knowledge graphs, and how this places nicely with RDFStar (formerly RDF*).

There are alternatives to reification/RDF* for placing information on edges with the context of RDF, in this post I will deal with one, the Singleton Property Pattern (SPP), described in Don’t Like RDF Reification? Making Statements about Statements Using Singleton Property (2015), Nguyen et al (PMC4350149).

The idea here is to mint a new property URI for every statement we wish to talk about. Given a triple S P O, we would rewrite as S new(P) O, and add a triple new(P) singlePropertyOf P.

So given the example in the previous post:

Using SPP we would have the following 3 triples:

  • :P1 :interacts_with_001 :P2
  • :interacts_with_001 singletonPropertyOf :interacts_with
  • :interacts_with_001 :supported_by :pmid123

To find all interacts-with associations, we could write a SPARQL query such as:

SELECT ?x ?y WHERE { ?x ?p ?y . ?p singletonPropertyOf :interacts_with }

Some of the proposed advantages of this scheme are discussed in the paper.

A variant of the SPP makes the new property a subPropertyOf the original property. I will call this SPP(sub). This has the advantage that the original statement is still entailed.

  • :P1 :interacts_with_001 :P2
  • :interacts_with_001 rdfs:subPropertyOf :interacts_with
  • :interacts_with_001 :supported_by :pmid123

Then if we assume RDFS entailment, the query becomes simpler:

SELECT ?x ?y WHERE { ?x :interacts_with ?y }

This is because the direct interacts_with triple is entailed due to the subPropertyOf axiom.

In the discussion section of the original paper the authors state that the pattern is compatible with OWL, but don’t provide examples or elucidation, or what is meant by compatible. There is a website that includes an OWL example.

Unfortunately, problems arise if we want to use this same pattern with other axiom types, beyond OWL Object Property Assertions; for example, SubClassOf, EquivalentClasses, SameAs. This is true for both the original SPP and the subPropertyOf variant form.

These problems arise when working in OWL2-DL. Use of OWL2-Full may eliminate these problems, but most OWL tooling and stacks are built on OWL2-DL, so it is important to be aware of the consequences.

OWL-DL is incompatible with the SPP

Unfortunately the SPP pattern only works if the property used in the statement is an actual OWL property.

In the official OWL2 mapping to RDF, predicates such as owl:equivalentClass, owl:sameAs, owl:subClassOf are syntax for constructing an OWL axiom of the corresponding type (respectively EquivalentClasses, SameIndividual and SubClassOf). These axiom types have no corresponding properties at the OWL-DL level.

For example, consider the case where we want to make an equivalence statement between two classes, and then talk about that statement using the SPP pattern. 

We do this by making a fresh property (here, arbitrarily called equivalentClass-1) that is the SPP form of owl:equivalentClass. For comparison purposes, we make a normal equivalence axiom between P1 and P2, and we also try an equivalence axiom between P3 and P4 using the SPP(sub) pattern: 

PREFIX rdf: <>
PREFIX rdfs: <>
PREFIX owl: <>

:P1 a owl:Class .
:P2 a owl:Class .
:P3 a owl:Class .
:P4 a owl:Class .

:P1 owl:equivalentClass :P2 .
:P3 :equivalentClass-1 :P4 .
:equivalentClass-1 rdfs:subPropertyOf owl:equivalentClass .

Note that this does not have the intended entailments. We can see this by doing a DL query in Protege. Here we use HermiT but other DL reasoners exhibit the same features.

For the normal equivalence axiom, we get expected entailments (namely that P2 is equivalent to P1):

However, we do not get the intended entailment that P3 is equivalent to P4

We can get more of a clue as to what is going on by converting the above turtle to OWL functional notation, which makes the DL assertions more explicit:



SubAnnotationPropertyOf(:equivalentClass-1 owl:equivalentClass)
EquivalentClasses(:P1 :P2)
AnnotationAssertion(:equivalentClass-1 :P3 :P4)

Note that the SPP-ized equivalence axiom has been translated into an owl annotation assertion, which has no logical semantics. However, even if we force the SPP property to be an object property, we still lack the required entailments. In both cases, we induce owl:equivalentClass to be an annotation property, when in fact it is not a property at all in OWL-DL.

The SPP(e) pattern may work provide the intended entailments when using OWL-Full, but this remains to be tested.

Even if this is the case, for pragmatic purposes most of the reasoners in use in the life science ontologies realm are OWL2-DL or a sub-profile like EL++ or RL (e.g. Elk, HermiT).

Use of SPP with plain RDF

If you are only concerned with plain RDF and not OWL, then the above may not be a concern for you. If SPP’s work for your use case, go ahead. But bear in mind that this pattern is not as widely used, and in addition to OWL issues, there may be other reasons to avoid – for example, proliferating the number of properties in your graph may confuse humans and break certain built in assumptions made by some tools. Overall my recommendation would be to avoid the SPP regardless of your use case.

It’s unfortunate that something as basic as placing information on an edge leads to such a proliferation of de-facto standards in the RDF world. I think this is one reason why graph databases such as Neo4J have the edge – they make this much easier, and they don’t force poor users to mentally reason over confusing combinations of W3C specifications and understand esoteric things such as the difference between OWL-DL and OWL-Full.

Hopefully RDFStar will solve some of these issues.

How to select and request terms from ontologies


Ontologies, knowledge models, and other kinds of standards are generally not static artefacts. They are created to serve a community, which likely includes you, and they should respond dynamically to serve that community, where resources allow.

The content of many ontologies in OBO such as the Gene Ontology are driven by their respective curator communities. Ontology editors make terms and whole ontology branches prospectively in anticipation of needs, but they also make terms and changes in response to curator needs. New terms can also be requested by data modelers, data engineers, and data scientists, for example, to map categorical data in a dataset in order to allow harmonization and cleaning of data. In many cases, the terms may exist already, they may be hard to find, or they may be spread across a distribution of ontologies, and this may be confusing, especially if you are not familiar with the area.

I wrote this guide primarily with the data engineer audience in mind, as this community may be less familiar with norms and tacit knowledge around the ontology development lifecycle. However, much of what I say is applicable to curators as well. I also wrote this document originally for members of my group, who are expected to contribute back to OBO and the work of ontology developers. Some of the recommendations may therefore seem a little onerous in places, but they should still hopefully be useful and adaptable to a broader audience. And in all cases, for open community ontologies, it is worth bearing in mind the maxim that ‘you get out what you put in’.

User stories

  • As a curator (e.g BgeeDb), I want a new anatomy term, to curate expression for a gene
  • As a data scientist, I need terms describing oxygen-requirement traits, so I can combine tabular microbial trait data to predict traits from other features
    • Alternate scenario: building a microbial Knowledge Graph (see this issue)
  • As a database developer, I need terms for sequence variants, so I can map categorical values in my database making it FAIR
  • As a knowledge graph builder, I need relations from the Relation Ontology or Biolink, so I can standardize edge labels in my graph
  • As a GO ontology developer, I need terms from the cell ontology, so I can provide logical defining axioms for terms in the cell differentiation branch
  • As a microbiome scientist, I need terms from ENVO/PO, so I can fill in MIxS-compliant environmental fields when I submit my sample data, making it FAIR
  • As an environmental genomics standards provider, I need terms from ENVO, so I can map enumerated values/dropdowns to an ontology when developing the MIxS standard
  • As a data modeler / standards provider, I need SO terms for genomic feature types, to define a value set for a genomics exchange format (e.g. GFF)
  • As a schema developer, I need terms for describing properties of sequence assemblies, e.g. number of aligned reads, N50, in order to make my sequencing schema FAIR

These scenarios encompass a range of different kinds of person with varying levels of expertise and commitment. The primary audience for this document is members of my group and the projects we are involved with (GO, Monarch, NMDC, Translator) but many of the recommendations will apply more broadly. But we would not expect the average scientist who is submitting a dataset to engage at the same level through GitHub etc (see the end of the document for discussion on approaches for making the overall process easier). 

20ish simple rules for selecting and requesting ontology terms

Be a good open science citizen

The work you are doing is part of a larger open science project, and you should have a community minded attribute.

When you request terms from ontologies and you provide information to help you should be microcredited, e.g. your orcid will be associated with the term. Remember that many efforts are voluntary or unfunded, and people are not necessarily paid to help you. Provide help where you can, provide context when making requests, and any background explicit or tacit knowledge that may help.

Always be respectful and appreciative when interacting with providers of terms or other curators. Follow codes of conduct. 

Use the appropriate ontology or standard: avoid pick-and-mix

Depending on the context of your project, there may be mandated or recommended standards or ontologies. These may be explicit or implicit.

If you are performing curation, it is likely that the ontology you use is fixed by your curation best practices and even your tools. For example, GO curators (obviously) use GO. But for other purposes it may not be obvious which ontology to use (and even with GO, curators have a choice of ontologies for providing additional context as extensions or in GO-CAMs). There are a large number of them, with confusing overlaps, and lots of tacit community knowledge that may not be immediately available to you.

Some general guidelines:

  • Look in the appropriate place, depending on what kind of term you need
    • If you need a classification term or a descriptor, then use an ontology
    • If you need something like a gene or a variant “term” then an ontology may not be appropriate, use the appropriate database instead, with caveats
    • If you need a property to describe a piece of data, then you may need to look in existing semantics schemas, e.g. schemas encoded in RDFS, a shape language such as ShEx, or LinkML
  • When looking for an ontology term, favor OBO over non-OBO resources
    • Sometimes better coverage is only available outside OBO – e.g. EDAM has a lot more terms for describing bioinformatics software artefacts, and EDAM is not in OBO. But it is still good to engage owners of the appropriate OBO ontology
    • When a non-OBO ontology is selected, use the OBO principles and guidelines to help evaluation – e.g is the ontology open? Does it follow good identifier lifecycle management?
    • The OLS uses a broader selection of ontologies that is narrower than what is in Bioportal. In my experience the non-OBO ontologies they include are quite pragmatic choices in many situations, e.g EDAM.
  • Even within OBO, there may still be confusion as to which ontologies to use, especially when many seem to have overlapping concepts, and scope may be poorly defined.
    • An example is the term used to describe an organism’s core metabolism for our microbial knowledge graph KG-Microbe, with multiple OBO contenders.
    • Always consult to glean information about the ontology. This is always the canonical unbiased source, and includes curated up-to-date metadata
    • A crucial piece of metadata that is in OBO is the ontology status – you must avoid using ontologies that are obsoleted, and you should avoid using ontologies that are marked inactive
    • Look at the ‘usages’ field in OBO. Has the ontology been used for similar purposes as what you intend? If the ontology has no usages, this is a worrying sign the ontology was made for ontologists rather than practical data annotators such as yourself (but note that some ontologies may be behind in curating their usages into OBO)
    • Look at the scope of the ontology, as defined on the OBO page. Is it well defined and clear? If not, consider avoiding. Is your term in scope for this ontology? If not then don’t use terms from the ontology just because the labels match.
    • Is the ontology an application ontology, i.e. an ontology that is not intended to be a reference for terms within a domain? If so it may not be fit for your intended use.
    • Consult others if in doubt. Many people in the group or in our funded projects are involved with specific ontologies.
    • You should be on the OBO slack, this is a good place to get advice.
    • Favor ontologies we are actively involved with or that follow similar data models and principles
    • Favor more active ontologies. OBO marks inactive ontologies with metadata tags that are clearly displayed, but you should still check
      • Is the github project active?
      • Are there many tickets that are never answered?
      • If you suspect an ontology is not active but it is not marked as such, be a good citizen and raise this on the OBO tracker
    • Use precedence – see what has been done previously in similar projects
    • We are actively working on projects like OBO Dashboard and on improving OBO metadata to help ontology selection
  • For any candidate term
    • Is it obsoleted? If so avoid, but look at the metadata for replacements
    • Does it have a definition? A core OBO principle is that reasonable attempts must be made to define terms in an ontology
    • Is there a taxonomic scope? Always use the appropriate taxonomic scope. If an uberon term is restricted to vertebrates, it is valid to use for humans. But if an ontology or term is designed for use with mouse, it may not be valid to apply terms for humans
    • Have others used the term?
    • If you have formal ontology training, avoid over-ontologizing in your thought processes for selection. See for example the section below on shadow terms.
    • Avoid terms that seem over-ontologized; e.g. that have strange labels a domain scientist would not understand
  • If you are looking for terms to categorize nodes or edges in a Knowledge Graph:
    • For most of our projects, KGs should conform to the biolink-model, so this is the appropriate place to search
    • Note that biolink still leverages OBO and standard bioinformatics databases for the nodes themselves; biolink classes and predicates are used for the node categories and edge labels
  • For environmental samples use GSC MIxS terms for column headers
    • Use ENVO for describing the environment

Figure: The OBO site provides up to date metadata for its ontologies. An example of an ontology marked deprecated, with the suggested replacement. Note in this case this ontology was not deprecated due to quality issues, instead the developers worked with a different ontology to incorporate their work, and provided new IDs for all their existing classes.

The biolink model will serve as a canonical guide for what kinds of IDs should be used for any kind of entity. The SOP is to find the category of relevance in biolink, and then examine the id_prefixes field. This indicates the resources that provide identifiers that are valid to use for that entity type, in priority order.

For example, for BiologicalProcess you will see on the page and in the yaml


      – GO

      – REACT

      – MetaCyc

      – KEGG.MODULE ## M number

Figure: portion of Biolink page for the data class BiologicalProcess. The favored ID prefixes are shown

This means that GO is always our favored ontology / ID space for representing a biological process. This followed by reactome, then metacyc, then kegg. Of course, GO and Reactome serve different purposes, with reactome pathway IDs classified using GO IDs. If you disagree with this ordering you can make a PR on biolink (or you can also make a project-specific extensions/contraction of biolink).

Avoid a pick-and-mix approach. It is better to draw like terms from the same ontology, this ensures overall coherence, and allows reasoning to be better leveraged.

If you are creating a LinkML enum, a good rule of thumb is that all ‘meaning’ annotations should come from the same ontology. Of course, this may not always be the case.

For example, the enum for sex_chromosome_type in chromo is all drawn from GO:


    description: >-

      what type of sex chromosome



        meaning: GO:0000805


        meaning: GO:0000806


        meaning: GO:0000804


        meaning: GO:0000807

Similarly for the gp2term relationship field in GPAD, these are all drawn from RO:

(note that part_of, BFO:0000050, is actually in RO, not BFO, despite the ID space)

However, entity type is drawn from SO, GO, and PR. 

It is a bad smell to have a mix of different ontologies for what should be a set of similar entities, e.g


    ## TODO: the mappings below are automated



        description: anaerobic


      strictly anaerobic:

        description: strictly anaerobic


      obligate aerobic:

        description: obligate aerobic



        description: aerobic



        description: facultative



        description: microaerophilic


      obligate anaerobic:

        description: obligate anaerobic


Some ontologies are themselves ad-hoc in their scoping, which can make it harder to determine which ontologies to go to find terms or request terms. Always favor ontologies with clear scope. We are actively working to fix scope problems in OBO:

Avoid shadow terms

Many ontologies mint “shadow concepts”. For example OBA may have the core concept of “blood pressure”. Another ontology many have a random mix of “datum” or “measurement” classes, e.g. “blood pressure datum”. Avoid these terms. Even if you want to describe a blood pressure measurement, just use the core concept. The fact that the concept is deployed in the context of a measurement should be communicated externally, e.g. in the data model you are using, not by precoordination. 

By using the core concept you increase the overall coherency and connectivity of the information you are describing. Many shadow terms are in ‘application ontologies’ and are not properly linked to the core concepts.

Note that my own recommendations may not be aligned with the broader OBO community – see this ticket for further discussion.

Exercise due diligence in looking for the terms

Make sure the concept you need is definitely not present in the ontology before requesting. 

Learn how to use ontology search tools appropriately. I recommend:

  • OLS for OBO and selected other ontologies
  • Bioportal for searching the broadest set of ontologies

Bioportal has the broadest collection (including all of OBO), but there is less of a filter. Ontologies may not be open. However, being in OBO is not a guarantee of quality, and there may be good reasons to use a non OBO ontology.

Expert ontologists may like to use Ontobee, but there are many things to be aware of before using it:

  • The update frequency is less than OLS
  • It does not display the partonomy, which is crucial for understanding many of the ontologies we work on
  • Overall it presents a more ‘close to the base metal’ OWL model. This is fine for ontologists, but it is better not to point biologists here

If you are not experienced with ontologies and in particular OBO, there are many things that potentially trip you up. Don’t be afraid to ask about these — many people in the same shoes have you have been confused.

Potential confusion point: Some ontologies import other ontologies, or parts of other ontologies

This means e.g. if you are searching for a chemical element like ‘nitrate’ you may find results “in” ENVO, because ENVO imports a portion of CHEBI.

Bioportal does a good job of separating out the core concept/IRI from imports of it:

In these cases, the ID is the same, but you should be aware what the true parent ontology is.

OLS also does a good job of collapsing these:


Potential confusion point: Some ontologies replicate parts of other ontologies

This is distinct from the import case above. In this case, one ontology may intentionally or unintentionally duplicate concepts from another. For example, the OMIT ontology copies large amounts of MESH and gives these new IDs. In these cases you should identify the authority and use the ID from there.

For example, a search for cockatoos in Bioportal shows MESH, MESH IDs reused elsewhere, as unlinked concept IDs presumably showing the same concept.

Searching semantic web schemas

For searching for terms in semantic web standards, is probably the best

Search tips

Note that sometimes you need to do more work than just entering a string. Most ontology search tools won’t do stemming etc. I recommend searching for similar concepts and exploring the neighborhood. Understanding the structure of the ontology will help you make a better request.

For example, imagine you are looking for a concept ‘bicycle’ in a product ontology. Just because nothing comes back in a search for ‘bicycle’ doesn’t mean the concept isn’t there. It may be under a synonym  like ‘bike’. Explore the ontology. Look for similar concepts like unicycle or car. If you see that the ontology has a class vehicle, subclasses like 4-wheeled, 2-wheeled, and 1-wheeled, but doesn’t have anything under 2-wheeled you can be confident the concept is missing.

Don’t get too hung up on this if you are not a domain scientist and don’t understand the concepts in the ontology, but it is usually a good idea to do this kind of initial exploration.

Mapping or searching for sets of terms

If you have a set of terms to map and you want to get a sense of coverage in different ontologies the parallel tools are:

  • Zooma
  • Bioportal annotator

This topic is deserving of its own post, so I won’t go into more detail here

Use GitHub for making requests

Make sure to consult the group best practice document on GitHub and the group GitHub overview

If you are sure the ontology doesn’t have the concept you need, you will want to make a request

In general, always use GitHub for making the request. If you know the email or slack of someone with ability to make terms it may be tempted to contact them directly but it’s better to use GitHub. This makes the process transparent, and you will be helping people who come after you.

If you cannot find a GitHub repo for the ontology/standard, this is a bad smell and maybe you should reconsider whether you want to use this ontology. Having a public repo (GitHub/GitLab/Bitbucket/etc) is a requirement of OBO. Note this same advice applies to software.

For OBO ontologies, you can easily find the GitHub issue tracker for any ontology via 

For some ontologies, there may be specialized term request systems (PRO, CHEBI). Go by the norms of the particular ontology, but my own preference is always to use GitHub, for the reasons stated above.

Search existing issues before making a request. It may be the case that others have requested the same term before you. Maybe it is out of scope, and the term is in a different ontology. Searching the issue tracker should reveal this (this is why it is good to always stay within github when making requests rather than private communication). It may be the case that the ontology refuses to grant requests for reasons that are arbitrary. In this case there may be a issue discussing the pros and cons. Read this and add your voice, but in a constructive fashion. Maybe a simple up-vote is sufficient. Or a comment like “similar to Mary, I also would find a term “Hawaiian pizza” very valuable”.

Always link the issue that you are working on to the term request. In GitHub, this is simply a matter of putting the URL in. You can either link from the request issue back to the parent issue, or from the parent issue to the request. 

(Note you will always be working to a issue. If you’re not, stop what you are doing and make one!)

You should also search the issue tracker to see if others have made the same requestavoid making duplicate issues. But you can still comment on existing ones. However, avoid tacking on or extending the scope of an existing issue. If there is a similar issue but your request is different, link to the current issue (#NUMBER – you should know github conventions), e.g. “My request is similar to fred’s in #1234, but I need a foo not a bar”.

Read the file

An increasing number of ontologies and other modeling artefacts include this in their repo. It should include guidance for people like you that is more specialized than this generalized guide. Read it!

Provide as much help as possible in your request

Remember, many ontologies are under-funded and requests are often fulfilled by our collaborators. Provide as much help as possible to them. If you are not knowledgeable about the domain, that is OK, but you can still provide context about your project.

e.g. “hey, I have been asked to provide a UI selection box with different pizza types. My boss gave me this list of ten pizza types but I don’t eat pizza, and I’m not sure how to map them to your ontology, and I may have some duplicates, it looks like you don’t have ‘Hawaiian’, but I’m wondering if maybe this ‘pineapple and ham’ is the same thing, or is there some subtle difference? If it’s the same, shouldn’t there be a synonym added?

If you have been given a spreadsheet, you can provide a link to it. If you are mapping a data table, provide a link, or selected examples, as this can help orient the person fulfilling the request. Remember, people aren’t mind readers.

For example, making a ticket where you say “I need you to add HSap” is not helpful. But if you can say the HSap value appears in a column called species, and the other values are MMus, ‘DMel’, this gives the ontology developer the context they need, avoiding the need for confusing back and fortheon the issue tracker.

Analogies are useful: If you can find analogous terms use these as examples.

If you have a domain scientist handy, you may want to engage them before making requests – e.g. if they can provide definitions. 

There is no rule as to whether to make one ticket/issue with multiple terms, or one ticket per term. If you think each term is nuanced and requires individual discussion, make separate tickets. If you are unsure then make an initial exploratory ticket. It’s usually OK to make a ticket for a question (GitHub even has a category/label for this).

Avoid making 100 requests only to discover that all of your requests are out of scope, requiring tedious closing of multiple tickets.

Be proactive and make pull requests

Even ontologies that have dedicated funding are under-resourced. You can help a lot by offering to make pull requests. If the ontology is a well-behaved OBO ontology there should be a clear procedure for doing this (if the ontology was made with ODK or follows ODK conventions, the file you should edit is src/ontology/foo-edit.owl in the repo).

Note that editing the OWL file usually entails using Protege. Basic Protege skills are worth learning. Normally this would not be required of most users, but in my group having basic Protege driving skills is useful and strongly encouraged

In some cases you don’t need to edit the file – the ontology SOP may dictate editing a TSV in github or google sheet, with this compiled to OWL. Consult the contributor docs for that ontology (and if these are lacking, gently suggest ways to improve this to make it easier for those who come after you to contribute).

You will likely need to be added to an idranges file – again if the ontology follows standard conventions this will be obvious.

It is a good idea to check if an ontology is welcoming of PRs. This should be obvious from the pulls tab in GitHub. In general most ontologies should be, but some ontology groups may have trouble adapting to the times and may still be unfamiliar and may prefer issues. Also in many cases the addition of terms is best done by an expert.

In all cases, use your best judgment!

Follow templates where possible

Many repos are set up with GitHub issue templates. If the repo you are requesting in does not, you may want to gently suggest they do (or better yet, make a PR for this, using ODK as a guide). If you are reading this document then you likely have more github-foo than the ontologist/curator fulfilling the request, you can be helpful!

In some cases, ontologies may have set up a templating system (robot or dosdp). You can be super-helpful and follow the system that has been set up. In some cases this means filling in a predefined google sheet (e.g. with columns for name, definition, parent). In some cases you can make a PR on a TSV in the repo. This is an evolving area, so stay tuned. If the process is not clear there are people in the group with expertise who can help.

If all else fails, make your own ‘application ontology’

Sometimes there may simply be no ontology fit for purpose. Or existing ontologies may simply be unable to fulfil your request. It may be the case that there is an ontology called ‘pizza ontology’ squatting this conceptal space in OBO, but they may fail to grant your term requests for arbitrary reasons (“we don’t add Hawaiian pizzas, as we object in principle to putting pineapple on pizza”), or have unrealistic timelines (“we have a pizza modeling discussion set for 2 years now at the annual pizza ontology conference, we may consider putting your request before the committee then, but it is unlikely to be ratified for 4 years“). They may make it impossible to add terms by being ontological perfectionist (“we will add your pizza if you add perfect OWL logical axiomatization describing topological and gastronomic properties of the pizza according to our undocumented design practice”). They may also simply model things incorrectly (“thanks for your request. We have added ‘Hawaiin Pizza’ as a subclass of ‘Hawaii’. Aloha!”)

In general this won’t happen, especially with well-behaved OBOs, but there may be some holdouts!  Be patient, and offer to make PRs (see above).

In some cases, such as those above, you may be justified in making your own ontology, using tools like ODK and ROBOT. Consult first! And never do this without first making requests.

In some cases you don’t need to make a new ontology, you can just create stubs. E.g. for a KG ingest, you can ‘inject’ something into the biolink-model, e.g. biolink:Pizza. There are various downsides to the injection approach, it may be better to use a different namespace. Depending on the project context it may or may not matter if the injected type resolves. Regardless, when doing this, add a comment to your code with a link to the ticket

Be bold and be collaborative

Whether you are making or fulfilling a request, you are all part of the same larger community of people working to make data more computable. Be as constructive and as helpful as possible, but also don’t hold back or be shy. Ultimately the ontology is there to serve you. But if it does not serve your need, is too confusing in some aspect, then it’s likely the same case for others. 


Overall the processes described above may seem overly complex or onerous. In fact they are not so different from analogous processes such as getting features into a piece of open source software.

Over the years there have been various proposals and implementations of ‘term brokers’ which act as both triage and a place to get an identifier for a term instantly. An example implementation is TermGenie

One reason why term brokers have not taken over as a way of getting terms into ontologies over the github procedure above is that there is a strong tendency to accumulate ontological debt (akin to technical debt). It’s easy to stick a bunch of junk terms into an ontology. But maintaining these and dealing with the downstream costs of including these can be very high.

This topic needs a blog post all of its own, stay tuned…

Avoid mixing parthood with cardinality constraints

We frequently have situations where we want to make an assertion combining parthood and cardinality. Here, cardinality pertains to the number of instances.

Section 5.3 of the OWL2 primer has an example of a cardinality restriction,

Individual: John
   Types: hasChild max 4 Parent

This is saying that John has at most 4 children that are parents.

A more natural biological example of a cardinality restriction is stating something like:

Class: Hand
   SubClassOf: hasPart exactly 5 Finger

i.e. every hand has exactly 5 fingers. Remember we are following the open world assumption here – we are not saying that our ontology has to list all 5 fingers. We are stating that in our model of the world, any instance of a hand h entails the existence of 5 distinct finger instances f1…f5, each of which is related to that hand, i.e. fn part-of h. Furthermore there are no other finger instances not in the set f1..5 that are part of h.

The precise set-theoretic semantics and provided in the OWL2 Direct Semantics specification.

This cardinality axiom seems like a perfectly natural, reasonable, and useful thing to add to an ontology (avoiding for now discussions about “canonical hands” and “variant hands”, for example in cases like polydactyly; let’s just assume we are describing “canonical anatomy”, whatever that is).

5 Kids Hand Showing The Number Five Hand Sign Stock Illustration - Download  Image Now - iStock
A canonical hand, with 5 fingers

And in fact there are various ontologies in OBO that do this kind of thing.

However, there is a trap here. If you try and run a reasoner such as HermiT you will get a frankly perplexing and unhelpful error such as this.

An error occurred during reasoning: Non-simple property 'BFO_0000051' or its inverse appears in the cardinality restriction 'BFO_0000051 exactly 5 UBERON_1234567

If you have a background in computer science and you have some time to spare you can go and look at section 11 of the OWL specification (global restrictions on axioms in OWL2 DL) to see what the magical special laws you must adhere to when writing OWL ontologies that conform to the DL profile, but it’s not particularly helpful to understand:

  • why you aren’t allowed to write this kind of thing, and
  • what the solution is.

Why can’t I say that?

A full explanation is outside the scope of this article, but the basic problem arises when combining transitive properties such as part-of with cardinality constraints. It makes the ontology fall outside the “DL” profile, which means that reasoners such as HermiT can’t use it, so rather ignore it HermiT will complain and refuse to reason.

Well I want to say that anyway, what happens if I do?

You may choose to assert the axiom anyway – after all, it may feel useful for documentation purposes, and people can ignore it if they don’t want it, right? That seems OK to me, but I don’t make the rules.

Even if you don’t intend to stray outside DL, an insidious problem arises here: many OBO ontologies use Elk as their reasoner, and Elk will happily ignore these DL violations (as well as anything it can’t reason over, outside it’s variant of the EL++ profile). This in itself is totally fine – its inferences are sound/correct, they just might not be complete. However, we have a problem if an ontology includes these DL violations, and the relevant portion of that ontology is extracted and then used as part of another ontology with a DL reasoner such as HermiT that fails fast when presented with these axioms. In most pipelines, if an ontology can’t be reasoned, it can’t be released, and everything is gummed up until an OWL expert can be summoned to diagnose and fix the problem. Things get worse if an ontology that is an N-th order import has a DL violation, as it may require waiting for all imports in the chain to be re-released. Not good!

Every now and then this happens with an OBO ontology and things get gummed up, and people naturally ask the usual questions, why did this happen, why can’t I say this perfectly reasonable thing, how do I fix this, hence this article.

How do we stop people from saying that?

Previously we didn’t have a good system for stopping people from making these assertions in their ontologies, and the assertions would leak via imports and imports of imports, and gum things up.

Now we have the wonderful robot tool and the relatively new validate-profile command, which can be run like this:

robot validate-profile --profile DL \
  --input my-ontology.owl \
  --output validation.txt

This will ensure that the ontology is in the DL profile. If it isn’t, this will fail, so you can add this to your Makefile in order to fail fast and avoid poisoning downstream ontologies.

This check will soon be integrated into the standard ODK setup.

OK, so how do I fix these?

So you have inadvertently strayed outside the DL profile and your ontology is full of has-parts with cardinality constraints – you didn’t mean it! You were only alerted when a poor downstream ontology imported your axioms and tried to use a DL reasoner. So what do you do?

In all honesty, my advice to you is ditch that axiom. Toss it in the bin. Can it. Flush that axiom down the toilet. Go on. It won’t be missed. It was already being ignored. I guarantee it wasn’t doing any real work for you (here work == entailments). And I guarantee your users won’t miss it.

A piece of advice often given to aspiring writers is to kill your darlings, i.e. get rid of your most precious and especially self-indulgent passages for the greater good of your literary work. The same applies here. Most complex OWL axioms are self-indulgences.

Even if you think you have a really good use case for having these axioms, such as representing stoichiometry of protein complexes or reaction participants, the chances are that OWL is actually a bad framework for the kind of inference you need, and you should be using some kind of closed-world reasoning system, e.g. one based on datalog.

OK, so maybe you don’t believe me, and you really want to say something that approximates your parts-with-numbers. Well, you can certainly weaken your cardinality restriction to an existential restriction (provided the minimum cardinality is above zero; for maxCardinality of zero you can use a ComplementOf). So in the anatomical example we could say

Class: Hand
   SubClassOf: hasPart some Finger

This is still perfectly sound – it is not as complete as your previous statement, but does that matter? What entailments were you expecting from the cardinality axiom. If this is intended more for humans, you can simply annotate your axiom with a comment indicating that humans typically have 5 fingers.

OK, so you still find this unsatisfactory. You really want to include a cardinality assertion, dammit! Fine, you can have one, but you won’t like it. We reluctantly added a sub-property of has-part to RO called ‘has component’:

In all honesty the definition for this relation is not so great. Picking holes in it is not so hard. It exists purely to get around this somewhat ridiculous constraint, and for you to be able to express your precious cardinality constraint, like this:

Class: Hand
   SubClassOf: hasComponent exactly 5 Finger

So how does this get around the constraint? Simple: hasComponent is not declared transitive. (recall that transitivity is not inferred down a property hierarchy). Also it is a different relation (a subproperty) from has-part, so you might not get the inferences you expect. For example, this does NOT prevent me from making an instance of hand that has as parts 6 distinct fingers – it only applies to the more specific relation, which we have not asserted, and is not inferred.

You can make an argument that this is worse than useless – it gives no useful entailments, and it confuses people to boot. I am responsible for creating this relation, and I have used it in ontologies like Uberon, but I now think this was a mistake.

Other approaches

There are other approaches. For a fixed set of cardinalities you could create subproperties, e.g. has-1-part-of, has-2-parts-of, etc. But these would still be less expressive than you would like, and would confuse people.

A pattern that does work in certain cases such as providing logical definitions for things like cells by number of nuclei is to use the EL-shunt pattern (to be covered in a future article) and make characteristic classes in an ontology like PATO.

While this still isn’t as expressive, it allows you to use proxies for cardinality in logical definitions (which do actual work for you), and shunt off the cardinality reasoning to a smaller ontology — where really it’s actually fine to just assert the hierarchy.

But this doesn’t work in all cases. There is no point making characteristics/qualities if they are not reused. It would be silly to do this with the hand example (e.g. making a has5fingers quality).

Isn’t this all a bit annoying?

Yes, it is. In my mind we should be free to state whatever axioms we need for our own use cases, expressivity be damned. I should be able to go outside DL, in fact to use anything from FOL or even beyond. We should not be condemned to live in fear of stepping outside of decidability (which sounds like something you want, but in practice is not useful). There are plenty of good strategies for employing a hybrid reasoning strategy, and in any case, we never use all of DL for most large OBO ontologies anyway.

But we have the technology we do, and we have to live with it for now.


  • don’t mix parthood and cardinality
  • you probably won’t miss that cardinality restriction anyway
  • no really, you won’t
  • use robot to check your profiles

Aligning Design Patterns across Multiple Ontologies in the Life Sciences

I was delighted to give the keynote at http://ISWC 2020 Workshop on Ontology Design and Patterns today. You can see a video or my slides, I’m including a brief summary here.

Opening slide: Aligning Design Patterns Across Multiple Ontologies in the Life Sciences

As this was a CS audience that may be unfamiliar with some of the issues we are tackling in OBO I framed this in terms of the massive number of named entities in the life sciences, all of which have to be categorized if we are to be able to find, integrated, and analyze data:

there are many named things in the life sciences

We created OBO to help organize and integrate the ontologies used to categorize these things

OBO: social and technological framework to categorize all the things

When we started, many ontologies were quite ‘SKOS-like’ in their nature, with simple axiomatization, and a lack of integration:

GO and other ontologies were originally SKOS-like

OWL gives us a framework for more modular development, leveraging other ontologies, and using reasoning to automate classification:

OWL reasoning can be used to maximize leverage in a modular approach: here re-using CHEBI’s chemical classification in GO

This is all great, but when I look at many ontologies I often see two problems, often in the same ontology, under- and over- axiomatization:

Finding the balance between under and over axiomatization

In some ontologies I see what I sometimes call ‘Rococo OWL’, over-axiomatization in an elaborate dense set of axioms that looks impressive but don’t deliver much functional utility (I plan to write about this in a future post).

Rococo: an exceptionally ornamental and theatrical style of architecture, art and decoration which combines asymmetry, scrolling curves, gilding, white and pastel colors, sculpted molding, and trompe l’oeil frescoes to create surprise and the illusion of motion and drama. The style was highly theatrical, designed to impress and awe at first sight. a movement that extolled frivolity, luxury and dilettantism, patronised by a corrupt and decadent ancien régime. Rococo ended in the revolution of 1789, with the bloody end of a political and economic system

We developed Dead Simple OWL Design Patterns (DOSDPs) to make it easier to write down and reuse common OWL patterns of writing definitions, primarily for compositional classes following the Rector Normalization pattern.

Example DOSDP yaml file

I gave an example of how we used DOSDPs to align logical definitions across multiple phenotype ontologies (the uPheno reconciliation project). I would like to expand on this in a future post.

multiple phenotype databases for humans and model organisms, and their respective vocabularies/ontologies

I finished with some open-ended questions about where we are going and whether we can try and unify different modeling frameworks that tackle things from different perspectives (closed-world shape-based on object-oriented modeling, template/pattern frameworks, lower level logical modeling frameworks).

Unifying multiple frameworks – is it possible or advisable?

Unfortunately due to lack of time I didn’t go into either ROBOT templates or OTTR templates.

And in closing, to emphasize that the community and social aspects are as important or more important than the technology:

Take homes

And some useful links:

○ ontology-development-kit

dead_simple_owl_design_patterns (dos-dps)


Special thanks to everyone in OBO and the uPheno reconciliation effort, especially David-Osumi Sutherland, Jim Balhoff, and Nico Matentzoglu.

And thanks to Pascal Hitzler and Cogan Shimizu for putting together such a great workshop.

Edge properties, part 1: Reification

This is the first part of what will be a multi-part series. See also part 2 on the singleton property pattern.

One of the ways in which RDF differs from Labeled Property Graph (LPG) models such as the data model in Neo4J is that there is no first-class mechanism for making statements about statements. For example, given a triple :P1 :interacts-with :P2, how do we say that triple is supported by a particular publication?

With an LPG, an edge can have properties associated with it in addition to the main edge label. In Neo4J documentation, this is often depicted as tag-values underneath the edge label. So if the assertion that P1 interacts with P2 is supported by a publication such as PMID:123 we might write this as:

(Note that some datamodels such as Neo4J don’t directly support hypergraphs, and if we wanted to represent pmid:123 as a distinct node with its own propertiess, then the association between the edge property and the node would be implicit rather than explicit)

In RDF, properties cannot be directly associated with edges. How would we represent something like the above in RDF? In fact there are multiple ways of modeling this.

A common approach is reification. Here we would create an extra node representing the statement, associate this with the original triple via three new triples, and then the statement node can be described as any other node. E.g.

This can be depicted visually as follows (note that while the first triple directly connecting P1 and P2 may seem redundant, it is not formally entailed by RDF semantics and should also be stated):

This is obviously quite verbose, so there are a different visual conventions and syntactic shortcuts to reduce bloat.

RDF* provides a more convenient compact syntax for writing edge properties:

  • <<:P1 :interacts_with :P2>>  :supported_by :pmid123 .

Here the <<…>> can be seen as acting as syntactic sugar, with the above single line of RDF* expanding to the 6 triples above.

RDF* is not yet a W3 standard, but a large number of tools support it. It is accompanied by SPARQL* for queries.

There is a lot more to be said about the topic of edge properties in LPGs and RDF, I will try to cover these in future posts. This includes:

  • Alternatives to RDF reification, of which there are many
    • Named Graphs, which capitalize on the fact that triplestores are actually quad stores, and use the graph with which a triple is associated with as a site of attachment for edge properties.
    • The Singleton Property Pattern (SPP). This has some adherents, but is not compatible with OWL-DL modeling. This is addressed in part two of this series
    • Alternative Reification Vocabularies. This includes the OWL reification vocabulary. It’s immensely depressing and confusing and under-appreciated that OWL did not adopt the RDF reification vocabulary, and the OWL stack fails horribly when we try and use the two together. Additionally OWL reification comes with annoying limitations (see my answer on stack overflow about RDF vs OWL reification).
    • RDF* can be seen as an alternative or it can be seen as syntactic sugar and/or a layer of abstraction over existing RDF reification
    • various other design patterns such as those in
  • Semantics of reification. RDF has monotonic semantics. This means that adding new triples (including reification triples) cannot retract the meaning of any existing triples (including the reified triples). So broadly speaking, it’s fine to annotate a triple with metadata (e.g. who said it), but not with something that alters it’s meaning (e.g. a negation qualifier, or probabilistic semantics). This has implications on how we represent knowledge graphs in RDF, and on proposals for simpler OWL layering on RDF. It also has implications for inference with KGs, both classic deductive boolean inference as well as modern KG embedding and associated ML approaches (e.g node2vec, embiggen).
  • Alternate syntaxes and tooling that is compatible with RDF and employs higher level abstractions above the verbose bloated reification syntax/model above. This includes RDF*/SPARQL* as well as KGX.

Next: Edge properties, part 2: singleton property pattern (and why it doesn’t work)

The Open World Assumption Considered Harmful

A frequent source of confusion with ontologies and more generally with any kind of information system is the Open World Assumption. This trips up novice inexperienced users, but as I will argue in this post, information providers could do much more to help these users. But first an explanation of the terms:

With the Open World Assumption (OWA) we do not make any assumptions based on the absence of statements. In contrast, with the Closed World Assumption (CWA), if something is not explicitly stated to be true, it is assumed to be false. As an example, consider a pet-owner database with the following facts:

Fred type Human .
Farrah type Human .

Foofoo type Cat .
Fido type Dog .

Fred owns Foofoo .
Farrah owns Fido.

Depicted as:

depiction of pet owners RDF graph, with triples indicated by arrows. RDF follows the OWA: the lack of a triple between Fred and Fido does not entail that Fred doesn’t own Fido.

Under the CWA, the answer to the question “how many cats does Fred own” is 1. Similarly, for “how many owners does Fido have” the answer also 1.

RDF and OWL are built on the OWA, where the answer to both question is: at least 1. We can’t rule out that Fred also owns Fido, or that he owns animals not known to the database. With the OWA, we can answer the question “does Fred own Foofoo” decisively with a “yes”, but if we ask “does Fred own Fido” the answer is “we don’t know”. It’s not asserted or entailed in the database, and neither is the negation.

Ontology formalisms such as OWL are explicitly built on the OWA, whereas traditional database systems have features constructed on the CWA.

OWL gives you mechanisms to add closure axioms, which allows you to be precise about what is known not be to true, in addition what is known to be true. For example, we can state that Fred does not own Fido, which closes the world a little. We can also state that Fred only owns Cats, which closes the world further, but still does not rule out that Fred owns cats other than Foofoo. We can also use an OWL Enumeration construct to exhaustively list animals Fred does own, which finally allows the answer to the question “how many animals does Fred own” with a specific number.

OWL ontologies and databases (aka ABoxes) often lack sufficient closure axioms in order to answer questions involving negation or counts. Sometimes this is simply because it’s a lot of work to add these additional axioms, work that doesn’t always have a payoff given typical OWL use cases. But often it is because of a mismatch between what the database/ontology author thinks they are saying, and what they are actually saying under the OWA. This kind of mismatch intent is quite common with OWL ontology developers.

Another common trap is reading OWL axioms such as Domain and Range as Closed World constraints, as they might be applied in a traditional database or a CWA object-oriented formalism such as UML.

Consider the following database plus ontology in OWL, where we attempt to constrain the ‘owns’ property only to humans

owns Domain Human
Fido type Dog
Fred type Human
Fido owns Fred

We might expect this to yield some kind of error. Clearly using our own knowledge of the world something is amiss here (likely the directions of the final triple has been accidentally inverted). But if we are to feed this in to an OWL reasoner to check for incoherencies (see previous posts on this topic), then it will report everything as consistent. However, if we examine the inferences closely, we will see that it is has inferred Fido to be both a Dog and a Human. It is only after we have stated explicit axioms that assert or entail Dog and Human are disjoint that we will see an inconsistency:

OWL reasoner entailing Fido is both a Dog and a Human, with the latter entailed by the Domain axiom. Note the ontology is still coherent, and only becomes incoherent when we add a disjointness axiom

In many cases the OWA is the most appropriate formalism to use, especially in a domain such as the biosciences, where knowledge (and consequently our databases) is frequently incomplete. However, we can’t afford to ignore the fact that the OWA contradicts many user expectations about information systems, and must be pragmatic and take care not to lead users astray.

BioPAX and the Open World Assumption

BioPAX is an RDF-based format for exchanging pathways. It is supposedly an RDF/OWL-based standard, with an OWL ontology defining the various classes and properties that can be used in the RDF representation. However, by their own admission the authors of the format were not aware of OWL semantics, and the OWA specifically, as explained in the official docs in the level 2 doc appendix, and also further expanded on in a paper from 2005 by Alan Ruttenberg, Jonathan Rees, and Joanne Luciano, Experience Using OWL DL for the Exchange of Biological Pathway Information, in particular the section “Ambushed by the Open World Assumption“. This gives particular examples of where the OWA makes things hard that should be easy, such as enumerating the members of a protein complex (we typically know all the members, but the BioPAX RDF representation doesn’t close the world).

BioPAX ontology together with RDF instances from EcoCyc. Triples for a the reaction 2-iminopropanoate + H2O → pyruvate + ammonium is shown. The reaction has ‘left’ and ‘right’ properties for reactants such as H2O. These are intended to be exhaustive but the lack of closure axioms means that we cannot rule out additional reactants for this reaction.

The Ortholog Conjecture and the Open World Assumption

gene duplication and speciation, taken from

In 2011 Nehrt et al made the controversial claim that they had overturned the ortholog conjecture, i.e they claimed that orthologs were less functionally similar than paralogs. This was in contrast to the received wisdom, i.e if a gene duplicates with a species lineage (paralogs) there is redundancy and one copy is less constrained to evolve a new function. Their analysis was based on semantic similarity of annotations in the Gene Ontology.

The paper stimulated a lot of discussion and follow-up studies and analyses. We in the Gene Ontology Consortium published a short response, “On the Use of Gene Ontology Annotations to Assess Functional Similarity among Orthologs and Paralogs: A Short Report“. In this we pointed out that the analysis assumed the CWA (absence of function assignment means the gene does not have that function), whereas GO annotations should be interpreted under the OWA (we have an explicit way of assigning that a gene does not have a function, rather than relying on absence). Due to bias in GO annotations, paralogs may artificially have higher functional similarity scores, rendering the original analysis insufficient to reject the ortholog conjecture.

The OWA in GO annotations is also addressed in the GO Handbook in the chapter Pitfalls, Biases, and Remedies by Pascale Gaudet. This chapter also makes the point that OWA can be considered in the context of annotation bias. For example, not all genes are annotated at the same level of specificity. The genes that are annotated reflect biases in experiments and publication, as well as what is selected to be curated.

Open World Assumption Considered (Sometimes) Harmful

The OWA is harmful where it grossly misaligns with use expectations.

While a base assumption of OWA is usually required with any curated information, it is also helpful to think in terms of an overriding implicit contract between any information provider and information consumer: any (good) information provider attempts to provide as complete information as is possible, given resource constraints.

My squid has no tentacles

Let’s take an example: If I am providing an ontology I purport to be an anatomical ontology for squid, then it behooves me to make sure the main body parts found in a squid are present.

Chiroteuthis veranii, the long armed squid, By Ernst Haeckel, with two elongated tentacles.

Let’s say my ontology contains classes for some squid body parts such as eye, brain, yet lacks classes for others such as the tentacle. A user may be surprised and disappointed when they search for tentacle and come back empty-handed (or empty tentacled, if they are a squid user). If this user were to tell me that my ontology sucked, I would be perfectly within my logical rights to retort: “sir, this ontology is in OWL and thus follows the Open World Assumption; as such the absence of a tentacle class in my squid ontology does not entail that squids lack tentacles, for such a claim would be ridiculous. Please refer to this dense interlinked set of documents published by the W3C that requires PhD in logic to understand and cease from making unwarranted assumptions about my ontology“.

Yet really the user is correct here. There should be an assumption of reasonable coverage, and I have violated that assumption. The tentacle is a major body part, it’s not like I have omitted some obscure neuroanatomical region. Is there a hard and fast dividing line here? No, of course not. But there are basic common sense principles that should be adhered to, and if they cannot be adhered to, omissions and biases should be clearly documented in the ontology to avoid confusing users.

This hypothetical example is made up, but I have seen many cases where biases and omissions in ontologies confusingly lead the user to infer absence where the inference is unwarranted.

Hydroxycholoroquine and COVID-19

The Coronavirus Infectious Disease Ontology (CIDO) integrates a number of different ontologies and includes axioms connecting terms or entities using different object properties. An example is the ‘treatment-for’ edge which connects diseases to treatments. Initially the ontology only contained a single treatment axiom, between COVID-19 and Hydroxychloroquine (HCQ). Under the OWA, this is perfectly valid: COVID-19 has been treated with HCQ (there is no implication about whether treatment is successful or not). However, the inclusion of a single edge of this type is at best confusing. A user could be led to believe there was something special about HCQ compared to other treatments, and the ontology developers had deliberately omitted these. In fact initial evidence for HCQ as a successful treatment has not panned out (despite what some prominent adherents may say). There are many other treatments, many of which are in different clinical trial phases, many of which may prove more effective, yet assertions about these are lacking in CIDO. In this particular case, even though the OWA allows us to legitimately omit information, from a common sense perspective, less is more here: it is better to include no information about treatments at all rather than confusingly sparse information. Luckily the CIDO developers have rapidly addressed this situation.

Ragged Lattices, including species-specific classes

An under-appreciated problem is the confusion ragged ontology lattices can cause users. This can be seen as a mismatch between localized CWA expectations on the part of the user and OWA on the part of the ontology provider. But first an explanation of what I mean by ragged lattice:

Many ontologies are compositional in nature. In a previous post we discussed how the Rector Normalization pattern could be used to automate classification. The resulting multi-parent classification forms a lattice. I have also written about how we should embrace multiple inheritance. One caveat to both of these pieces is that we should be aware of the confusion that can be caused by inconsistently populated (‘ragged’) lattices.

Take for example cell types, which can be classified along a number of orthogonal axes, many intrinsic to the cell itself – its morphological properties, it’s lineage, its function, or gene products expressed. The example below shows the leukocyte hierarchy in CL, largely based on intrinsic properties:

Protege screenshot of the cell ontology, leukocyte hierarchy

Another way to classify cells is by anatomical location. In CL we have a class ‘kidney cell’ which is logically defined as ‘any cell that is part of a kidney’. This branch of CL recapitulates anatomy at the upper levels.

kidney cell hierarchy in CL, recapitulating anatomical classification

so far, perfectly coherent. However, the resulting structure can be confusing to someone now used to thinking in OWL and the OWA. I have seen many instances where a user will go to a branch of CL such as ‘kidney cell‘ and start looking for a class such as ‘mast cell‘. It’s perfectly reasonable for them to look here, as mast cells are found in most organs. However, CL does not place ‘mast cell’ as a subclass of ‘kidney cell’ as this would entail that all mast cells are found in the kidney. And, CL has not populated the cross-product of all the main immune cell types with the anatomical structures in which they can be found. The fleshing out of the lattice is inconsistent, leading to confusion caused by violation of an assumed contract (provision of a class “kidney cell” and incomplete cell types underneath).

This is even more apparent if we introduce different axes of classification, such as the organism taxon in which the cell type is found, e.g. “mouse lymphocyte”, “human lymphocyte”:

inferred hierarchy when we add classes following a taxon design pattern, e.g. mouse cell, mouse lymphocyte. Only a small set of classes in the ontology are mouse specific.

Above is a screenshot of what happens when we introduce classes such as ‘mouse cell’ or ‘mouse lymphocyte’. We see very few classes underneath. Many people indoctrinated/experienced with OWL will not have a problem with this, they understand that these groupings are just for mouse-specific classes, and that the OWA holds, and absence of a particular compositional class, e.g. “mouse neuron” does not entail that mice do not have neurons.

One ontology in which the taxon pattern does work is the protein ontology, which includes groupings like “mouse protein”. PRO includes all known mouse proteins under this, so the classification is not ragged in the same way as the examples above.

There is no perfect solution here. Enforcing single inheritance does not work. Compositional class groupings are useful. However, ontology developers should try and avoid ragged lattices, and where possible populate lattices consistently. We need better tools here, e.g. ways to quantitative measure the raggedness of our ontologies.

Ontologies and databases should better document biases and assumptions

As providers of information, we need to do a better job of making all assumptions explicit and well-documented. This applies particularly to any curated corpus of knowledge, but in particular to ontologies. Even though hiding behind the OWA is logically defensible, we need to make things more intuitive for users.

It’s not uncommon for an ontology to have excellent very complete coverage of one aspect of the domain, and to be highly incomplete in another (reflecting either the biases/interests of the developers, or of the broader field). In fact I have been guilty of this in ontologies I have built or contributed to. I have seen users become confused when a class they expected to find was not present, or they have been perplexed by the ragged lattice problem, or an edge they expected to find was not present.

Few knowledge bases can ever be complete, but we can do better at documenting known unknowns or incompletenesses. We can imagine a range of formal computable ways of doing this, but a good start would be some simple standard annotation properties that can be used as inline documentation in the ontology. Branches of the ontology could be tagged in this way, e.g. to indicate that ‘kidney cell’ doesn’t include all cells found in the kidney, only kidney specific ones; or that developmental processes in GO are biased towards human and model organisms. This system could also be used for Knowledge Graphs and annotation databases too, to indicate that particular genes may be under-studied or under-annotated, an extension of the ND evidence type used in GO.

In addition we could do a better job at providing consistent levels of coverage of annotations or classes. There are tradeoffs here, as we naturally do not want to omit anything, but we can do a better job at balancing things out. Better tools are required here for detecting imbalances and helping populate information in a more balanced consistent fashion. Some of these may already exist and I’m not aware of them – please respond in the comments if you are aware of any!

A simple standard for sharing mappings

A common pain point for anyone working in bioinformatics is mapping identifiers. Many databases have overlapping content, or provide different data about the same entities, such as genes. Typically every database mints public identifiers in its own namespace. This means that the same gene may have multiple different identifiers in different databases (see for example some of the issues with SARS-CoV-2 protein identifiers). Anyone doing an analysis that combines data from different databases must do some kind of cross-walk or mapping.

Unfortunately mapping is fraught with problems. Simply finding the required mappings can be a challenge, and for any given pair of databases there may be different mappings from different providers. The provider may be the source databases, or a 3rd party provider such as BridgeDb. The meaning of a mapping may not be clear: does a mapping denote equivalence, or at least a 1:1 relationship? This is particularly challenging when trying to build a knowledge graph from multiple sources, where we want to merge information about the same entity.

Mappings are a big deal for ontologies too. There is an entire field of ontology alignment/matching. In theory ontologies should be able to make the meaning of mappings explicit, yet somehow we have messed this up, providing multiple alternate ways to say the same thing (OWL logical expressions, SKOS, and classic loose bioinformatics ‘dbxrefs’).

Within the Open Bio Ontologies project we attempted to avoid the mapping issue by promoting reuse of ontologies and concepts from ontologies — including reusing identifiers/URIs. Reuse is a standard concept in software engineering, and I’ve written before about (re)using software concepts in ontology engineering. However, not all ontologies are in OBO, and not all ontologies in OBO are perfectly modular and non-overlapping, so mapping remains a necessary evil.

Mappings between Ontologies visualized in the OLS OxO tool

Overall there are a multitude of headaches and challenges associated with mappings. One tractable chunk we have tried to break off recently is to come up with a standard exchange format for mappings. Currently mappings are distributed in ad-hoc formats, and there is no standard way of providing metadata about the mappings (who provided them, when, how, what is their quality, etc).

SSSOM: A Simple Shared Standard for Ontology Mapping

We have recently come up a proposed standard for mappings. We came up with the name SSSOM. A few initial comments about the name:

  • it stands for Simple Shared Standard for Ontology Mapping. However, I believe it’s completely applicable to any named entity, whether modeled ontologically or not. You can use SSSOM for genes, proteins, people
  • Yes, that is 3 leading ‘S’s. I have a colleague who calls it ‘slytherin

Details can be found in the SSSOM repo. I’ll provide a brief summary here.

The primary manifestation of SSSOM is as a TSV (tab-separate value) file. However, the data model is independent of the serialization format, and it can also be modeled in OWL, and any OWL serialization is possible (including JSON-LD).

SSSOM provides a standard way to describe a lot of rich information about mappings, but it allows you to be lazy and provide a minimum amount of information. The following example shows some mappings between the human phenotype ontology and the mouse phenotype ontology:

Example SSSOM table (source can be found at

Note that in this case we are using SKOS as mapping predicates, but other predicates can be used.

Identifiers and mapping set metadata

SSSOM does require that all entities are written as CURIEs, with defined prefixes. The prefix expansions to URIs are written in the header in the same way you would for a format like RDF/Turtle.

For the above example, the source example TSV can be found here. Note the header:

#creator_id: ""
#  HP: ""
#  MP: ""
#  skos: ""
#license: ""
#mapping_provider: ""

The header is escaped by hash-quote marks, and is in YAML format. The curie_map tag provides expansions of prefixes to base URIs. It is recommended you use standard prefixes, such as the OBO prefixes (for ontologies) or the Biolink Model (which incorporates OBO, as well as other sources like via prefixcommons).

The header also allows for many other pieces of metadata about the mapping set. Inclusion of an explicit license is encouraged – and I would recommend CC-0 for all mappings.

Mapping metadata

The complete set of elements that can be used to describe a mapping can be found in the relevant section of the spec. Some of these can be used for individual mappings, some can be applied in the header if they apply to all.

Some elements to call out:

  • Each mapping can have an associated confidence score, between zero and one. This can be useful for probabilistic OWL based ontology merging approaches, e.g. LogMap and kBOOM/Boomer.
  • Mappings and mapping sets can have provenance – e.g. orcid of the mapping_provider, as well as the date of the mapping
  • Information about how the match was made, such as the mapping tool, the type of match (e.g. automated lexical vs curated). We have developed a controlled vocabulary for this. For lexical matches, you can also indicate what property was matched (e.g a match may be based on a shared oboInOwl:hasDbXref in common, a shared rdfs:label, or a shared label/snonym pair).

OWL serialization

See the docs on OWL.

Example of use outside ontologies

The metadata_converter project is intended to provide schema mappings between metadata schemes. The current focus is on standards used in environmental ‘omics’, of interest to the NMDC, such as MIxS, NEON, DarwinCore, and SESAR/IGSN.

The mappings between schema elements in SSSOM format can be found here.


SSSOM is a new standard, and may change based on community feedback, so there is not much tooling yet.

We have an early version of a Python toolkit for working with SSSOM files:

Additionally, rdf_matcher generates SSSOM files (more on rdf_matcher in a future post). Boomer will be adapted to take SSSOM as an input for probabilistic axioms.

Feedback welcome!

We welcome comments, criticism, questions, requests for new metadata elements etc on our tracker.

For the current version of SSSOM we are indebted to the following people who crafted the spec:

  • Ernesto Jimenez-Ruiz (City, University of London)
  • John Graybeal (Stanford)
  • William Duncan (LBL)
  • David Osumi-Sutherland (EMBL-EBI)
  • Simon Jupp (SciBite)
  • James McLaughlin (EMBL-EBI)
  • Henriette Harmse (EMBL-EBI)

The person responsible for the vast majority of the work on SSOM is Nicolas Matentzoglu who crafted the spec, wrote the metadata ontology, served as community liaison and coordinated feedback

What is the SARS-CoV-2 molecular parts list?

There is a lot we still have to learn about SARS-CoV-2 and the disease it causes in humans. One aspect of the virus that we do know a lot about is its underlying molecular blueprint. We have the core viral genome, and broadly speaking we know the ‘parts list’ of proteins that are translated and spliced from the genome. There is a lot that we still don’t know about the proteins themselves – how variations affect the ability of the virus to infect a host, which molecules bind to these proteins and how that binding impacts their function. But at least we know the basic parts list. Or we think we do. There is the Spike protein (S), which adorns the surface of this virus like a crown, hence the name ‘coronavirus’. There are the 16 ‘non-structural proteins’ formed by cleavage of a viral polyprotein; one such protein is nsp5 which functions as a protease that performs this same cleavage. And there are the accessory proteins, such as the mysterious ORF8. The genomic blueprint and the translated and cleaved products can be illustrated visually:

SARS-CoV-2 genome and protein products. The ORF1a/1ab polyprotein is cleaved into cleavage products (non-structural proteins; nsp1-16). Note that there are two overlapping polyproteins 1a and 1b, only 1ab is shown here for simplicity. Image taken from

Each of these proteins has a variety of different names, for example, nsp3 is also known as PLpro. The genome is small enough that most scientists working on it have memorized the core aliases such that human-to-human communication is relatively unproblematic.

Of course, as we all know, relying on gene and protein symbols for unique identification in a database for machine-machine communication is a recipe for disaster. Symbols are inherently ambiguous, so we assign identifiers to entities in order to disambiguate them. These identifiers can then be adorned with metadata such as symbols, names, aliases, descriptions, functional descriptions and so on.

As everyone working in bioinformatics knows, different databases assign different identifiers for the same entity (by varying definitions of ‘same’), creating the ubiquitous identifier mapping problem and a cottage industry in mapping solutions.

This is a perennial problem for all omics entities such as genes and proteins, regardless of the organism or system being studied. But when it comes to SARS-CoV-2, things are considerably worse.

It turns out that many problems arise from the relatively simple biological phenomena of cleavage of viral polyproteins. While the molecular biology is not so difficult (one parent protein as a source for many derivative proteins), many bioinformatics databases are not designed with this phenomena in mind. This is fine for scenarios where we can afford to gloss over differences between the immediate products of translation and downstream cleavage products. While cleavage certainly happens in the human genome (e.g POMC), it’s rare enough to effectively ignore in some contexts (although arguably this causes a lot of problems too). However, the phenomena of a single translation product producing multiple functionally discrete units is much more common in viruses, which creates issues for many databases when creating a useful ‘canonical parts list’.

The roll-up problem

The first problem is that many databases either ignore the cleavage products or don’t assign them identifiers in the same category as other proteins. This has the effect of ‘rolling up’ all data to the polyprotein. This undercounts the number of true proteins, and does not provision identifiers for distinct functional entities.

For example, NCBI Gene does a fantastic job of assembling the genetic parts lists for genes across all cellular organisms and viruses. Most of the time, the gene is an appropriate unit of analysis, and we can use gene identifiers as proxies for the product transcribed and translated from that gene. In the case of SARS-CoV-2, NCBI mints a gene ID for the polyprotein (e.g. 1ab), but lacks distinct gene IDs for individual cleavage products ,even though each arguably fulfill the definition of discrete genes, and each is a discrete non-overlapping unit with a distinct function. Referring to the figure above, nsp1-10 are all ‘rolled up’ into the 1ab or 1a polyprotein entity.

Now this is perhaps understandable given that the NCBI Gene database is centered on genes (they do provide distinct protein IDs for the products, see later), and the case can be made that we should only have gene IDs for the immediate protein products (e.g polyproteins and structural proteins and accessory ORFs).

But the roll-up problem also exists for dedicated protein databases such as UniProt. UniProt mint IDs for polyproteins such as 1ab, but there is no UniProt accession for nsp1-16. These are ‘rolled up’ into the 1ab entry, as shown in the screenshot:

UniProt entry for viral polyprotein 1ab. Function summaries for distinct proteins (nsp1-3 shown, others below the fold) are rolled up to the polyprotein level

However, UniProt do provide identifiers for the various cleavage products, these are called ‘chain IDs’, and are of the form PRO_nnnnn. For example, an identifier for the nsp3 product is PRO_0000449621). Due to the structure of these IDs they are sometimes called ‘PRO IDs’ (However, they should not be confused with IDs from the Protein Ontology, which are also called ‘PRO IDs’. Confusing, huh?).

UniProt ‘chain’ IDs, with nsp3 highlighted. These do not get distinct accessions and do not get treated in the same way as a ‘full’ accessioned protein entry

Unfortunately these chain IDs are not quite first-class citizens in the protein database world. For example, the fantastic InterproScan pipeline is executed on the polyproteins, not the chain IDs. This means that domain and GO function calls are made at the level of the polyprotein, so it looks to a machine like there is one super-multifunctional protein that acts as a protease, ADP-ribose binding protein, autophagosome induction, etc. In one sense this is sort of true, but I don’t think it’s a very useful way of looking at protein function. It is more meaningful to assign the functions at the level of the individual cleavage products. It is possible to propagate the interproscan-assigned annotations down to the NSPs using the supplied coordinates, but it should not fall on consumers to do this extra processing step.

The not-quite-first-class status of these identifiers also causes additional issues. For example different ways to write the same ID (P0DTD1-PRO_0000449621 vs P0DTD1:PRO_0000449621 vs P0DTD1#PRO_0000449621 vs simply PRO_0000449621), and no standard URL (although UniProt is working on these issues).

The identical twin identifier problem

An additional major problem is the existence of two distinct identifiers for each of the initial non-structural proteins. Of course, we live with multiple identifiers in bioinformatics all the time, but we generally expect a single database to assign a single identifier for a single entity. Not so!

The problem here is the fact there is a ribosomal frameshift in the translation of the polyprotein in SARS-CoV-2 (again, the biology here is fairly basic), which necessitates two distinct database entries; here: each (called 1ab; aka P0DTD1 and 1a; aka P0DTC1). So far so good. However, while these are truly distinct polyproteins, the non-structural proteins cleaved from them are identical up until the frameshift. However, due to an assumption in databases that each cleavage product must have one ‘parent’, IDs are duplicated. This is shown in the following diagram:

Two polyproteins 1ab and 1a (this is shown an 1a and 1b here, in fact the 1ab pp covers both ORFs). Each nsp 1-10 gets two distinct IDs depending on the ‘parent’ despite sequence identity, and as far as we know, the same function. Diagram courtesy of ViralZone/SIB

While on the surface this may seem like a trivial problem with some easy workarounds, in fact this representation breaks a number of things. First it artificially inflates the proteome making it seems there are more proteins than they actually are. A parts list is less useful if it has to be post-processed in ad-hoc ways to get the ‘true’ parts list.

It can make it difficult when trying to promote the use of standard database identifiers over protein symbols because an arbitrary decision must be made, and if I make a different arbitrary decision from you, then our data does not automatically integrate. Ironically, using standard protein symbols like ‘nsp3’ may actually be better for database integration than identifiers designed for that purpose!

And when curating something like a protein interaction database or a pathway database an orthology database or assembling a COVID Knowledge Graph that deals with pairwise interactions, we must either choose arbitrarily or fully populate the cross-product of all pair combos. E.g. if nsp3 in SARS is orthologous to nsp3 in SARS-CoV-2, then we have to make four statements instead of one.

While I focused on UniProt IDs here, other major resources such as NCBI also have these duplicates in their protein database for the sam reason.

Kudos to Wikidata and the Protein Ontology

Two resources I have seen that gets this right are the Protein Ontology and Wikidata.

The Protein Ontology (aka PR, sometimes known as PRO; NOT to be confused with ‘PRO’ entries in UniProt) includes a single first-class identifier/PURL for each nsp, for example nsp3 has CURIE PR:000050272 ( It has mappings to each of the two sequence-identical PRO chain IDs in UniProt. It also has distinct entries for the parent polyprotein, and it has meaningful ontologically encoded edges linking the two (SARS-CoV-2 protein ontology available from

Protein Ontology entry for nsp3
Protein Ontology entry for SARS-CoV-2 nsp3, shown in obo format syntax (obo format is a human-readable concrete syntax for OWL).

Wikidata also does a good job of providing a single canonical identifier that is 1:1 with distinct proteins encoded by the SARS-CoV-2 genome (for example, the entry for nsp3 However, it is not as complete. Sadly it does not have mappings to either the protein ontology or the UniProt PRO chain IDs (remember: these are different!).

The big disadvantage of Wikidata and the Protein Ontology over the big major sequence databases is that they are not the big major sequence databases. They suffer a curation lag (one employing crowdsourcing, the other manual curation) whereas the main protein databases automate more albeit at the expense of quirks such as non-first-class IDs and duplicate IDs. Depending on the use case, this may not be a problem. Due to the importance of the SARS-CoV-2 proteome, sufficient resources were able to be marshalled on this effort. But will this scale if we want unique non-dupplicate IDs for all proteins in all coronaviruses – including all the different ones infecting bats and other hosts?

A compromise solution

When building KG-COVID-19 we needed to decide which IDs to use as canonical for SARS-CoV-2 genes and proteins. While our system is capable of working with alternate IDs (either normalizing during the KG build stage, or post build as part of a clique-merge step), it is best to avoid these. Mapping IDs can lead to either unintentional roll-ups (information about the cleavage product propagating up to the polyprotein) or worse, fanning-out (rolled up information then spreading to ‘sibling’ proteins); or if 1:1 is enforced the overall system is fragile.

We liked the curation work done by the Protein Ontology, but we knew (1) we needed a system that we could instantly get IDs for proteins in any other viral genome (2) we wanted to be aligned with sources we were ingesting, such as the IntAct curation of the Gordon et al paper, and Reactome plus GO-CAM curation of viral-host pathways. This necessitating the choice of a major database.

Working with the very helpful UniProt team in concert with IntAct curators we were able to ascertain that of the duplicate entries, by convention we should take the ID that comes from the longer polyprotein as the ‘reference’. For example, nsp3 has the following chain IDs:

  • P0DTC1-PRO_0000449637 (from the shorter pp: 1a) [NO]
  • P0DTD1-PRO_0000449621 (from the longer pp: 1ab) [YES]

(Remember, these are sequence-identical and as far as we know functionally identical).

In this case, we take PRO_0000449621 as the canonical/reference entry. This is also the entry IntAct use to curate interactions. We pretend that PRO_0000449637 does not exist.

This is very far from perfect. Biologically speaking, it’s actually the shorter pp that is more commonly expressed, so the choice of the longer one is potentially confusing. These is also the question of how UniProt should propagate annotations. It is valid to propagate from one chain ID to its ‘identical twin’. But what about when these annotations reference other cleavage products (e.g pairwise functional annotation from a GO-CAM, or an ortholog). Do we populate the cross-product? This could get confusing (my interest in this was both from the point of view of our COVID KG, but also wearing my GO hat)

Nevertheless this was the best compromise we could find, and we decided to follow this convention.

Some of the decisions are recorded in this presentation

Working with the UniProt and IntAct teams we also came up with a standard way to write IDs and PURLs for the chain IDs (CURIEs are of the form UniProtKB:ACCESSION-PRO_NNNNNNN). While this is not the most thrilling or groundbreaking development in the battle against coronaviruses, it excites me as it means we have to do far less time consuming and error prone identifier post-processing just to make data link up.

As part of the KG-COVID-19 project, Marcin Joachimiak coordinated the curation of a canonical UniProt-centric protein file (available in our GitHub repository), leveraging work that had been done by UniProt, the protein ontology curators, and the SciBite ontology team. We use UniProt IDs (either standard accessions, for polyproteins, structural proteins, and accessory ORFs; or chain IDs for NSPs) This file differs from the files obtained directly from UniProt, as we include only reference members of nsp ‘twins’, and we exclude less meaningful cleavage products.

This file lives in GitHub (we accept Pull Requests) and serves as one source for building our KG. The information is also available in KGX property graph format, or as RDF, or can be queried from our SPARQL endpoint.

We are also coordinating with different groups such as COVIDScholar to use this as a canonical vocabulary for text mining. Previously groups performing concept recognition on the CORD-19 corpus using protein databases as dictionaries missed the non-structural proteins, which is a major drawback.

Imagine a world

In an ideal world posts like this would never need to be written. There is no panacea; however, systems such as the Protein Ontology and Wikidata which employ an ontologically grounded flexible graph make it easier to work around legacy assumptions about relationships between types of molecular parts (see also the feature graph concept from Chado). The ontology-oriented basis makes it easier to render implicit assumptions explicit, and to encode things such as the relationship between molecular parts in a computable way. Also embracing OBO principles and reusing identifiers/PURLs rather than minting new ones for each database could go some way towards avoiding potential confusion and duplication of effort.

I know this is difficult to conceive of in the current landscape of bioinformatics databases, but paraphrasing John Lennon, I invite you to:

Imagine no proliferating identifiers
I wonder if you can
No need for mappings or normalization

A federation of ann(otations)
Imagine all the people (and machines) sharing all the data, you

You may say I’m a dreamer
But I’m not the only one
I hope some day you’ll join us
And the knowledge will be as one

Building a COVID-19 Knowledge Graph

With COVID-19 cases continuing to grow in number across the globe, scientists are forming new collaborations in order to better understand all aspects of SARS-CoV-2 together with its impact on human health. One aspect of this is organizing existing and emerging information about viral and host cell molecular biology, disease epidemiology, phenotypic progression, and effect of drugs and other treatments in individuals.

Knowledge Graphs (KGs) provide a way to organize complex heterogeneous information connecting different biological and clinical entities such as genes, drugs, diseases, exposures, phenotypes, and pathways.

For example, the following image shows a graphical (network) representation of SARS-CoV-2 proteins and host human proteins they are hypothesized to interact with, together with existing known human-human protein interactions, annotated with GO terms and drug target information:


SARS-CoV-2 host interaction map; taken from

Graphs such as this can be further extended with other information about the human and viral genes as it becomes available. Mechanisms such as endocytosis can also be included as nodes in the graph, as well as expression states of relevant human cells, etc.  Existing ontologies like GO, HPO, Mondo, and CHEBI, together with their annotations can be conceived of as KGs.

Screen Shot 2020-04-05 at 7.38.51 PM

Portion of a KG formed from GO, Mondo, HPO, Genes, and their inter-relationships

These KGs can be used as data warehouses for querying data integrated in a single place. They can also be used as sources in Machine Learning, for tasks such as link prediction. For example: which compounds might be likely to treat a particular disease, based on properties of both the compound and the disease.

The KG-COVID-19 Knowledge Graph Hub

As part of a collaboration between the Monarch Initiative, the Illuminating the Druggable Genome KG project, and PheKnowLater we have been collaboratively building a KG for COVID-19. All of the source is in GitHub, in the Knowledge-Graph-Hub/kg-covid-19 repository.

The project is built around the concept of a KG “Hub”, a lightweight way to build a KG from multiple upstream sources. Any developer can follow the instructions to ingest a new source, and make a Pull Request on the repo. So far we have a number of different sources ingested (detailed in the yaml file), and more on the way. The output is a simple biolink-model compliant KG in a simple TSV format that is compatible with Property Graphs (e.g. Neo4J) as well as RDF graphs. In all cases we use CURIEs that are equivalent to standard URIs, such as OBO Class PURLs.

One of the goals is to use this alongside our N2V framework to discover new links (for example, identifying existing drugs that could be repurposed to treat COVID-19) and generate actionable knowledge.

Screen Shot 2020-04-05 at 7.00.12 PM


Knowledge Graphs at the Virtual Biohackathon

The COVID-19 Biohackathon is a virtual event starting today (April 5 2020), lasting for a week, with the goal to “create a cohesive effort and work on tooling for COVID-19 analysis. The biohackathon will lead to more readily accessible data, protocols, detection kits, protein predictions etc.“. The Biohackathon was spearheaded by many of the same people behind the yearly Biohackathon which I have previously reported on.

One of the subgroups at the hackathon is the KnowledgeGraph group. This includes the kg-covid-19 contributors and other luminaries from the life sciences linked data / KG world, including neXtProt, UniProt, KnetMiner, Monarch, HPO, IDG-KG, GO.

I’m excited to see all these people working together as part of a dynamic group to produce tools that aim to help elucidate some of the biology underlying this critical threat. Of course, this is just one very small part of a massive global effort (really what we need to tackle COVID-19 is better public health infrastructure, widespread testing, ventilators, PPE for medical staff and workers on the front line, etc, see How the Pandemic Will End by Ed Jong). But I also think that this is an opportunity for collaborating on some of the crucial knowledge-based tools that have wide applications in biomedicine.

If you want to know more, the details of the biohackathon can be found on its GitHub page, and the kg-covid-19 repository can be found here, with contributor guidelines here.