About this page
Key metrics and visualizations from the selected version of the AOP-Wiki database. Use the version selector above to compare different database snapshots over time.
- Current State: entity counts and database composition
- Network Analysis: AOP connectivity and structural relationships
- Data Quality: annotation completeness and ontology usage patterns
Current Database State
Entity Counts
Total number of each entity type and unique authors in the latest version of the AOP-Wiki database.
Methodology
What this measures: Full inventory of the selected snapshot: AOPs, Key Events, Key Event Relationships, Stressors, and the count of distinct authors who have contributed content. Use this card for a complete picture of database scope; use the Core Entity Summary card next to it for a stripped-down AOP/KE/KER view.
Data source: SPARQL queries against the AOP-Wiki RDF endpoint count instances of each entity class (aopo:AdverseOutcomePathway, aopo:KeyEvent, aopo:KeyEventRelationship, nci:C54571 for Stressors) and distinct creator URIs within a single named graph version.
Known limitations: Data reflects the RDF transformation of AOP-Wiki, not the raw database. Author counts are based on unique dc:creator URIs and may not correspond exactly to AOP-Wiki user accounts. Entities without RDF type annotations would not be counted.
View SPARQL Query
SELECT ?graph (COUNT(?aop) AS ?count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
Network Analysis
AOP Connectivity
Analysis of AOP connectivity based on shared Key Events. Connected AOPs share at least one Key Event with other AOPs, while isolated AOPs have unique Key Events.
Methodology
What this measures: Analyzes the connectivity of AOPs based on shared Key Events. Connected AOPs share at least one Key Event with other AOPs, while isolated AOPs have entirely unique Key Events. This reveals the degree of overlap and interconnection in the AOP knowledge base.
Data source: Two SPARQL queries: one counts total AOPs, the other counts AOPs that share at least one Key Event with another AOP (via aopo:has_key_event). The difference gives the isolated AOP count.
Known limitations: Connectivity is determined solely by shared Key Events declared via aopo:has_key_event. Implicit relationships or shared stressors are not considered. Network density depends on explicitly declared KE-KER relationships in the RDF data.
View SPARQL Query
SELECT ?graph (COUNT(DISTINCT ?aop1) AS ?connected_aops)
WHERE {
GRAPH ?graph {
?aop1 aopo:has_key_event ?ke .
?aop2 aopo:has_key_event ?ke .
FILTER(?aop1 != ?aop2)
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
AOP-AOP Overlap Network
Force-directed network where nodes are AOPs and edges connect AOP pairs that share Key Events. Use the slider above to adjust the minimum shared-KE threshold (range 2-10, default 5). Node colour = OECD status, node size = #KEs in the AOP, edge thickness = #shared KEs. Hover a node for its title and metadata. Tightly-clustered nodes (e.g. the MASLD AOP family 624-629) share a KE backbone and likely reflect related biology.
Methodology
What this measures: Force-directed network of AOPs that share a Key Event backbone. Nodes are AOPs (colour = OECD status, size = #KEs); edges connect pairs sharing ≥N KEs, where N is user-adjustable via the slider above the plot (range 2-10, default 5). With 584 AOPs there are >2400 pairs at ≥2 shared KEs, ~200 at ≥5, and only a handful at ≥10 (mostly the MASLD AOP family 624-629, which share 14-17 KEs each). Isolated AOPs (no partner meeting the threshold) are not drawn — the graph focuses on overlap structure.
Data source: Two SPARQL queries against the latest graph. First aggregates AOP pairs by shared-KE count with a `FILTER (STR(?aop1) < STR(?aop2))` to deduplicate. Second fetches per-AOP metadata (title, KE count, OECD status) for all AOPs that appear in any edge. Spring layout (k = 1.5/√n, seed=42) is computed in Python via networkx.
Known limitations: The threshold is editorial — use the slider above the plot to explore denser or sparser views. Edge count is capped at 200 to protect Plotly rendering; this binds at thresholds ≤3 today. Spring layout has no inherent meaning — proximity reflects shared KEs, not biological similarity. The network is undirected (AOP1↔AOP2); KE-level directionality is lost. The displayed SPARQL query reflects the default threshold of 5; the live plot uses the slider value.
Resolve latest snapshot graph URI
SELECT ?graph WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
} GROUP BY ?graph ORDER BY DESC(?graph) LIMIT 1
AOP pairs sharing ≥5 KEs (run on the latest graph)
SELECT ?aop1 ?aop2 (COUNT(DISTINCT ?ke) AS ?sharedKEs)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop1 a aopo:AdverseOutcomePathway ; aopo:has_key_event ?ke .
?aop2 a aopo:AdverseOutcomePathway ; aopo:has_key_event ?ke .
FILTER (STR(?aop1) < STR(?aop2))
}
}
GROUP BY ?aop1 ?aop2
HAVING (COUNT(DISTINCT ?ke) >= 5)
ORDER BY DESC(?sharedKEs)
LIMIT 250
Per-AOP metadata (title, KE count, OECD status) for nodes
SELECT ?aop ?title (COUNT(DISTINCT ?ke) AS ?ke_count) ?status
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
OPTIONAL { ?aop <http://purl.org/dc/elements/1.1/title> ?title }
OPTIONAL { ?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?s . BIND(STR(?s) AS ?status) }
}
}
GROUP BY ?aop ?title ?status
Average Components per AOP
Average number of Key Events and Key Event Relationships per AOP in the current database.
Methodology
What this measures: Calculates the average number of Key Events and Key Event Relationships per AOP in the selected database version. This metric indicates the typical structural complexity of AOPs.
Data source: SPARQL queries count the total number of AOP-to-KE and AOP-to-KER relationships (via aopo:has_key_event and aopo:has_key_event_relationship), then divide by the total number of AOPs.
Known limitations: Averages can be skewed by a few very large or very small AOPs. The metric does not distinguish between well-developed and stub AOPs. Relationships must be explicitly declared in RDF.
Count AOPs in latest graph
SELECT ?graph (COUNT(?aop) AS ?count)
WHERE {
GRAPH ?graph { ?aop a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
Count Key Events in latest graph
SELECT ?graph (COUNT(?ke) AS ?count)
WHERE {
GRAPH ?graph { ?ke a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
Count Key Event Relationships in latest graph
SELECT ?graph (COUNT(?ker) AS ?count)
WHERE {
GRAPH ?graph { ?ker a aopo:KeyEventRelationship . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
Key Event Analysis
KE Component Distribution
Distribution of Key Event component annotations (Process, Object, Action) in the current database.
Methodology
What this measures: Shows the distribution of Key Event Component annotations (Biological Process, Biological Object, and Action) across all Key Events. Each KE can have up to three component annotations describing the biological context.
Data source: A SPARQL query counts distinct biological process, object, and action terms attached to Key Events via the aopo:hasBiologicalEvent hop. Each KE links to a biological-event node, which carries optional aopo:hasProcess, aopo:hasObject, and aopo:hasAction annotations.
Known limitations: Only counts presence/absence of each component type, not the quality or specificity of annotations. KEs without any component annotations are not shown. Some KEs may have multiple annotations of the same type.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Count distinct process/object/action terms via biological events
SELECT
(COUNT(DISTINCT ?process) AS ?processes)
(COUNT(DISTINCT ?object) AS ?objects)
(COUNT(DISTINCT ?action) AS ?actions)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
OPTIONAL { ?bioevent aopo:hasProcess ?process . }
OPTIONAL { ?bioevent aopo:hasObject ?object . }
OPTIONAL { ?bioevent aopo:hasAction ?action . }
}
}
KE Annotation Depth
Distribution of annotation depth for Key Events, showing how thoroughly they are documented.
Methodology
What this measures: Measures how thoroughly each Key Event is annotated by counting how many of the three possible KE Component types (Process, Object, Action) each KE has. Shows the distribution across 0, 1, 2, or 3 annotations per KE.
Data source: A SPARQL query counts the number of biological-event annotations on each Key Event (?ke aopo:hasBiologicalEvent ?bioevent). Each bioevent carries at most one of aopo:hasProcess, aopo:hasObject, or aopo:hasAction, so the bioevent count equals the KE's component-annotation depth. The plot bins KEs by this count (0, 1, 2, 3+ components).
Known limitations: Treats all component types equally regardless of scientific importance. A KE with 3 low-quality annotations ranks higher than one with 1 highly specific annotation. Only measures breadth, not depth of annotation.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Count biological-event annotations per Key Event
SELECT ?ke (COUNT(DISTINCT ?bioevent) AS ?annotation_depth)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke aopo:hasBiologicalEvent ?bioevent . }
}
}
GROUP BY ?ke
ORDER BY DESC(?annotation_depth)
Breakdown Analysis
Key Events by Biological Level of Organization
Distribution of Key Events across biological levels of organization (molecular, cellular, tissue, organ, organism, population). Shows which biological scales are most studied.
Methodology
What this measures: Distribution of Key Events across biological levels of organization (molecular, cellular, tissue, organ, organism, population). Reveals which biological scales are most represented in the AOP-Wiki knowledge base.
Data source: SPARQL query counts distinct Key Events grouped by their Level of Biological Organisation annotation (NCI Thesaurus property C25664). KEs without this annotation appear as 'Not Annotated'.
Known limitations: Not all Key Events have biological level annotations. Unannotated KEs appear as 'Not Annotated' and may dominate the chart. The level vocabulary depends on how curators annotated each KE. Coverage varies by version as curation progresses.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Count KEs per biological level of organisation
SELECT ?level_label (COUNT(DISTINCT ?ke) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent .
OPTIONAL {
?ke <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25664> ?level_obj .
}
BIND(IF(BOUND(?level_obj), STR(?level_obj), "Not Annotated") AS ?level_label)
}
}
GROUP BY ?level_label
ORDER BY DESC(?count)
Taxonomic Group Distribution Across AOPs
Which taxonomic groups (species/organisms) are most represented across AOPs in the current database. Shows the top taxonomic applicability annotations.
Methodology
What this measures: Top 25 species annotated as taxonomically applicable to AOPs (via the `NCBITAXON/131567` predicate). Resolved from NCBI taxon IDs to scientific names using a curated label map (`static/data/ncbi_taxon_labels.json`, 133 species covering everything currently in AOP-Wiki). Both AOP-Wiki storage formats — modern `NCBITAXON/<id>` URIs and legacy `WCS_<id>` strings — are coalesced into a single bar per species. New species not yet in the label map render as `Taxon <id> (unresolved)` so they remain visible.
Data source: SPARQL pulls raw (`?aop`, `?taxon_obj`) pairs filtered to AOPs and the `131567` predicate, then Python aggregates per NCBI taxon ID (regex `(\d+)$` against the raw value handles both URI and `WCS_` formats). `WikiUser_<id>` strings — curator user IDs that historically leaked into the taxonomy field, not taxa — are filtered out; their count is logged for curation follow-up.
Known limitations: Only AOPs with an explicit `131567` annotation are shown. A single AOP may carry multiple taxa (it will then contribute to multiple bars). The label map is curated, not live: new species in future snapshots will display as `Taxon NNNN (unresolved)` until the map is regenerated. `WikiUser_NN` entries are filtered out, masking a known data-quality issue — see the dashboard logs for the count.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Pull raw (AOP, taxon) pairs for client-side aggregation
SELECT ?aop ?taxon_obj
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
?aop <http://purl.bioontology.org/ontology/NCBITAXON/131567> ?taxon_obj .
}
}
Entity Counts by OECD Status
Breakdown of AOPs, Key Events, and Key Event Relationships by their OECD approval status. Shows the curation maturity distribution across entity types.
Methodology
What this measures: Breaks down entity counts (AOPs, Key Events, Key Event Relationships) by OECD approval status category. Shows how curation maturity is distributed across entity types.
Data source: Three separate SPARQL queries count AOPs directly by their OECD Status annotation (NCI Thesaurus C25688), and KEs/KERs by the OECD status of their parent AOPs (via aopo:has_key_event and aopo:has_key_event_relationship relationships).
Known limitations: KEs and KERs inherit OECD status from their parent AOPs. A KE belonging to AOPs with different statuses appears in each status group. AOPs without an OECD status annotation appear as 'No Status'. Status categories reflect what is present in the data.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Count AOPs per OECD status
SELECT ?status_label (COUNT(DISTINCT ?aop) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
}
BIND(IF(BOUND(?status_obj), STR(?status_obj), "No Status") AS ?status_label)
}
}
GROUP BY ?status_label
Count KEs per parent-AOP OECD status
SELECT ?status_label (COUNT(DISTINCT ?ke) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
}
BIND(IF(BOUND(?status_obj), STR(?status_obj), "No Status") AS ?status_label)
}
}
GROUP BY ?status_label
Count KERs per parent-AOP OECD status
SELECT ?status_label (COUNT(DISTINCT ?ker) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event_relationship ?ker .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
}
BIND(IF(BOUND(?status_obj), STR(?status_obj), "No Status") AS ?status_label)
}
}
GROUP BY ?status_label
Coverage Analysis
AOP Coverage of Organ Systems
AOP coverage of 13 high-level organ systems, classified per AOP via a hybrid of four signals:
A (curated UBERON/CL anatomy on Key Events),
A′ (UBERON/CL appearing as biological-event objects),
B (GO biological-process bridge, curated map), and
C (regex on AOP title — exploratory, grey). Bar and pie views share one
scope toggle so they stay in sync; the View toggle drives the bar only (pie slices are
inherently proportional).
Tip: the CSV download below contains one row per AOP × bucket
(columns: AOP, AOP Title, AO URI, Organ System, Signals, Best Signal, Version, Scope) —
including the "No annotation" bucket, which lists every AOP that the classifier could not place
under the current scope.
Methodology
What this measures: Same per-AOP hybrid classification as before, but with two toggles. Scope picks which Key Events count toward Signals A, A' and B: all KEs (broadest), Apical KEs only (Tissue/Organ/Individual/Population), or just the Adverse Outcome (regulatory endpoint). Signal C (AOP title regex) is kept regardless of scope. View switches between absolute AOP counts and share of all AOPs in the snapshot. The four legacy panels collapse into this single view; the pie below mirrors the same scope so you read one coherent slice across the section.
Data source: One SPARQL query per snapshot pulls all AOPs, their member KEs, OrganContext / CellTypeContext / hasObject / hasProcess IRIs, and AOP titles. The UBERON / CL / GO term-to-bucket map is built offline by scripts/build_organ_system_cache.py — it queries Ubergraph (an integrated UBERON+CL+GO+RO ontology endpoint) and writes static/data/organ_system_cache.json. The dashboard loads that cache at startup. Click 'Browse full curated mapping (JSON)' to see the resolved term-to-bucket map, the bucket anchors, and the override layer.
How the mapping works:
- Step 1 — SPARQL pull. One query per snapshot collects every AOP, its member Key Events, and any IRIs in the four annotation predicates:
aopo:OrganContext,aopo:CellTypeContext,aopo:hasObject(insideaopo:hasBiologicalEvent), andaopo:hasProcess. AOP titles are pulled too — Signal C runs on them. - Step 2 — UBERON / CL → bucket via Ubergraph (Signals A and A'). Anatomical IRIs are resolved by transitive
(part_of | subClassOf)*closure to a small set of anchor IRIs per bucket — e.g. Nervous =UBERON_0001016(nervous system); Hepatobiliary = liver + gallbladder + bile duct. Anchor-specificity pruning then drops reached anchors that are themselves ancestors of other reached anchors — so liver (UBERON:0002107) classifies only as Hepatobiliary even though UBERON places it under both digestive and endocrine systems. The lookup runs offline againsthttps://ubergraph.apps.renci.org/sparqland is cached atstatic/data/organ_system_cache.json. Intentional dual-anchors are preserved: pancreas (UBERON_0001264) is its own anchor for both Digestive and Endocrine because it is both an exocrine digestive organ and an endocrine gland — so pancreas-derived terms classify to both. - Step 3 — Process / Phenotype signal (Signal B). Three resolution paths into the same 13 buckets: (a) GO biological-process via
RO:0002296(results_in_development_of) → UBERON anchor (~3 terms); (b) HP and MP phenotypes via theirrdfs:labelmatched against the Signal-C bucket regex — this replaces the previousUPHENO:0000001approach, which Ubergraph materialises as an over-broad anatomy closure (hepatic-steatosis and microvesicular-hepatic-steatosis return the same 35 UBERON targets including endocrine and digestive system). Label-regex gives mono-organ classification when the phenotype name names an organ system. Phenotypes whose label contains no organ keyword (e.g. behavioural HP/MP terms) are NOT classified. - Step 4 — Keyword regex on AOP titles (Signal C, exploratory). Each AOP title is scanned with a bucket-specific regex set, e.g. Nervous =
\bneuro,\bsynap,\bmyelin, …; Hepatobiliary =\bhepat,\bliver\b,\bsteatosis\b, …; Cardiovascular =\bcardio,\bheart\b, …. Lowest-confidence signal, shown in grey throughout. - Step 5 — Editorial override layer. A small project-owned override layer is applied after the ontology resolution to handle terms where the project's framing diverges from UBERON. Currently a single entry: blood (
UBERON_0000178) is reported under both Cardiovascular and Immune/Haematopoietic — UBERON places it structurally under haematopoietic only, but toxicology practice frames blood-borne effects as cardiovascular too. - Step 6 — Aggregate per AOP. An AOP is counted in a bucket if any of its member KEs (Signals A/A'/B) or its own title (Signal C) classifies into it. The bar segment colour shows the highest-confidence signal that classified the AOP–bucket pair (A > A' > B > C). AOPs can belong to multiple buckets — see the Multi-organ AOPs plot.
- Step 7 — Source code. Full classifier (~300 LOC, covering
classify_anatomy,classify_process,classify_text, the SIGNAL_ORDER reducer, the apical-level filter, and AO-only filter): see plots/organ_systems.py on GitHub. The ontology cache builder is at scripts/build_organ_system_cache.py.
Known limitations: The bucket anchors are curated (13 buckets × ~1-4 anchors each). UBERON's own structural decisions drive the rest — e.g. blood is haematopoietic, not cardiovascular, in UBERON; we override that one case. Signal B only classifies 3 GO BPs in the current snapshot because the RO:0002296 axiom is rare in GO — the trade-off vs a hand-curated bridge is conscious. Signal C is regex on free-text titles, shown in grey; not for regulatory claims. The 13 buckets are coarse — sub-organ resolution is collapsed for the headline view but preserved in the CSV download.
Browse full curated mapping (JSON)
Consolidated query (all signals in one pull)
SELECT ?aop ?aop_title ?ao ?ke ?organ ?cell ?obj ?proc
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
<http://purl.org/dc/elements/1.1/title> ?aop_title ;
aopo:has_key_event ?ke .
OPTIONAL { ?aop aopo:has_adverse_outcome ?ao . }
OPTIONAL { ?ke aopo:OrganContext ?organ . }
OPTIONAL { ?ke aopo:CellTypeContext ?cell . }
OPTIONAL {
?ke aopo:hasBiologicalEvent ?be .
OPTIONAL { ?be aopo:hasObject ?obj . }
OPTIONAL { ?be aopo:hasProcess ?proc . }
}
}
}
Signal A — curated anatomy on KEs
# Signal A only — curated anatomy directly on Key Events
SELECT ?aop ?ke ?organ_or_cell
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
{ ?ke aopo:OrganContext ?organ_or_cell . }
UNION
{ ?ke aopo:CellTypeContext ?organ_or_cell . }
}
}
Signal A' — UBERON/CL via hasObject
# Signal A' only — UBERON / CL appearing as hasObject inside a biological event
SELECT ?aop ?ke ?obj
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
?ke aopo:hasBiologicalEvent ?be .
?be aopo:hasObject ?obj .
FILTER( STRSTARTS(STR(?obj), "http://purl.obolibrary.org/obo/UBERON_")
|| STRSTARTS(STR(?obj), "http://purl.obolibrary.org/obo/CL_") )
}
}
Signal B — GO biological-process terms
# Signal B only — GO biological-process terms (bridged to buckets in Python)
SELECT ?aop ?ke ?proc
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
?ke aopo:hasBiologicalEvent ?be .
?be aopo:hasProcess ?proc .
FILTER( STRSTARTS(STR(?proc), "http://purl.obolibrary.org/obo/GO_") )
}
}
Signal C — fetch titles for Python regex
# Signal C precursor — fetch AOP and AO titles (Signal C runs as regex in
# Python against these literals; the curated patterns are listed at
# /api/organ-system-buckets under "keyword_patterns").
SELECT ?aop ?aop_title ?ao ?ao_title
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
<http://purl.org/dc/elements/1.1/title> ?aop_title .
OPTIONAL {
?aop aopo:has_adverse_outcome ?ao .
OPTIONAL { ?ao <http://purl.org/dc/elements/1.1/title> ?ao_title . }
}
}
}
Bar view
Pie view
Multi-organ AOPs
How many distinct organ systems each AOP classifies into across Signals A, A′, B and C. Single-organ AOPs sit in the “1” column; multi-organ pathways pile into 2, 3, …. The raw-data toggle lists every multi-organ AOP with its full bucket set; the CSV download gives the same per-AOP detail.
Methodology
What this measures: Distribution of AOPs by the number of distinct organ systems they classify into across Signals A, A', B, and C (excluding the No-annotation sentinel). Answers 'how many AOPs are single-organ vs multi-organ?'. The raw-data toggle lists every multi-organ AOP with its full bucket set, so you can inspect which pathways span e.g. Endocrine + Reproductive + Nervous.
Data source: Reuses the same SPARQL pull and ontology resolution as the AOP Coverage plot. For each AOP we count the number of distinct organ-system buckets it lands in via any of the four signals.
How the mapping works:
- Step 1 — SPARQL pull. One query per snapshot collects every AOP, its member Key Events, and any IRIs in the four annotation predicates:
aopo:OrganContext,aopo:CellTypeContext,aopo:hasObject(insideaopo:hasBiologicalEvent), andaopo:hasProcess. AOP titles are pulled too — Signal C runs on them. - Step 2 — UBERON / CL → bucket via Ubergraph (Signals A and A'). Anatomical IRIs are resolved by transitive
(part_of | subClassOf)*closure to a small set of anchor IRIs per bucket — e.g. Nervous =UBERON_0001016(nervous system); Hepatobiliary = liver + gallbladder + bile duct. Anchor-specificity pruning then drops reached anchors that are themselves ancestors of other reached anchors — so liver (UBERON:0002107) classifies only as Hepatobiliary even though UBERON places it under both digestive and endocrine systems. The lookup runs offline againsthttps://ubergraph.apps.renci.org/sparqland is cached atstatic/data/organ_system_cache.json. Intentional dual-anchors are preserved: pancreas (UBERON_0001264) is its own anchor for both Digestive and Endocrine because it is both an exocrine digestive organ and an endocrine gland — so pancreas-derived terms classify to both. - Step 3 — Process / Phenotype signal (Signal B). Three resolution paths into the same 13 buckets: (a) GO biological-process via
RO:0002296(results_in_development_of) → UBERON anchor (~3 terms); (b) HP and MP phenotypes via theirrdfs:labelmatched against the Signal-C bucket regex — this replaces the previousUPHENO:0000001approach, which Ubergraph materialises as an over-broad anatomy closure (hepatic-steatosis and microvesicular-hepatic-steatosis return the same 35 UBERON targets including endocrine and digestive system). Label-regex gives mono-organ classification when the phenotype name names an organ system. Phenotypes whose label contains no organ keyword (e.g. behavioural HP/MP terms) are NOT classified. - Step 4 — Keyword regex on AOP titles (Signal C, exploratory). Each AOP title is scanned with a bucket-specific regex set, e.g. Nervous =
\bneuro,\bsynap,\bmyelin, …; Hepatobiliary =\bhepat,\bliver\b,\bsteatosis\b, …; Cardiovascular =\bcardio,\bheart\b, …. Lowest-confidence signal, shown in grey throughout. - Step 5 — Editorial override layer. A small project-owned override layer is applied after the ontology resolution to handle terms where the project's framing diverges from UBERON. Currently a single entry: blood (
UBERON_0000178) is reported under both Cardiovascular and Immune/Haematopoietic — UBERON places it structurally under haematopoietic only, but toxicology practice frames blood-borne effects as cardiovascular too. - Step 6 — Aggregate per AOP. An AOP is counted in a bucket if any of its member KEs (Signals A/A'/B) or its own title (Signal C) classifies into it. The bar segment colour shows the highest-confidence signal that classified the AOP–bucket pair (A > A' > B > C). AOPs can belong to multiple buckets — see the Multi-organ AOPs plot.
- Step 7 — Source code. Full classifier (~300 LOC, covering
classify_anatomy,classify_process,classify_text, the SIGNAL_ORDER reducer, the apical-level filter, and AO-only filter): see plots/organ_systems.py on GitHub. The ontology cache builder is at scripts/build_organ_system_cache.py.
Known limitations: An AOP appearing in multiple buckets does not necessarily mean it is biologically multi-system — it can also mean Signal C (keywords) added an extra bucket on top of Signal A's curated anatomy. The CSV preserves which signal(s) contributed each bucket so this is auditable.
Browse full curated mapping (JSON)
Consolidated query (all signals in one pull)
SELECT ?aop ?aop_title ?ao ?ke ?organ ?cell ?obj ?proc
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
<http://purl.org/dc/elements/1.1/title> ?aop_title ;
aopo:has_key_event ?ke .
OPTIONAL { ?aop aopo:has_adverse_outcome ?ao . }
OPTIONAL { ?ke aopo:OrganContext ?organ . }
OPTIONAL { ?ke aopo:CellTypeContext ?cell . }
OPTIONAL {
?ke aopo:hasBiologicalEvent ?be .
OPTIONAL { ?be aopo:hasObject ?obj . }
OPTIONAL { ?be aopo:hasProcess ?proc . }
}
}
}
Signal A — curated anatomy on KEs
# Signal A only — curated anatomy directly on Key Events
SELECT ?aop ?ke ?organ_or_cell
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
{ ?ke aopo:OrganContext ?organ_or_cell . }
UNION
{ ?ke aopo:CellTypeContext ?organ_or_cell . }
}
}
Signal A' — UBERON/CL via hasObject
# Signal A' only — UBERON / CL appearing as hasObject inside a biological event
SELECT ?aop ?ke ?obj
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
?ke aopo:hasBiologicalEvent ?be .
?be aopo:hasObject ?obj .
FILTER( STRSTARTS(STR(?obj), "http://purl.obolibrary.org/obo/UBERON_")
|| STRSTARTS(STR(?obj), "http://purl.obolibrary.org/obo/CL_") )
}
}
Signal B — GO biological-process terms
# Signal B only — GO biological-process terms (bridged to buckets in Python)
SELECT ?aop ?ke ?proc
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
?ke aopo:hasBiologicalEvent ?be .
?be aopo:hasProcess ?proc .
FILTER( STRSTARTS(STR(?proc), "http://purl.obolibrary.org/obo/GO_") )
}
}
Signal C — fetch titles for Python regex
# Signal C precursor — fetch AOP and AO titles (Signal C runs as regex in
# Python against these literals; the curated patterns are listed at
# /api/organ-system-buckets under "keyword_patterns").
SELECT ?aop ?aop_title ?ao ?ao_title
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
<http://purl.org/dc/elements/1.1/title> ?aop_title .
OPTIONAL {
?aop aopo:has_adverse_outcome ?ao .
OPTIONAL { ?ao <http://purl.org/dc/elements/1.1/title> ?ao_title . }
}
}
}
AOP Life-Stage Applicability
Distribution of AOPs across declared life-stage applicability labels (e.g. Adult, Juvenile, Embryonic). Surfaces gaps in coverage of vulnerable populations. Sex applicability is not exposed as a structured RDF predicate; see methodology note.
Methodology
What this measures: Counts how many AOPs declare each life-stage applicability label (Adult, Juvenile, Embryo, All life stages, etc.) via aopo:LifeStageContext. An AOP with no LifeStageContext literal at all is reported as Not specified. AOPs with multiple life-stage labels contribute once per label.
Data source: Single SPARQL query selecting every aopo:AdverseOutcomePathway and OPTIONAL aopo:LifeStageContext literal in the selected snapshot. Aggregation happens in Python after deduplicating per AOP.
Known limitations: aopo:LifeStageContext values are free-text literals chosen by curators — there is no fixed controlled vocabulary, so spelling variants (e.g. "Adult" vs "Adults") appear as distinct bars. Sex applicability is NOT exposed as a structured RDF predicate; it is only described inside free-text aopo:AopContext literals and cannot be machine-aggregated reliably. The dashboard surfaces this gap rather than guessing.
View SPARQL Query
SELECT ?aop ?life_stage
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL { ?aop aopo:LifeStageContext ?life_stage . }
}
}
Key Event Reuse Analysis
Key Event Reuse Distribution
Histogram showing how many AOPs each Key Event belongs to. Most KEs appear in only 1 AOP, but some are shared across many pathways.
Methodology
What this measures: Histogram showing the distribution of how many AOPs each Key Event belongs to. Most KEs appear in only 1 AOP, but some are shared across many pathways, indicating shared biological mechanisms.
Data source: SPARQL query counts distinct AOPs per Key Event, then bins the results into discrete categories: 1, 2, 3, 4, 5, 6-10, and 11+ AOPs per KE.
Known limitations: Bins KEs into discrete groups for readability. The '6-10' and '11+' bins aggregate multiple values. Only KEs that are linked to at least one AOP via aopo:has_key_event are included. Orphan KEs (not linked to any AOP) are excluded.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
AOP count per Key Event (full distribution)
SELECT ?ke (COUNT(DISTINCT ?aop) AS ?aop_count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
}
}
GROUP BY ?ke
Most Reused Key Events Across AOPs
Top 30 Key Events that appear in the most AOPs, revealing shared biology across pathways. Click on a bar to open the Key Event in AOP-Wiki.
Methodology
What this measures: Shows the top 30 Key Events that appear in the most AOPs, revealing shared biology across adverse outcome pathways. Clicking a bar opens the corresponding KE page on AOP-Wiki.
Data source: SPARQL query counts distinct AOPs per Key Event via aopo:has_key_event relationships. Only KEs appearing in more than one AOP are shown. KE titles are retrieved via dc:title.
Known limitations: Limited to the top 30 most reused KEs. KE titles may be truncated for readability. The count reflects explicit aopo:has_key_event declarations in the RDF data. Entity links open https://aopwiki.org/events/{id} in a new tab.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Top 30 KEs by AOP membership count (HAVING > 1)
SELECT ?ke (SAMPLE(?title_val) AS ?title) (COUNT(DISTINCT ?aop) AS ?aop_count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
OPTIONAL { ?ke dc:title ?title_val . }
}
}
GROUP BY ?ke
HAVING (COUNT(DISTINCT ?aop) > 1)
ORDER BY DESC(?aop_count)
LIMIT 30
Data Quality & Completeness
KE Measurement-Method Coverage
Share of Key Events that carry an obo:MMO_0000000 (measurement method)
description — the single biggest completeness signal for NAM-ready AOPs.
Currently only ~37% of KEs have one.
Methodology
What this measures: Donut showing what fraction of KEs in the latest snapshot carry an `obo:MMO_0000000` measurement-method description. ~37% covered today; the uncovered ~63% is the single biggest NAM-readiness gap visible in AOP-Wiki RDF. Companion to the historical trend on the Trends page.
Data source: Single SPARQL aggregation over the latest named graph: `SUM(IF(BOUND(?mmo), 1, 0))` divided by `COUNT(?ke)`.
Known limitations: Counts presence of any MMO triple — does not assess length or quality of the assay text. KEs reused across AOPs are counted once.
View SPARQL Query
SELECT (SUM(IF(BOUND(?mmo), 1, 0)) AS ?with_mmo)
(COUNT(?ke) AS ?total)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke <http://purl.obolibrary.org/obo/MMO_0000000> ?mmo }
}
}
Ontology Term Diversity
Number of unique ontology terms used per source ontology (GO, CHEBI, UBERON, etc.) in Key Event annotations. Shows usage diversity, not coverage against reference ontologies.
Methodology
What this measures: Counts the number of unique ontology terms used per source ontology (GO, CHEBI, UBERON, NCBITAXON, etc.) in KE annotations. Shows the breadth of ontology vocabulary in use.
Data source: SPARQL query retrieves all distinct ontology-linked IRIs from biological process and biological object annotations. Python post-processing classifies each IRI by ontology namespace prefix and counts unique terms per source.
Known limitations: Shows aggregate counts of unique terms per ontology, not coverage vs reference ontologies (Phase 5 scope). Classification is based on URI prefix patterns. Terms from unrecognized ontologies appear as 'Other'.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Distinct ontology terms attached to KEs via biological events
SELECT DISTINCT ?term
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?be .
{ ?be aopo:hasProcess ?term . }
UNION
{ ?be aopo:hasObject ?term . }
}
FILTER(isIRI(?term))
}
Ontology Usage
Overview of ontology term usage across Key Event annotations in the AOP-Wiki database.
Methodology
What this measures: Shows the distribution of ontology terms used to annotate Key Event biological components (processes, objects, actions). Groups terms by their source ontology (GO, MP, NBO, MI, VT, MESH, HP, OTHER) to reveal which ontologies are most commonly used in the AOP-Wiki knowledge base.
Data source: SPARQL query retrieves all biological event terms linked to Key Events via aopo:hasProcess, aopo:hasObject, and aopo:hasAction predicates, then classifies each term by its URI prefix to determine the source ontology.
Known limitations: Ontology classification is based on URI prefix matching (e.g., GO_, MP_, HP_). Terms with unrecognized prefixes are grouped as OTHER. Only counts distinct terms, not total usage frequency. Limited to Key Event annotations in the selected version.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Distribution of process/object/action terms by ontology source
SELECT ?ontology (COUNT(DISTINCT ?term) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
{
?bioevent aopo:hasProcess ?term .
} UNION {
?bioevent aopo:hasObject ?term .
} UNION {
?bioevent aopo:hasAction ?term .
}
BIND(
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/GO_"), "GO",
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/MP_"), "MP",
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/NBO_"), "NBO",
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/MI_"), "MI",
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/VT_"), "VT",
IF(STRSTARTS(STR(?term), "http://purl.org/commons/record/mesh/"), "MESH",
IF(STRSTARTS(STR(?term), "http://purl.obolibrary.org/obo/HP_"), "HP", "OTHER"))))))) AS ?ontology)
}
}
GROUP BY ?ontology
AOP Completeness
Analysis of AOP data completeness showing the distribution of essential vs optional fields.
Methodology
What this measures: Analyzes how completely AOPs are documented by measuring the presence of key metadata properties. Shows the distribution of completeness scores across all AOPs, where completeness is the fraction of non-ubiquitous properties that are filled in.
Data source: Properties are loaded from property_labels.csv which defines expected properties per entity type. For each AOP, SPARQL queries check presence of each property. Properties that are 100% present (always filled) are excluded to focus on informative variation.
Known limitations: Completeness is based on property presence, not quality or accuracy of the data. Properties always present (100%) are excluded from the calculation. The property list is defined externally and may not capture all relevant metadata.
Total AOPs in latest graph
SELECT ?graph (COUNT(DISTINCT ?aop) AS ?total_aops)
WHERE {
GRAPH ?graph { ?aop a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph) LIMIT 1
Count AOPs per property in latest graph
SELECT DISTINCT ?p (COUNT(DISTINCT ?aop) AS ?n)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
?p ?o .
}
}
GROUP BY ?p
AOP Completeness by OECD Status
Comparison of AOP completeness scores across OECD status categories (Endorsed, Under Review, Under Development) grouped by property type: Essential (Title, Abstract, Description), Content (Key Events, Relationships, Stressors), Context (Applicability domains), Assessment (Evidence, Plausibility), and Metadata (Dates, Identifiers).
Methodology
What this measures: Compares AOP completeness scores across OECD approval status categories (e.g., Endorsed, Under Review, Under Development). Reveals whether more mature AOPs tend to be better documented. Properties are grouped into categories: Essential, Content, Context, Assessment, and Metadata.
Data source: Combines AOP completeness data with OECD status information. SPARQL queries retrieve both property presence counts and the OECD status for each AOP. Status is determined via the NCI Thesaurus OECD status URI (http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688).
Known limitations: OECD status data is version-specific and may change between releases. Some AOPs may lack a status annotation. Properties always present (100%) are excluded from completeness calculation. Status categories reflect the OECD approval pipeline stages present in the data.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
AOPs with each property, grouped by OECD status
SELECT ?status ?p (COUNT(DISTINCT ?aop) AS ?count_with_property)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
?aop ?p ?o .
}
}
GROUP BY ?status ?p
Total AOPs per OECD status (denominator)
SELECT ?status (COUNT(DISTINCT ?aop) AS ?total_aops)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
}
}
GROUP BY ?status
Show property details
KE Completeness by AOP OECD Status
Completeness of Key Events based on the OECD status of AOPs they belong to. KEs belonging to multiple AOPs with different statuses are counted for each status. Property types: Essential (Title, Description), Content (Biological components), Context (Applicability), Assessment (Evidence, Measurement), and Metadata (Dates, Links).
Methodology
What this measures: Measures completeness of Key Events based on the OECD status of the AOPs they belong to. KEs linked to multiple AOPs with different statuses are counted for each status. Property categories include Essential (Title, Description), Content (Biological components), Context (Applicability), Assessment (Evidence), and Metadata.
Data source: SPARQL queries join KE property presence data with AOP status information via the aopo:has_key_event relationship. Each KE inherits the status of its parent AOP(s).
Known limitations: A KE belonging to multiple AOPs with different OECD statuses will appear in each status group, potentially inflating counts. KEs not linked to any AOP are excluded. Properties always present are excluded from completeness scores.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
KEs with each property, grouped by parent AOP OECD status
SELECT ?status ?p (COUNT(DISTINCT ?ke) AS ?count_with_property)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
?ke a aopo:KeyEvent ;
?p ?o .
}
}
GROUP BY ?status ?p
Total KEs per OECD status (denominator)
SELECT ?status (COUNT(DISTINCT ?ke) AS ?total_kes)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
}
}
GROUP BY ?status
Show property details
KER Completeness by AOP OECD Status
Completeness of Key Event Relationships based on the OECD status of AOPs they belong to. KERs belonging to multiple AOPs with different statuses are counted for each status. Property types: Essential (Title, Description), Content (Upstream/Downstream KEs), Context (Applicability, Evidence type), and Metadata (Dates, Links).
Methodology
What this measures: Measures completeness of Key Event Relationships based on the OECD status of the AOPs they belong to. KERs linked to multiple AOPs with different statuses are counted for each status. Property categories include Essential, Content, Context, and Metadata.
Data source: SPARQL queries join KER property presence data with AOP status information via the aopo:has_key_event_relationship predicate. Each KER inherits the status of its parent AOP(s).
Known limitations: A KER belonging to multiple AOPs with different OECD statuses will appear in each status group. KERs not linked to any AOP are excluded. Properties always present are excluded from completeness scores.
Identify latest graph (AOP anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
KERs with each property, grouped by parent AOP OECD status
SELECT ?status ?p (COUNT(DISTINCT ?ker) AS ?count_with_property)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event_relationship ?ker .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
?ker a aopo:KeyEventRelationship ;
?p ?o .
}
}
GROUP BY ?status ?p
Total KERs per OECD status (denominator)
SELECT ?status (COUNT(DISTINCT ?ker) AS ?total_kers)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event_relationship ?ker .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
BIND(STR(?status_obj) AS ?status)
}
}
}
GROUP BY ?status
Show property details
Biological Process Usage
Distribution of biological process ontology terms used in Key Event annotations.
Methodology
What this measures: Shows the distribution of biological process ontology terms used in Key Event annotations. Identifies which ontologies (e.g., GO, MESH, NCIT) are most commonly referenced for describing biological processes in KE component annotations.
Data source: A SPARQL query retrieves biological process URIs reached from Key Events via the aopo:hasBiologicalEvent → aopo:hasProcess path, then groups them by their ontology source namespace.
Known limitations: Only covers processes explicitly annotated in the RDF data. Ontology classification is based on URI prefix patterns. Some processes may be classified differently across ontologies.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Distribution of biological-process terms by ontology source
SELECT ?ontology (COUNT(DISTINCT ?process) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
?bioevent aopo:hasProcess ?process .
BIND(
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/GO_"), "GO",
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/MP_"), "MP",
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/NBO_"), "NBO",
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/MI_"), "MI",
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/VT_"), "VT",
IF(STRSTARTS(STR(?process), "http://purl.org/commons/record/mesh/"), "MESH",
IF(STRSTARTS(STR(?process), "http://purl.obolibrary.org/obo/HP_"), "HP", "OTHER"))))))) AS ?ontology)
}
}
GROUP BY ?ontology
Biological Object Usage
Distribution of biological object ontology terms used in Key Event annotations.
Methodology
What this measures: Shows the distribution of biological object ontology terms used in Key Event annotations. Identifies which ontologies are most commonly referenced for describing biological objects (molecules, genes, proteins, etc.) in KE component annotations.
Data source: A SPARQL query retrieves biological object URIs reached from Key Events via the aopo:hasBiologicalEvent → aopo:hasObject path, then groups them by their ontology source namespace.
Known limitations: Only covers objects explicitly annotated in the RDF data. Ontology classification is based on URI prefix patterns. Multiple ontology terms may refer to the same biological entity.
Identify latest graph (KE anchor)
SELECT ?graph
WHERE {
GRAPH ?graph { ?s a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY DESC(?graph)
LIMIT 1
Distribution of biological-object terms by ontology source
SELECT ?ontology (COUNT(DISTINCT ?object) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
?bioevent aopo:hasObject ?object .
BIND(
IF(STRSTARTS(STR(?object), "http://purl.obolibrary.org/obo/CL_"), "CL",
IF(STRSTARTS(STR(?object), "http://purl.obolibrary.org/obo/UBERON_"), "UBERON",
IF(STRSTARTS(STR(?object), "http://purl.obolibrary.org/obo/CHEBI_"), "ChEBI",
IF(STRSTARTS(STR(?object), "http://purl.obolibrary.org/obo/GO_"), "GO",
IF(STRSTARTS(STR(?object), "http://purl.obolibrary.org/obo/PR_"), "PR", "OTHER"))))) AS ?ontology)
}
}
GROUP BY ?ontology