About this page
Evolution and growth patterns of the AOP-Wiki database over time, using quarterly releases. Toggle the global Delta Mode button at the top to switch every plot between absolute counts and per-version deltas, or use the per-plot checkbox. Use the Range selectors to constrain every snapshot-keyed plot to a sub-window; CSV/PNG/SVG downloads and the methodology "Run on Endpoint" queries honour the same window. Lifetime / creation-date plots are not affected by the range selector β their x-axis is creation year, not snapshot date.
Main Entity Trends
AOP Entity Counts
Tracks the total number of AOPs, Key Events (KEs), Key Event Relationships (KERs), and Stressors over time.
Methodology
What this measures: Tracks the total number of AOPs, Key Events (KEs), Key Event Relationships (KERs), and Stressors across all available database versions. Shows how the knowledge base has grown over time through quarterly RDF releases.
Data source: Four separate SPARQL queries count instances of each entity class (aopo:AdverseOutcomePathway, aopo:KeyEvent, aopo:KeyEventRelationship, nci:C54571) across all named graph versions. Results are merged into a unified time series.
Known limitations: Data reflects the RDF transformation, not the raw AOP-Wiki database. Entity counts include all instances regardless of completeness or quality. Some versions may have data quality variations due to changes in the RDF conversion pipeline. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph (COUNT(?aop) AS ?count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
}
}
GROUP BY ?graph
ORDER BY ?graph
AOP Property Presence Over Time
Shows how many AOPs contain each property over time. Properties always present (100%) are excluded for clarity.
Methodology
What this measures: Tracks which metadata properties are present in AOPs over time. Shows absolute counts of AOPs containing each property per version. Properties that are always 100% present are excluded to highlight meaningful variation in documentation completeness.
Data source: Properties are defined in property_labels.csv. For each version, SPARQL queries check how many AOPs have each property present. Uses CSV-based property loading and GROUP_CONCAT aggregation for efficiency.
Known limitations: Properties always present (100%) are excluded for clarity. Measures presence only, not quality of property values. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
Count AOPs with each property, per version
SELECT ?graph ?p (COUNT(DISTINCT ?AOP) AS ?count)
WHERE {
GRAPH ?graph {
?AOP a aopo:AdverseOutcomePathway ;
?p ?o .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?p
ORDER BY ?graph ?p
Total AOPs per version (denominator for percentage view)
SELECT ?graph (COUNT(DISTINCT ?AOP) AS ?total)
WHERE {
GRAPH ?graph { ?AOP a aopo:AdverseOutcomePathway . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Key Event Property Presence Over Time
Tracks which metadata properties are present in Key Events over time. Identifies completeness patterns and annotation trends. Uses marker shapes for visual distinction.
Methodology
What this measures: Tracks which metadata properties are present in Key Events over time. Identifies completeness patterns and annotation trends. Uses marker shapes for visual distinction between property lines.
Data source: Properties are defined in property_labels.csv filtered for KE entity type. SPARQL queries check property presence across all Key Events in each version using GROUP_CONCAT aggregation.
Known limitations: Properties always present (100%) are excluded for clarity. Measures presence of each property, not quality or accuracy of the values stored. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
Count KEs with each property, per version
SELECT ?graph ?p (COUNT(DISTINCT ?ke) AS ?count)
WHERE {
GRAPH ?graph {
?ke a aopo:KeyEvent ;
?p ?o .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?p
ORDER BY ?graph ?p
Total KEs per version (denominator for percentage view)
SELECT ?graph (COUNT(DISTINCT ?ke) AS ?total)
WHERE {
GRAPH ?graph { ?ke a aopo:KeyEvent . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Key Event Relationship Property Presence Over Time
Tracks which metadata properties are present in Key Event Relationships over time. Monitors evidence and annotation quality. Uses marker shapes for visual distinction.
Methodology
What this measures: Tracks which metadata properties are present in Key Event Relationships over time. Monitors evidence and annotation quality across versions. Uses marker shapes for visual distinction between property lines.
Data source: Properties are defined in property_labels.csv filtered for KER entity type. SPARQL queries check property presence across all KERs in each version using GROUP_CONCAT aggregation.
Known limitations: Properties always present (100%) are excluded for clarity. Measures presence of each property, not the strength or quality of evidence recorded. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
Count KERs with each property, per version
SELECT ?graph ?p (COUNT(DISTINCT ?ker) AS ?count)
WHERE {
GRAPH ?graph {
?ker a aopo:KeyEventRelationship ;
?p ?o .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?p
ORDER BY ?graph ?p
Total KERs per version (denominator for percentage view)
SELECT ?graph (COUNT(DISTINCT ?ker) AS ?total)
WHERE {
GRAPH ?graph { ?ker a aopo:KeyEventRelationship . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Stressor Property Presence Over Time
Tracks which metadata properties are present in Stressors over time. Identifies documentation patterns and completeness trends. Uses marker shapes for visual distinction.
Methodology
What this measures: Tracks which metadata properties are present in Stressors over time. Identifies documentation patterns and completeness trends for stressor entities. Uses marker shapes for visual distinction.
Data source: Properties are defined in property_labels.csv filtered for Stressor entity type. SPARQL queries check property presence across all Stressors in each version using GROUP_CONCAT aggregation.
Known limitations: Properties always present (100%) are excluded for clarity. Stressors are identified by the NCI Thesaurus type (nci:C54571), which may not capture all stressor-related entities in the knowledge base. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
Count Stressors with each property, per version
SELECT ?graph ?p (COUNT(DISTINCT ?s) AS ?count)
WHERE {
GRAPH ?graph {
?s a nci:C54571 ;
?p ?o .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?p
ORDER BY ?graph ?p
Total Stressors per version (denominator for percentage view)
SELECT ?graph (COUNT(DISTINCT ?s) AS ?total)
WHERE {
GRAPH ?graph { ?s a nci:C54571 . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Entity Completeness Trends
Average Entity Completeness Over Time
Shows the average completeness percentage for AOPs, Key Events, Key Event Relationships, and Stressors over time. Excludes properties that are 100% present (always filled in) to focus on optional properties that reflect data richness. Completeness is calculated as the percentage of non-ubiquitous properties each entity has filled in, then averaged across all entities of that type in each version.
Methodology
What this measures: Shows the average completeness percentage for AOPs, Key Events, Key Event Relationships, and Stressors over time. Completeness is the fraction of non-ubiquitous properties each entity has filled in, averaged across all entities of that type per version.
Data source: For each of AOP, KE, KER, and Stressor, three SPARQL queries run: (1) total entities per version, (2) property-presence counts per version (used to drop properties that hit 100% in any version), (3) per-entity property counts using the filtered URI list. The disclosed queries show the AOP variant; the plot loops over all four entity types in Python, substituting the entity's RDF type and property list from property_labels.csv before each round-trip. Per-entity completeness is computed in Python as prop_count / total_filtered_properties; the chart shows the mean per version, with one line per entity type.
Known limitations: Excludes properties that are 100% present (always filled in) to focus on optional properties reflecting data richness. Averages can mask bimodal distributions where some entities are very complete and others are very sparse. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
Total entities per version (denominator) β shown for AOP; plot also runs against KE, KER, Stressor
SELECT ?graph (COUNT(DISTINCT ?aop) AS ?total)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Property-presence counts per version (used to drop properties that hit 100% in any version)
SELECT ?graph ?p (COUNT(DISTINCT ?aop) AS ?count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway ;
?p ?o .
FILTER(?p IN (
<http://purl.org/dc/elements/1.1/title>,
<http://purl.org/dc/terms/abstract>,
<http://aopkb.org/aop_ontology#has_key_event>,
<http://aopkb.org/aop_ontology#has_adverse_outcome>
))
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?p
ORDER BY ?graph ?p
Per-entity property counts (numerator for completeness)
SELECT ?graph ?aop (COUNT(DISTINCT ?p) AS ?prop_count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway ;
?p ?o .
FILTER(?p IN (
<http://purl.org/dc/elements/1.1/title>,
<http://purl.org/dc/terms/abstract>,
<http://aopkb.org/aop_ontology#has_key_event>,
<http://aopkb.org/aop_ontology#has_adverse_outcome>
))
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?aop
ORDER BY ?graph ?aop
Composite AOP Completeness Distribution Over Time
Distribution of composite completeness scores per AOP per snapshot. Each AOP's score is the flat average of its own property completeness with the completeness of every linked Key Event and Key Event Relationship β so large networks are dominated by their KE/KER averages. Box = Q1 / median / Q3, whiskers = 1.5ΓIQR, points = outliers. Two cohorts side-by-side: the Optional-only view (left) excludes any property that hits 100% presence in any snapshot β the discriminating signal of curator effort on truly optional fields; the All-properties view (right) uses the full denominator and reads higher because mandatory fields are always in the numerator.
Methodology
What this measures: Distribution of composite completeness scores per AOP per snapshot. Each AOP's score is the flat average of its own property completeness with the completeness of every linked Key Event and Key Event Relationship β large networks are dominated by their KE/KER averages. The view is shown in two cohorts side-by-side: 'Optional properties only' (left) excludes any property that reaches 100% presence in any snapshot β removing mandatory wiki-form fields that don't discriminate between curated and abandoned AOPs; 'All properties' (right) uses the full denominator and necessarily reads higher because mandatory fields are always present. The downloaded CSV/PNG/SVG matches whichever cohort's Download button you click.
Data source: For each snapshot, three SPARQL queries are issued in parallel: (1) entity totals for AOPs, KEs, and KERs; (2) property presence counts per entity type filtered by the property URIs in property_labels.csv; (3) the AOPβKE and AOPβKER network structure. Python post-processing then drops properties that reach 100% presence in any version (focus on optional properties), computes each AOP's own completeness against the surviving AOP property set, averages the completeness of its linked KEs and KERs, and combines the three into a flat-average composite score per AOP.
Known limitations: Composite scores weight AOP, KE, and KER completeness equally. The 'Optional properties only' cohort drops a property as soon as it hits 100% presence in any single snapshot in the history β so a property that was once mandatory and has since drifted lower is still excluded. The 'All properties' cohort avoids that asymmetry but reads higher because mandatory fields are uniformly in the numerator. Box plots show quartiles (Q1, median, Q3) with whiskers at 1.5x IQR. AOPs with no linked KEs or KERs fall back to their own completeness only β those often appear as high outliers. The disclosed queries below show the filter the code builds at runtime; substitute your own property URI list when running them outside the app.
Per-version entity totals (AOP, KE, KER) β issued once per snapshot
SELECT ?entity_type (COUNT(DISTINCT ?entity) AS ?total)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
{ ?entity a aopo:AdverseOutcomePathway . BIND("AOP" AS ?entity_type) }
UNION
{ ?entity a aopo:KeyEvent . BIND("KE" AS ?entity_type) }
UNION
{ ?entity a aopo:KeyEventRelationship . BIND("KER" AS ?entity_type) }
}
}
GROUP BY ?entity_type
Per-version property presence per entity type β ?p restricted to property_labels.csv URIs (substitute your own list)
SELECT ?entity_type ?p (COUNT(DISTINCT ?entity) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
{ ?entity a aopo:AdverseOutcomePathway ; ?p ?o . BIND("AOP" AS ?entity_type) }
UNION
{ ?entity a aopo:KeyEvent ; ?p ?o . BIND("KE" AS ?entity_type) }
UNION
{ ?entity a aopo:KeyEventRelationship ; ?p ?o . BIND("KER" AS ?entity_type) }
FILTER(?p IN (<http://purl.org/dc/elements/1.1/title>, <http://purl.org/dc/elements/1.1/creator>))
}
}
GROUP BY ?entity_type ?p
Per-version AOPβKE / AOPβKER network structure β used to weight linked-entity completeness
SELECT ?aop
(GROUP_CONCAT(DISTINCT ?ke; separator="|") AS ?kes)
(GROUP_CONCAT(DISTINCT ?ker; separator="|") AS ?kers)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL { ?aop aopo:has_key_event ?ke }
OPTIONAL { ?aop aopo:has_key_event_relationship ?ker }
}
}
GROUP BY ?aop
Optional properties only
All properties
Mean AOP Completeness by OECD Status Over Time
Shows the mean completeness score per OECD approval status over time. Tracks how documentation quality correlates with maturity level across database versions. Each line represents a different OECD status (e.g., Endorsed, Approved, Under Review, Under Development), with higher completeness indicating more thoroughly documented AOPs in that category.
Methodology
What this measures: Tracks the mean completeness percentage per OECD approval status category across database versions. Shows how documentation quality correlates with the approval pipeline stage over time.
Data source: Combines AOP completeness data with OECD status annotations. For each version and status, calculates the average completeness across all AOPs in that status category.
Known limitations: OECD status data is version-specific and may change between releases. Status categories depend on what is present in the data. Some AOPs may lack status annotations and are excluded from this analysis. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph ?aop (STR(?status_obj) AS ?status)
(COUNT(DISTINCT ?p) AS ?prop_count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?status_obj .
}
?aop ?p ?o .
FILTER(?p IN (
<http://aopkb.org/aop_ontology#AopContext>,
<http://aopkb.org/aop_ontology#LifeStageContext>,
<http://aopkb.org/aop_ontology#has_adverse_outcome>,
<http://aopkb.org/aop_ontology#has_evidence>,
<http://aopkb.org/aop_ontology#has_key_event>,
<http://aopkb.org/aop_ontology#has_key_event_relationship>,
<http://aopkb.org/aop_ontology#has_molecular_initiating_event>,
<http://edamontology.org/operation_3799>,
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25217>,
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688>,
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25725>,
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C48192>,
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C54571>,
<http://purl.bioontology.org/ontology/NCBITAXON/131567>,
<http://purl.obolibrary.org/obo/PATO_0000047>,
<http://purl.org/dc/elements/1.1/creator>,
<http://purl.org/dc/elements/1.1/description>,
<http://purl.org/dc/elements/1.1/identifier>,
<http://purl.org/dc/elements/1.1/title>,
<http://purl.org/dc/terms/abstract>,
<http://purl.org/dc/terms/alternative>,
<http://purl.org/dc/terms/created>,
<http://purl.org/dc/terms/isPartOf>,
<http://purl.org/dc/terms/modified>,
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>,
<http://www.w3.org/2000/01/rdf-schema#label>,
<http://www.w3.org/2000/01/rdf-schema#seeAlso>,
<http://xmlns.com/foaf/0.1/page>
))
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?aop ?status_obj
OECD Status Distribution Over Time
How the OECD-status mix of AOP-Wiki has evolved β fraction of AOPs in each OECD status (No Status, Under Development, Under Review, WPHA/WNT Endorsed, etc.) per snapshot. Answers "is AOP-Wiki maturing or accumulating drafts?" Companion to the OECD-completeness plot above, which measures average completeness per status.
Methodology
What this measures: Per-version count of AOPs in each OECD status. Companion to the OECD completeness trend above β that view measures *quality* per status; this view measures *mix*. Reveals whether AOP-Wiki is maturing (more endorsed/approved AOPs) or accumulating drafts. Absolute mode shows raw counts; the percentage toggle shows the share of each status in the snapshot total.
Data source: One per-version SPARQL aggregation. The status predicate is the NCI Thesaurus term `<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688>` (same predicate used by the OECD completeness trend). AOPs without the predicate are bucketed as `No Status` via a COALESCE binding so they remain visible in the chart.
Known limitations: Some historical status labels (e.g. `EAGMST Approved`, `Archived`) only appear in earlier snapshots; they are kept on the chart with their own colour so the historical sequence is faithful. `No Status` is a heterogeneous bucket β it includes both AOPs that have never been submitted to OECD and AOPs whose status triple was lost during a curation cleanup. Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT ?graph ?status_str (COUNT(DISTINCT ?aop) AS ?n_aops)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL {
?aop <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C25688> ?s .
}
BIND(COALESCE(STR(?s), "No Status") AS ?status_str)
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?status_str
Coverage Growth
How the database's reach is broadening (more stressors, more KE annotations, more organ systems) and where the gaps remain. Complements the completeness view above: completeness asks "are existing records well-filled-in?", coverage asks "what does the corpus span?".
Stressor Coverage Growth
Distinct stressors (`nci:C54571`) over time. Isolated from the AOP Entity Counts plot for focused download. Pair with the AOPs-per-stressor distribution next to it to distinguish broadening (more stressors) from deepening (same stressors, more AOPs).
Methodology
What this measures: Per-version count of distinct stressors typed `nci:C54571`. Same numbers as the Stressors trace of the headline AOP Entity Counts plot, isolated so it can be downloaded, methodology-cited, and toggled to a Ξ view on its own. Best read alongside the AOPs-per-stressor distribution to distinguish *broadening* (new stressors) from *deepening* (same stressors, more AOPs).
Data source: One COUNT-per-graph aggregation. The Ξ view is computed in Python from the absolute counts (pandas diff).
Known limitations: Counts the distinct stressor URIs of class `nci:C54571` regardless of whether they are linked to any AOP. A stressor may exist in the RDF without yet being attached to an AOP. Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT ?graph (COUNT(DISTINCT ?s) AS ?n_stressors)
WHERE {
GRAPH ?graph { ?s a <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C54571> . }
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
AOPs per Stressor Distribution
Stressors bucketed by how many AOPs reference them: 1 AOP, 2 AOPs, 3-5, 6-10, 11+. Reveals whether the stressor coverage is broadening (most stressors appear in 1 AOP) or deepening (a few popular stressors carry many AOPs).
Methodology
What this measures: Per snapshot, stressors bucketed by how many AOPs reference them: {1 AOP, 2 AOPs, 3-5, 6-10, 11+}. The stacked-area view reveals whether AOP-Wiki is broadening (most stressors used in 1 AOP each) or deepening (a few popular stressors carry many AOPs). Latest snapshot has ~74% of stressors in just one AOP β coverage is currently broad and shallow.
Data source: One per-version GROUP BY aggregation returning (graph, stressor URI, #AOPs referencing it). Bucketing is applied in Python. The percentage view normalises against the total number of stressors in that snapshot.
Known limitations: Only counts AOPβstressor edges via the `nci:C54571` predicate (the AOP-Wiki RDF uses the same URI for both the class and the linking predicate β unusual modelling but consistent). Stressors not yet attached to any AOP do not appear in this view (use the Stressor Coverage Growth plot for total counts).
View SPARQL Query
SELECT ?graph ?stressor (COUNT(DISTINCT ?aop) AS ?aop_count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway ;
<http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C54571> ?stressor .
?stressor a <http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C54571> .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?stressor
KE Measurement-Method Coverage Over Time
Historical trend of KE measurement-method coverage (companion to the latest-snapshot
donut on the snapshot page). Tracks the percentage of Key Events carrying an
obo:MMO_0000000 assay description over time β a key signal for
NAM-readiness.
Methodology
What this measures: Per-version share of Key Events that carry an `obo:MMO_0000000` description β the predicate AOP-Wiki uses for free-text measurement-method / assay text. Currently only ~37% of KEs have one; the gap is the largest single completeness signal for NAM-ready AOPs. Companion to the snapshot donut on the Latest page.
Data source: One per-version aggregation. `SUM(IF(BOUND(?mmo), 1, 0))` counts KEs with at least one MMO triple; `COUNT(?ke)` is the denominator. Percentage = with / total Γ 100.
Known limitations: Measures presence, not quality β a KE with a one-character MMO string and a KE with a full assay paragraph both count as `with MMO`. Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT ?graph
(SUM(IF(BOUND(?mmo), 1, 0)) AS ?with_mmo)
(COUNT(?ke) AS ?total)
WHERE {
GRAPH ?graph {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke <http://purl.obolibrary.org/obo/MMO_0000000> ?mmo }
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
KE Migration Map
Heatmap of the top 50 most-mobile Key Events across all quarterly snapshots. X-axis is the snapshot date; Y-axis is the KE; cell colour encodes how many AOPs that KE was in at that quarter. Empty cells mean the KE was absent. Reveals KEs that were first introduced, removed, merged, or jumped between AOPs β the single most uniquely multi-endpoint-enabled view (no other AOP-Wiki tool has the versioned graph history to produce it).
Methodology
What this measures: Across all quarterly snapshots, tracks how each KE's AOP membership evolved. Rendered as a heatmap: Y-axis = top 50 most-mobile KEs (scored as `snapshots_present Γ peak_aop_count`), X-axis = snapshot date, cell colour = #AOPs the KE was in at that quarter, empty cells = KE absent. Surfaces KEs that were first introduced, removed, merged, or jumped between AOPs over time.
Data source: Two SPARQL calls: (1) a per-graph aggregation returning (graph, KE, #AOPs containing it) β ~41K rows across 32 snapshots β which drives the heatmap; (2) a latest-snapshot lookup of KE titles for the y-axis labels (production restricts it to the rendered top-50 KEs via a VALUES block). Mobility score is computed in Python; the top 50 KEs by score are rendered. The CSV download contains the full top-50 timeline (1591 rows: KEs Γ snapshots in which they appear).
Known limitations: The Sankey rendering the original issue proposed is unreadable at 50 KEs Γ 32 snapshots Γ ~500 AOPs (a true Sankey would have thousands of nodes); the heatmap conveys the same per-KE journey signal without the visual collapse. The mobility score is editorial β a single-AOP KE present in every snapshot ranks below a 2-AOP KE present in every snapshot. Empty cells encode either KE absence OR KE present but in zero AOPs (impossible by construction β every KE in the AOP-Wiki RDF is in at least one AOP), so empty = absent.
Per-snapshot KE β AOP membership (drives the heatmap)
SELECT ?graph ?ke (COUNT(DISTINCT ?aop) AS ?n_aops)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?ke
KE titles for the y-axis labels (latest snapshot)
SELECT ?ke ?title
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke <http://purl.org/dc/elements/1.1/title> ?title }
}
}
Organ-System Coverage of AOPs over Time
Number of AOPs classified into each of 13 organ-system buckets at every quarterly snapshot.
Toggle to switch to a percentage view β each line as a share of the total AOPs in that snapshot.
Combines Signals A (curated aopo:OrganContext / aopo:CellTypeContext),
A′ (aopo:hasObject UBERON/CL) and B (GO biological-process bridge).
Signal C (keywords) is excluded from the trend view.
Methodology
What this measures: Number of AOPs classified into each of 13 organ-system buckets at every quarterly snapshot. Toggle 'Show Percentage' to switch to a per-snapshot normalised view. Combines structured-anatomy signals A and A' (UBERON / CL) with Signal B (Process / phenotype β GO BP via RO:0002296, plus HP and MP via UPHENO:0000001). Signal C (keywords) is excluded from the longitudinal view because keyword behaviour tracks title-editing more than coverage growth.
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: Same caveats as the snapshot views, applied per snapshot. Pre-2020 snapshots have very sparse OrganContext / CellTypeContext annotations β early values should not be read as 'zero biological coverage', only as 'zero structured anatomy coverage at that time'. The percentage view normalises by total AOPs per snapshot, so growth that lags AOP count growth shows as a flat or declining line even when the absolute number rises.
Browse full curated mapping (JSON)
Per-snapshot consolidated query (all signals)
SELECT ?aop ?organ ?cell ?obj ?proc
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke .
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_") )
}
}
AOP Connectivity and Network Structure
Average KEs and KERs per AOP
Shows how densely connected each AOP is on average, measured by the number of Key Events and Key Event Relationships per AOP.
Methodology
What this measures: Tracks how densely connected each AOP is on average over time, measured by the number of Key Events and Key Event Relationships per AOP in each version. Indicates whether newer AOPs tend to be more or less complex.
Data source: SPARQL queries count total AOP, KE-to-AOP, and KER-to-AOP relationships across all versions, then compute the ratio per version.
Known limitations: Averages can be dominated by a few very large or very small AOPs. Does not distinguish between well-developed and stub AOPs. Only counts explicitly declared relationships. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph
(COUNT(DISTINCT ?aop) AS ?aop_count)
(COUNT(?ke) AS ?ke_count)
(COUNT(?ker) AS ?ker_count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL { ?aop aopo:has_key_event ?ke . }
OPTIONAL { ?aop aopo:has_key_event_relationship ?ker . }
}
}
GROUP BY ?graph
ORDER BY ?graph
AOP Network Density
Shows how densely connected the KE-KER graph is over time, calculated as the ratio of edges to possible connections between nodes.
Methodology
What this measures: Measures how densely connected the KE-KER graph is over time. Network density is the ratio of actual edges (KERs) to the maximum possible edges between KE nodes, showing whether the knowledge base is becoming more interconnected.
Data source: SPARQL queries count unique Key Events (nodes) and Key Event Relationships (edges) per version. Density = edges / (nodes * (nodes - 1) / 2) for an undirected graph interpretation.
Known limitations: Network density depends on explicitly declared KE-KER relationships in the RDF data. Adding many new KEs without corresponding KERs will decrease density. The metric is sensitive to the number of isolated or poorly connected nodes. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph (COUNT(DISTINCT ?ke) AS ?nodes) (COUNT(?ker) AS ?edges)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway ;
aopo:has_key_event ?ke ;
aopo:has_key_event_relationship ?ker .
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph
ORDER BY ?graph
Authors and AOP Lifetime
Authors of AOPs
Tracks the number of unique authors contributing to AOPs over time.
Methodology
What this measures: Tracks the number of unique authors contributing to AOPs over time. Shows how the contributor base has grown across database versions.
Data source: SPARQL queries count distinct dc:creator URIs across all AOPs per version. Each unique creator URI is counted once per version.
Known limitations: Author counts are based on unique dc:creator URIs and may not match AOP-Wiki user accounts exactly. Co-authorship is counted per unique URI. Authors who contribute to non-AOP entities are not included. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph (COUNT(DISTINCT ?author) AS ?count)
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
?aop dc:creator ?author .
}
}
GROUP BY ?graph
ORDER BY ?graph
AOPs Created Over Time
Number of unique AOPs first created in each year.
Methodology
What this measures: Visualizes temporal patterns of AOP creation and modification. Includes three views: (1) number of AOPs created per year, (2) number of AOPs last modified per year, and (3) a scatter plot of creation date vs. last modification date for each AOP.
Data source: SPARQL queries retrieve dc:date (creation) and dcterms:modified (last modification) timestamps for all AOPs in the latest version. Dates are parsed and grouped by year for the histogram views.
Known limitations: Creation and modification dates reflect what is stored in the RDF data, which may differ from the AOP-Wiki web interface timestamps. Some AOPs may have missing or malformed date values. Only the latest version's date information is used. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?aop ?created ?modified
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL { ?aop dc:date ?created . }
OPTIONAL { ?aop dcterms:modified ?modified . }
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
ORDER BY DESC(?graph)
AOP Creation vs Modification
Scatter plot showing when each AOP was created versus when it was last updated.
Methodology
What this measures: Visualizes temporal patterns of AOP creation and modification. Includes three views: (1) number of AOPs created per year, (2) number of AOPs last modified per year, and (3) a scatter plot of creation date vs. last modification date for each AOP.
Data source: SPARQL queries retrieve dc:date (creation) and dcterms:modified (last modification) timestamps for all AOPs in the latest version. Dates are parsed and grouped by year for the histogram views.
Known limitations: Creation and modification dates reflect what is stored in the RDF data, which may differ from the AOP-Wiki web interface timestamps. Some AOPs may have missing or malformed date values. Only the latest version's date information is used. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?aop ?created ?modified
WHERE {
GRAPH ?graph {
?aop a aopo:AdverseOutcomePathway .
OPTIONAL { ?aop dc:date ?created . }
OPTIONAL { ?aop dcterms:modified ?modified . }
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
ORDER BY DESC(?graph)
KE Component & Annotation Trends
KE Component Annotations
Tracks how many Key Event annotations include Process, Object, and Action elements over time.
Methodology
What this measures: Tracks how many Key Event annotations include Process, Object, and Action elements over time. Shows the absolute number of each component type across database versions.
Data source: Per-version parallel SPARQL queries count Key Events that reach process, object, and action annotations via the aopo:hasBiologicalEvent hop (?ke aopo:hasBiologicalEvent ?ev . ?ev aopo:hasProcess|hasObject|hasAction ?term). Totals represent the number of KE-to-component relationships per version graph.
Known limitations: Counts the number of annotations, not unique terms. A KE with multiple process annotations contributes multiple counts. Growth in annotations may reflect both new KEs and enrichment of existing ones. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT
(COUNT(?process) AS ?process_count)
(COUNT(?object) AS ?object_count)
(COUNT(?action) AS ?action_count)
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 Components as % of Total KEs
Shows how many Key Events have Process, Object, and Action annotations as a percentage of all KEs per version.
Methodology
What this measures: Shows how many Key Events have Process, Object, and Action annotations as a percentage of all KEs per version. Normalizes for growth in total KE count to reveal annotation coverage trends.
Data source: Uses the same SPARQL query as KE Component Annotations, but divides each component count by the total KE count per version to produce percentages.
Known limitations: Percentage calculations assume consistent definition of what constitutes a KE across versions. Changes in RDF conversion methodology could affect comparability between versions. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT
(COUNT(?process) AS ?process_count)
(COUNT(?object) AS ?object_count)
(COUNT(?action) AS ?action_count)
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 . }
}
}
Unique KE Component Annotations
Tracks the total number of unique Process, Object, and Action annotations used in Key Events over time.
Methodology
What this measures: Tracks the total number of unique (distinct) Process, Object, and Action annotations used in Key Events over time. Unlike the component count, this measures the vocabulary diversity of annotations.
Data source: SPARQL queries count distinct URIs for each component type (biological processes, objects, actions) across all KEs per version.
Known limitations: Unique counts are based on distinct URIs, so the same biological concept referenced by different ontology URIs would be counted separately. Does not measure the frequency of use for each unique term. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT
(COUNT(DISTINCT ?process) AS ?process_count)
(COUNT(DISTINCT ?object) AS ?object_count)
(COUNT(DISTINCT ?action) AS ?action_count)
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 . }
}
}
Biological Process Annotations
Shows KE annotations with biological processes grouped by ontology.
Methodology
What this measures: Tracks KE annotations with biological processes and objects grouped by ontology source. Shows which ontologies (GO, MESH, NCIT, etc.) are most commonly used for annotating Key Events over time.
Data source: SPARQL queries retrieve all biological process and object URIs from KE annotations, classify them by ontology namespace prefix, and count occurrences per version.
Known limitations: Ontology classification is based on URI prefix pattern matching. Some URIs may not match known prefixes and would be classified as 'Other'. Does not measure the quality or specificity of ontology term usage. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?process (COUNT(?process) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
?bioevent aopo:hasProcess ?process .
}
}
GROUP BY ?process
Biological Object Annotations
Shows KE annotations with biological objects grouped by ontology.
Methodology
What this measures: Tracks KE annotations with biological processes and objects grouped by ontology source. Shows which ontologies (GO, MESH, NCIT, etc.) are most commonly used for annotating Key Events over time.
Data source: SPARQL queries retrieve all biological process and object URIs from KE annotations, classify them by ontology namespace prefix, and count occurrences per version.
Known limitations: Ontology classification is based on URI prefix pattern matching. Some URIs may not match known prefixes and would be classified as 'Other'. Does not measure the quality or specificity of ontology term usage. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?process (COUNT(?process) AS ?count)
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> {
?ke a aopo:KeyEvent ;
aopo:hasBiologicalEvent ?bioevent .
?bioevent aopo:hasProcess ?process .
}
}
GROUP BY ?process
KEs by Number of KECs
Tracks how many Key Events contain a specific number of Key Event Components (KECs) over time, showing annotation completeness.
Methodology
What this measures: Tracks how many Key Events contain a specific number of Key Event Components (0, 1, 2, or 3) over time. Reveals annotation completeness trends and whether the community is enriching existing KEs or primarily creating new ones.
Data source: A SPARQL query counts biological-event annotations per Key Event (?ke aopo:hasBiologicalEvent ?bioevent) using an inner subquery, then buckets KEs into groups by their bioevent count (0, 1, 2, 3, 4, 5, 6+) per version graph.
Known limitations: Only counts distinct component types (max 3: Process, Object, Action), not total annotations. A KE with multiple processes but no objects or actions would count as 1. Does not measure annotation quality. Trend data covers only the published RDF release versions available in the SPARQL endpoint; the AOP-Wiki knowledge base predates the earliest RDF release, so earlier activity is not captured.
View SPARQL Query
SELECT ?graph ?bioevent_count_group
(COUNT(DISTINCT ?ke) AS ?total_kes)
WHERE {
GRAPH ?graph {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke aopo:hasBiologicalEvent ?bioevent . }
{
SELECT ?ke (COUNT(DISTINCT ?bioevent2) AS ?bioevent_count)
WHERE {
?ke a aopo:KeyEvent .
OPTIONAL { ?ke aopo:hasBiologicalEvent ?bioevent2 . }
}
GROUP BY ?ke
}
BIND(
IF(?bioevent_count = 0, "0",
IF(?bioevent_count = 1, "1",
IF(?bioevent_count = 2, "2",
IF(?bioevent_count = 3, "3",
IF(?bioevent_count = 4, "4",
IF(?bioevent_count = 5, "5",
IF(?bioevent_count >= 6, "6+", ">1"))))))) AS ?bioevent_count_group
)
}
FILTER(STRSTARTS(STR(?graph), "http://aopwiki.org/graph/"))
}
GROUP BY ?graph ?bioevent_count_group
ORDER BY ?graph xsd:integer(?bioevent_count_group)
Ontology Term Growth
Tracks the number of unique ontology terms (GO, CHEBI, UBERON, etc.) used in Key Event annotations across versions. Growth indicates expanding annotation vocabulary.
Methodology
What this measures: Tracks the number of unique ontology terms used in biological process and object annotations across database versions. Growth indicates expanding annotation vocabulary and richer biological characterization.
Data source: Per-version parallel SPARQL queries count distinct IRI-valued terms reached from Key Events via the aopo:hasBiologicalEvent hop, taking the union of aopo:hasProcess and aopo:hasObject paths. Results are plotted as line chart (absolute) and bar chart (delta per version).
Known limitations: Counts unique term IRIs, not unique biological concepts (different IRIs may reference the same concept across ontologies). Only covers process and object annotations. Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT (COUNT(DISTINCT ?term) AS ?unique_terms)
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))
}
}
Database Churn
Entity Birth/Death Curve
Gross additions vs removals between adjacent snapshots β one panel per entity type. Additions sit above the zero line, removals below. A net delta of zero can still hide churn (e.g. five new KEs added while five existing KEs were merged or deprecated); this view exposes both flows. The CSV includes the URIs of every entity that was added or removed per quarter for curator follow-up.
Methodology
What this measures: Gross additions vs removals per snapshot transition, one panel per entity type. Additions appear above the zero line, removals below. The AOP Entity Counts plot above shows net change β a delta of zero can still hide significant churn (e.g. five new KEs added while five existing KEs were merged or deprecated). This view exposes both flows.
Data source: For each entity class (AOPs, KEs, KERs, Stressors), the distinct set of entity URIs is fetched per named graph using the query below; consecutive snapshots are then diffed in Python. `added` = present in v_curr but not v_prev, `removed` = present in v_prev but not v_curr. An equivalent endpoint-side computation would substitute two graph URIs into a `GRAPH <v_curr> { β¦ } MINUS { GRAPH <v_prev> { β¦ } }` pattern. The downloadable CSV preserves the actual added/removed URIs per quarter for curator follow-up.
Known limitations: Only entities present as `a aopo:AdverseOutcomePathway` / `aopo:KeyEvent` / `aopo:KeyEventRelationship` / `nci:C54571` are tracked. A URI changing identifier between versions (re-minted) will look like a removal + addition; merges or splits will look similar. The earliest snapshot has no predecessor and is therefore omitted. Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT DISTINCT ?e
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> { ?e a aopo:KeyEvent . }
}
Cumulative Removed Entities
Running graveyard view β for each snapshot, the count of entities that appeared in any earlier snapshot but are absent now. Companion to the birth/death curve above: that view shows per-quarter flow, this one shows accumulated stock. Re-additions decrement the line. The CSV lists every absent URI per snapshot so curators can audit deprecations.
Methodology
What this measures: For each snapshot N, the running count of entities that appeared in any earlier snapshot but are absent in N. One trace per entity type (AOPs, KEs, KERs, Stressors). Companion to the birth/death curve above: that plot shows per-quarter flow (births and deaths), this one shows the accumulated stock of attrition. A re-addition (URI absent in v_N but back in v_{N+1}) decrements the line.
Data source: The same per-graph entity URI fetch as Entity Birth/Death (the query below, run once per snapshot per entity class). For each entity type we then walk snapshots chronologically, maintain the running union of all URIs ever seen, and at each step count `(ever_seen_through_N) β URIs_in_N` β entities seen at any earlier point AND absent right now. The downloadable CSV lists every absent URI per snapshot.
Known limitations: Counts only entities typed as `a aopo:AdverseOutcomePathway` / `aopo:KeyEvent` / `aopo:KeyEventRelationship` / `nci:C54571`. A URI re-minted between snapshots will look like a removal even if the entity semantically still exists. The earliest snapshot is always 0 (nothing has been seen yet). Trend data covers only the published RDF release versions available in the SPARQL endpoint.
View SPARQL Query
SELECT DISTINCT ?e
WHERE {
GRAPH <http://aopwiki.org/graph/2026-04-01> { ?e a aopo:KeyEvent . }
}