Epidemiological Linkage Inference from Temporal and Genetic Data with a Variable Infectiousness (E/P/I) Model for SARS-CoV-2.
Project description
epilink: Epidemiological Linkage from Temporal and Genetic Data
Estimate the probability that two cases are epidemiologically linked from their temporal and genetic distances. Implements a mechanistic SARS‑CoV‑2 infectiousness model (E/P/I) with optional Numba acceleration. Usable from Python or the command line.
By default, linkage estimates follow the appendix definition of recent transmission and use only M=0 genetic compatibility, i.e. included_intermediate_counts=(0,).
Features
- Estimate P(link | genetic distance g, temporal gap t)
- Parameterised infectiousness profiles (InfectiousnessToTransmissionTime/SymptomOnsetToTransmissionTime; configurable)
- Fast simulation kernels with optional JIT (Numba)
- Python API plus a lightweight CLI for batch runs
Installation
From PyPI:
pip install epilink
Recommended (conda/mamba):
# Create a fresh env (uses compiled deps from conda-forge)
conda create -n epilink -c conda-forge python=3.11 numpy scipy numba networkx pandas pip
conda activate epilink
git clone https://github.com/ydnkka/epilink.git
cd epilink
# Install the package from source without touching conda-managed deps
pip install -e . --no-deps
# (Optional) Dev tools: tests, linting, docs
pip install "pytest>=7.3" "pytest-cov>=4.0" "mypy>=1.4" "ruff>=0.5" "black>=24.1" \
"pre-commit>=3.3" "mkdocs>=1.5" "mkdocs-material>=9.5" "mkdocstrings[python]>=0.24"
Alternative (pip + venv):
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
python -m pip install --upgrade pip
pip install -e .[dev]
Notes:
- Prefer conda-forge for NumPy/SciPy/Numba (especially on Apple Silicon).
- In a conda env, avoid pip-installing compiled deps; use
pip install -e . --no-deps.
Quickstart
Python API
import numpy as np
from epilink import InfectiousnessToTransmissionTime, MolecularClock, estimate_linkage_probability, estimate_linkage_probability_grid
toit = InfectiousnessToTransmissionTime(rng_seed=123)
clock = MolecularClock(use_relaxed_clock=False, rng_seed=123)
# Probability that a pair with 2 SNPs and 4 days apart is directly linked (m=0)
p = estimate_linkage_probability(
transmission_profile=toit,
clock=clock,
genetic_distance=2,
temporal_distance=4,
included_intermediate_counts=0,
num_simulations=10_000,
)
print("P(link):", p)
# Grid over genetic distances (SNPs) and temporal gaps (days)
gd = np.arange(0, 6) # 0..5 SNPs
td = np.arange(0, 15, 3) # 0..12 days, step 3
mat = estimate_linkage_probability_grid(
transmission_profile=toit,
clock=clock,
genetic_distances=gd,
temporal_distances=td,
num_simulations=10_000,
)
print(mat)
CLI
# Help
epilink --help
epilink point --help
epilink grid --help
# Single pair
epilink point -g 2 -t 4 --num-simulations 200
# Multiple pairs (CSV to stdout)
epilink point -g 0 1 2 -t 0 2 5 --num-simulations 500 > out.csv
# Custom infectiousness profile and numerical grid bounds
epilink point -g 2 -t 4 --num-simulations 200 \
--grid-min-days 0 --grid-max-days 40 \
--incubation-shape 5.0 --incubation-scale 1.1 \
--latent-shape 2.0 --symptomatic-rate 0.4 \
--symptomatic-shape 1.2 --rel-presymptomatic-infectiousness 2.0
# Grid (CSV to file)
epilink grid --genetic-start 0 --genetic-stop 5 --genetic-step 1 \
--temporal-start 0 --temporal-stop 12 --temporal-step 3 \
--num-simulations 10000 --output grid.csv
Commonly used options (see --help for full list):
-m, --included-intermediate-countsdefault"0"; e.g."0,1,2"to include longer chains--relaxed-clock--substitution-rate 1e-3--relaxed-clock-sigma 0.33--seed 12345--grid-min-days 0 --grid-max-days 60(numerical grid bounds)--incubation-shape,--incubation-scale,--latent-shape,--symptomatic-rate,--symptomatic-shape,--rel-presymptomatic-infectiousness
Development
Run tests:
pytest --cov=epilink --cov-report=term-missing
# To count Python-side coverage of JIT kernels:
# NUMBA_DISABLE_JIT=1 pytest
Code quality:
ruff check .
black .
mypy src/epilink
Pre-commit:
pre-commit install
pre-commit run -a
Docs:
mkdocs serve
Examples
Examples in examples/:
python examples/quickstart.pypython examples/grid_to_csv.py --output grid.csv
Install plotting deps if needed:
mamba install -c conda-forge matplotlib seaborn
License
MIT License (see LICENSE)
Development & Contributing
For developers:
- Testing releases: See TESTPYPI.md for instructions on testing package releases on TestPyPI before publishing to PyPI
- Contributing: Pull requests welcome! Please ensure tests pass and coverage remains high
Contact
Reference
Hart WS, Maini PK, Thompson RN (2021). High infectiousness immediately before COVID‑19 symptom onset highlights the importance of continued contact tracing. eLife, 10:e65534. https://doi.org/10.7554/eLife.65534
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file epilink-0.1.2.tar.gz.
File metadata
- Download URL: epilink-0.1.2.tar.gz
- Upload date:
- Size: 53.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53965308640a649b143a656c822f159910c90695c45c54cb0987fcf9eb2150dd
|
|
| MD5 |
2bfda407c2eb9475b051e90f12be4dea
|
|
| BLAKE2b-256 |
f2825cf77195581b5b90e88535f0fd67e6f04ce263959d127eb814593683061d
|
Provenance
The following attestation bundles were made for epilink-0.1.2.tar.gz:
Publisher:
release.yml on ydnkka/epilink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epilink-0.1.2.tar.gz -
Subject digest:
53965308640a649b143a656c822f159910c90695c45c54cb0987fcf9eb2150dd - Sigstore transparency entry: 1107771699
- Sigstore integration time:
-
Permalink:
ydnkka/epilink@28ed19885e803f3575d7a92387e5bd35d34980a7 -
Branch / Tag:
refs/tags/v0.1.2-apha - Owner: https://github.com/ydnkka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@28ed19885e803f3575d7a92387e5bd35d34980a7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file epilink-0.1.2-py3-none-any.whl.
File metadata
- Download URL: epilink-0.1.2-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ad499ca502ecccea1a1b1fcb4c167b1971001036b9cfa97b54ac4e7fa8b5fe0
|
|
| MD5 |
b343a80e6d965b4eaa5249e31d0749f4
|
|
| BLAKE2b-256 |
885e5c3677d449cbea22d4891634ec3a51380cacc19edfcf59ee198264096786
|
Provenance
The following attestation bundles were made for epilink-0.1.2-py3-none-any.whl:
Publisher:
release.yml on ydnkka/epilink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epilink-0.1.2-py3-none-any.whl -
Subject digest:
2ad499ca502ecccea1a1b1fcb4c167b1971001036b9cfa97b54ac4e7fa8b5fe0 - Sigstore transparency entry: 1107771701
- Sigstore integration time:
-
Permalink:
ydnkka/epilink@28ed19885e803f3575d7a92387e5bd35d34980a7 -
Branch / Tag:
refs/tags/v0.1.2-apha - Owner: https://github.com/ydnkka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@28ed19885e803f3575d7a92387e5bd35d34980a7 -
Trigger Event:
release
-
Statement type: