Querying the Cognitive Atlas Ontology#
The neurosynth and neurostore engines load the Cognitive Atlas ontology (cogat.v2.owl of the
cogat-ontology
repository: about 1,800 classes, the concepts, tasks and task contrasts of
the field, with their labels, definitions and relations) next to the
studies, terms and peaks. Nothing is copied into tables: the ontology is
read by load_ontology() and stays an
ontology. Its triples are facts that rules and queries join with the data of
the engine, and its axioms (a class rdfs:subClassOf another) are
constraints that rewrite the queries, which is NeuroLang’s open-world
reasoning (see RDF Data and Ontologies). The file is downloaded once into
{data_dir}/{engine}/, and loading it takes about two seconds.
This page shows how to pull information out of it. The queries are Datalog,
for the neurolang-query REPL (neurolang-query --engine neurostore),
the --engine option of its one-shot mode, or
execute_datalog_program().
What is in the ontology#
The ontology is loaded with individuals: true and names: prefixed,
so that a triple s p o is the fact p(s, o), with classes and
properties named after their prefix, and the IRIs of the classes
(http://www.cognitiveatlas.org/ontology/cogat.owl#CAO_00587) are their
values. The ones to know:
rdfs:label(class, text)the name of a concept, task or contrast, capitalised (
'Working memory'); contrasts are namedTask_name-contrast('Digit_span_task-backward').skos:definition(class, text)its definition.
neurolang:subClassOf(class, super_class)the class hierarchy.
rdfs:subClassOfalso holds the axioms that are not a class, such as the restrictions below.owl:onProperty(restriction, property),owl:someValuesFrom(restriction, class)the existential restrictions. A contrast that measures a concept is a subclass of the restriction
measures some <concept>.
and, defined by the engine with rules over those:
cogat_subclass_of(class, ancestor)the hierarchy at any depth: the closure of
neurolang:subClassOf.cogat_measures(contrast, concept)the contrasts (and tasks) that measure a concept.
cogat_term(class, term)the label in lower case, to join with the terms of
mentionsandterm_in_study_tfidf.
They are listed with --list-predicates, and the sorts are
cogat_class (an IRI) and cogat_term.
Looking up concepts#
A concept is found by its label, and what is known of it by its IRI:
ans(d) :- rdfs:label(c, 'Working memory'), skos:definition(c, d)
ans(parent) :- rdfs:label(c, 'Working memory'),
neurolang:subClassOf(c, p), rdfs:label(p, parent)
The first returns the definition of working memory, “active maintenance and flexible updating of goal-task relevant information…”, the second its parent, Cognitive control.
Below a concept#
The classes below Cognitive control, at any depth (16 of them, among which Attention, Auditory working memory, Divided attention and Listening):
ans(l) :- rdfs:label(c, 'Cognitive control'),
cogat_subclass_of(x, c), rdfs:label(x, l)
and the contrasts that measure working memory, e.g.
Digit_span_task-backward:
ans(l) :- rdfs:label(c, 'Working memory'),
cogat_measures(x, c), rdfs:label(x, l)
Any other relation of the ontology is read the same way, through its
restrictions. For instance cogat_measures is defined as:
cogat_measures(x, c) :- rdfs:subClassOf(x, r),
owl:onProperty(r, <http://www.cognitiveatlas.org/ontology/cogat.owl#measures>),
owl:someValuesFrom(r, c)
and the properties used by the restrictions of the ontology
(descended_from, has_contrast, has_part, is_related_to,
measured_by, measures, part_of) are listed by:
ans(p) :- owl:onProperty(r, p)
From the ontology to the studies#
The ontology becomes useful with the data: its labels are the terms of the studies. The studies that mention working memory or any concept below it (301 studies below it in the 2026-10 NeuroStore release, among the 2,031 that mention working memory itself):
ans(s) :- rdfs:label(c, 'Working memory'),
cogat_subclass_of(x, c), cogat_term(x, t), mentions(s, t)
ans(s) :- mentions(s, 'working memory')
and the voxels they report, to map the concept with all its sub-concepts:
ans(i, j, k, s) :- rdfs:label(c, 'Cognitive control'),
cogat_subclass_of(x, c), cogat_term(x, t), mentions(s, t),
reports(s, i, j, k)
The opposite join, which Cognitive Atlas labels the studies talk about and how often (282 of them in the 2026-10 release, the first being Activation, Memory and Attention):
ans(l, agg_count(s)) :- rdfs:label(x, l), cogat_term(x, t),
mentions(s, t)
cogat_term lowercases the labels first. Writing the comparison in the
query itself, (lcase(l) == t) between rdfs:label and mentions,
gives the same answer but compares every label with every row of
mentions, which is about ten times slower.
mentions keeps the TF-IDF above 0.03. To weigh the studies instead, use
weighted_mention(s, t, w) or term_in_study_tfidf(s, t, w) in the same
rule. In the neurostore engine the terms are words and sequences of up
to three words of the abstracts, so multi-word concepts such as working
memory or spatial working memory are terms; the neurosynth vocabulary
has its own multi-word terms.
Using the ontology without an engine#
The same queries run on any frontend that loaded the file:
from neurolang.frontend import NeurolangPDL
nl = NeurolangPDL()
nl.load_ontology(
"cogat.v2.owl", individuals=True, names="prefixed"
)
nl.execute_datalog_program("""
cogat_subclass_of(x, y) :- neurolang:subClassOf(x, y)
cogat_subclass_of(x, z) :-
cogat_subclass_of(x, y), neurolang:subClassOf(y, z)
""")
below = nl.execute_datalog_program(
"ans(l) :- rdfs:label(c, 'Working memory'),"
" cogat_subclass_of(x, c), rdfs:label(x, l)"
)
To use the ontology in an engine of your own, add it to the ontologies
of its entry in engines.yaml, or extend coordinate_meta_analysis
(see Engine Configuration (engines.yaml)):
ontologies:
- url: https://raw.githubusercontent.com/CognitiveAtlas/cogat-ontology/master/ontology/cogat.v2.owl
individuals: true
names: prefixed