Niagara
Niagara is a causal discovery method for interval-based event sequences. It models event starts, active intervals, and event ends, and selects causal mechanisms between events using a minimum-description-length score.
This repository contains the reusable implementation accompanying the AAAI 2026 paper Causal Discovery from Interval-Based Event Sequences (see citation below). Version 0.1.0 retains the behaviour of the implementation used for the experiments in the publication. The latest version is recommended for any further experimentation.
Installation
pip install niagara-cd
Five-minute example
Provide one row per event occurrence.
The columns are the event name, start time, and end time; an optional fourth column identifies a sequence.
Sequences are treated as independent timelines while sharing one fitted graph and set of distribution parameters; do not offset sequences to make their timestamps non-overlapping.
Times are elapsed values starting at 0 within each sequence, rather than absolute calendar dates.
Pass one horizon for equal-length recordings or a mapping such as {"Sydney": 24, "London": 12} for different lengths.
If omitted, each sequence's maximum recorded timestamp is used; provide it explicitly when observation continued silently after the final event.
import numpy as np
from niagara import fit
intervals = np.array(
[
["rain", 0.0, 2.0],
["traffic", 1.0, 3.0],
["rain", 5.0, 7.0],
["traffic", 6.0, 8.0],
],
dtype=object,
)
result = fit(intervals, horizon=10.0)
print(result.feature_names)
print(result.adjacency)
print(result.edges)
print(result.mechanisms)
This example produces an event-level edge from rain to traffic:
('rain', 'traffic')
[[0. 1.]
[0. 0.]]
The feature order gives the row and column labels of the adjacency matrix.
Rows are causes (parents), columns are effects (children), and a value of 1 at position [i, j] means feature_names[i] → feature_names[j].
Here, the value at row rain and column traffic is 1.
result.edges provides the same event-level result without requiring matrix indexing:
print(result.edges)
# (('rain', 'traffic'),)
To inspect whether the mechanism concerns an event starting, being ongoing, or ending, use result.mechanisms:
mechanism = result.mechanisms[0]
print(mechanism.parents)
# (Endpoint(event='rain', kind='interval'),)
print(mechanism.child)
# Endpoint(event='traffic', kind='start')
print(mechanism.operator)
# None
This means that rain being ongoing is selected as a cause of traffic starting.
Endpoint kinds are start, interval, and end.
For a logical mechanism with two parents, operator is and, or, or xor; it is None for a single-parent mechanism.
A Pandas DataFrame may be supplied instead when it has event, start, and end columns, plus an optional sequence column.
Rows are kept in their supplied order, and event names are preserved.
Public API
fit(data, *, horizon=None, feature_names=None, config=None) fits Niagara and returns a NiagaraResult.
NiagaraConfig controls exhaustive or partial search, the maximum error proportion, the OR heuristic, and MDL precision.
Defaults match the publication implementation.
Niagara discovers causes of event starts only. It does not search for causes of event ends because the causal-identifiability theory assumes exponential waiting-time distributions, whereas event durations are modeled with a log-normal distribution.
NiagaraResult.adjacency is the event-level parent-by-child adjacency matrix, labeled by NiagaraResult.feature_names on both axes.
NiagaraResult.edges contains the corresponding named (parent, child) pairs.
NiagaraResult.mechanisms contains the more detailed start/interval/end mechanisms as CausalMechanism objects.
Use result.to_dict() or result.to_json(path) for serialization.
Command line
Given events.csv:
event,start,end
rain,0,2
traffic,1,3
rain,5,7
traffic,6,8
Run:
niagara events.csv --horizon 10 --output result.json --adjacency-output adjacency.csv
Citation
If you use Niagara, please cite:
Lénaïg Cornanguer, Joscha Cüppers, and Jilles Vreeken. Causal Discovery from Interval-Based Event Sequences. In: Proceedings of the AAAI Conference on Artificial Intelligence (AAAI), AAAI, 2026.
Citation metadata is also available in CITATION.cff.
License
Niagara is distributed under the BSD 3-Clause License.
Metadata
Release files for niagara-cd 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| niagara_cd-0.2.0.tar.gz | 26.3 kB | With provenance | Details for niagara_cd-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| niagara_cd-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for niagara_cd-0.2.0-py3-none-any.whl |
Total release size: 57.3 kB
Release files / niagara_cd-0.2.0.tar.gz
| Download URL | niagara_cd-0.2.0.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dd2d17ab76e3e649697a5c400797585f95a90dc3acac904881d2d6e10d0007f3
|
|
BLAKE2b-256 checksum How to use checksums |
75f8c31bb5f765e8fdff06973575e228858e290721a4f9acb4d7b5748679afab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / niagara_cd-0.2.0-py3-none-any.whl
| Download URL | niagara_cd-0.2.0-py3-none-any.whl |
|---|---|
| Size | 31.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
28276128de26d8790548ba3dd9178a44f1a7d523681fe7aca8e94271aab82ef1
|
|
BLAKE2b-256 checksum How to use checksums |
009a62272fe16194547bb6eb21e666fcf8c2c1e216030b2a04640c6c34eadb15
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logSecurity for niagara-cd 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for niagara_cd-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.