A Python toolkit for compartmental models, sensitivity analysis, interactive visualisations, and automated reports — built for low-resource health contexts in Africa.
From ODE integration to publication-ready reports in a single coherent API designed for field epidemiologists.
.run() API. Returns structured ModelResult with R0, peak, final size, and Plotly/Matplotlib plots. Monte Carlo sensitivity analysis with uniform, normal, and triangular distributions..plot().from episia import epi result = epi.seir(N=1_000_000, I0=10, E0=50, beta=0.35, sigma=1/5.2, gamma=1/14).run() print(result)
SEIR Model R0 : 4.900 Peak infected : 331,751 at t=84.5 Final size : 99.2%
# Sensitivity analysis 200 Monte Carlo runs from episia.models import SEIRModel, SensitivityAnalysis from episia.models.parameters import SEIRParameters sa = SensitivityAnalysis(SEIRModel, SEIRParameters, fixed=dict(N=1_000_000, I0=10, E0=50, t_span=(0,200)), distributions={ 'beta': ('uniform', 0.20, 0.50), 'gamma': ('normal', 0.07, 0.02), 'sigma': ('triangular',0.15, 0.19, 0.25), }, n_samples=200, seed=42) sar = sa.run() sar.to_dataframe().head(3)
| r0 | peak_infected | peak_time | final_size |
|---|---|---|---|
| 4.12 | 289,441 | 78.2 | 98.1% |
| 2.87 | 174,208 | 92.5 | 84.7% |
| 1.64 | 48,392 | 141.0 | 47.3% |
from episia.stats.contingency import risk_ratio rr = risk_ratio(a=40, b=10, c=20, d=30) print(rr)
Risk Ratio: 2.667 (1.514–4.696) p=0.0003 *
# Scenario comparison sr.to_dataframe()
| scenario | R0 | peak_I | final |
|---|---|---|---|
| No intervention | 4.90 | 331,751 | 99.2% |
| 50% reduction | 2.52 | 198,430 | 87.1% |
| 70% reduction | 1.54 | 51,204 | 55.3% |
Every Episia result renders inline interactive Plotly charts, DataFrames, and HTML reports without leaving the notebook.
.to_dataframe().EpiLoader — silent in CI and non-TTY environments.Pull surveillance data directly from any DHIS2 instance. Episia handles authentication, period parsing, and conversion to a ready-to-analyse SurveillanceDataset in a single call.
from episia.dhis2 import DHIS2Client # Connect to any DHIS2 instance client = DHIS2Client( url = "https://dhis2.sante.gov.bf", username = "admin", password = "district", ) print(client.ping()) # True # List available org units and data elements ous = client.list_org_units(level=3) des = client.list_data_elements() print(len(des), "data elements available") # Pull meningitis cases from last 52 weeks ds = client.to_dataset( data_element = "meningite_cases", period = "LAST_52_WEEKS", org_unit = ous[0]["id"], ) print(ds) # SurveillanceDataset(n=52, cases=1847, 2024W01 -> 2024W52) # Run epidemic alert detection from episia.data.surveillance import AlertEngine engine = AlertEngine(ds) alerts = engine.run(threshold=20, zscore_threshold=2.0) print(len(alerts), "alerts detected") for a in alerts[:3]: print(f"[{a.severity}]", a.period, "|", a.message)
# Use DHIS2Adapter standalone # to convert already-fetched JSON from episia.dhis2 import DHIS2Adapter adapter = DHIS2Adapter() # Convert analytics API response ds = adapter.from_analytics_response( response = raw_json, cases_element = "FTRrcoaog83", deaths_element = "deaths_uid", ) print(ds) # Period types supported: # 2024W01 ISO week # 202401 month YYYYMM # 2024Q1 quarter # 2024 year # Install with DHIS2 extras # pip install episia[dhis2] # Works with PAT token auth too client2 = DHIS2Client( url = "https://your-instance/dhis", token = "d2pat_xxxxxxxxxxxx", )
Episia fills a gap no other Python library addresses — full biostatistics, epidemic modelling, DHIS2 integration, and automated reporting in a single validated package built for African public health.
| Package | Language | Biostatistics | Epidemic models | DHIS2 | Visualization | Reports | Validated | Tests | Updated |
|---|---|---|---|---|---|---|---|---|---|
| Episia | Python | Yes - full | Yes - SIR / SEIR / SEIRD + calibration + sensitivity | Yes - native | Yes - Plotly + Matplotlib | Yes - HTML | Yes - OpenEpi 45/45 | 1390 | 2026 |
| epiR | R | Yes - full | - | - | Partial - Base R | - | Yes | ~300 | 2024 |
| EpiEstim | R | - | Partial - R(t) only | - | Partial - ggplot2 | - | Yes | - | 2023 |
| EpiPy | Python | Partial - basic | Partial - SIR / SEIR | - | Partial - Matplotlib | - | - | ~200 | 2021 |
| PyEpiLib | Python | - | Partial - SIR only | - | Partial - Matplotlib | - | - | <100 | 2022 |
| Statsmodels | Python | Partial - general stats | - | - | Partial - Matplotlib | - | Yes | 5000+ | 2024 |
Partial = limited scope or single backend. Yes = full coverage of that capability.
No configuration required - sane defaults throughout. The simplest case is always the cleanest.
from episia.models import SEIRModel from episia.models.parameters import SEIRParameters from episia import report_from_model params = SEIRParameters( N=22_100_000, # Burkina Faso population I0=1, E0=10, beta=0.35, sigma=1/5.2, gamma=1/14, t_span=(0, 365), ) result = SEIRModel(params).run() report = report_from_model(result, title="SEIR Analysis", author="Dr. Ouedraogo", institution="Xcept-Health", ) report.save_html("report.html") report.save_markdown("report.md")
$ pip install episia $ pip install episia[dhis2] # with DHIS2 support
Each model shares the same ModelResult output format — consistent API, consistent plots.
| Model | Compartments | Best for | Tags |
|---|---|---|---|
SIRModel |
S → I → R |
Simple outbreaks, fast dynamics | SIR |
SEIRModel |
S → E → I → R |
Diseases with incubation period (influenza, COVID-19, meningitis) | SEIRincubation |
SEIRDModel |
S → E → I → R + D |
Outbreaks with significant mortality (Ebola, cholera) | SEIRDmortalityCFR |