Episia Package#
Episia - Epidemiology Toolbox for Python Based on OpenEpi algorithms, extended for the African public health context.
Quick start:
from episia import epi
# SEIR model
model = epi.seir(N=1_000_000, I0=10, E0=50, beta=0.35,
sigma=1/5.2, gamma=1/14)
result = model.run()
result.plot().show()
# Biostatistics
rr = epi.risk_ratio(a=40, b=10, c=20, d=30)
print(rr)
# Report
report = epi.report(result, title="SEIR — Burkina Faso 2024")
report.save_html("report.html")
Advanced usage (direct imports):
# Models
from episia.models import SIRModel, SEIRModel, SEIRDModel
from episia.models import SensitivityAnalysis, ModelCalibrator
# Stats
from episia.stats import risk_ratio, odds_ratio, diagnostic_test_2x2
from episia.stats import roc_analysis, sample_size_risk_ratio
# Reporting
from episia import EpiReport
report = EpiReport(title="My report", author="Dr. Ouedraogo")
report.add_metrics({"R0": 3.2, "Peak": "42,500"})
report.save_html("report.html")
# Visualization
from episia.viz import plot_epicurve, plot_roc, plot_forest, set_theme
set_theme("dark")
# Surveillance data
from episia.data import SurveillanceDataset, AlertEngine
- class episia.AlertEngine(dataset)[source]#
Bases:
objectThreshold-based and statistical alert detection for surveillance data.
Example:
engine = AlertEngine(dataset) alerts = engine.run( threshold=10, zscore_threshold=2.0, use_endemic_channel=True, ) for a in alerts: print(a.period, a.severity, a.message)
- Parameters:
dataset (SurveillanceDataset)
- __init__(dataset)[source]#
- Parameters:
dataset (SurveillanceDataset)
- run(threshold=None, zscore_threshold=2.0, use_endemic_channel=False, historical_years=None, freq='W')[source]#
Run all enabled alert detectors.
- Parameters:
threshold (float | None) – Absolute case count threshold.
zscore_threshold (float) – Z-score threshold for statistical alert.
use_endemic_channel (bool) – Use endemic channel (requires ≥3 historical years).
historical_years (List[int] | None) – Years to use for endemic channel baseline.
freq (str) – Aggregation frequency (‘D’, ‘W’, ‘ME’).
- Returns:
List of Alert objects, sorted by period.
- Return type:
- class episia.EpiReport(title='Epidemiological report', author=None, institution=None, date=None, description=None)[source]#
Bases:
objectStructured epidemiological report builder.
Example:
report = EpiReport(title="Analyse SEIR", author="Dr. Ouedraogo") report.add_text("Introduction...", title="Introduction") report.add_metrics({"R0": 3.2, "Peak": 42500}) report.add_table(df, title="Results") report.save_html("rapport.html") report.save_markdown("rapport.md")
- Parameters:
- __init__(title='Epidemiological report', author=None, institution=None, date=None, description=None)[source]#
- class episia.EpisiaAPI[source]#
Bases:
objectUnified Episia API single entry point for all functionality. Instantiated as the module-level epi singleton.
- static report(result, title=None, **kwargs)[source]#
Build a report from any EpiResult or ModelResult.
- static seir(N, I0, E0, beta, sigma, gamma, t_end=365, **kwargs)[source]#
Convenience factory for SEIRModel.
- static seird(N, I0, E0, beta, sigma, gamma, mu, t_end=365, **kwargs)[source]#
Convenience factory for SEIRDModel.
- class episia.SurveillanceDataset(df, *, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None)[source]#
Bases:
objectStructured surveillance case count dataset.
- Wraps a pandas DataFrame with columns:
date / week / period time axis district / site spatial unit (optional) disease disease or syndrome name cases integer case count deaths integer death count (optional) population population at risk (optional)
Built from CSV, DHIS2 exports, or a plain DataFrame.
Example:
from episia.data.surveillance import SurveillanceDataset ds = SurveillanceDataset.from_csv("meningite_2024.csv", date_col="semaine", cases_col="cas") print(ds.summary()) ds.epicurve().plot().show() alerts = ds.alert_engine().run()
- Parameters:
- __init__(df, *, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None)[source]#
- aggregate(freq='W', group_by=None)[source]#
Aggregate cases by time frequency and optional grouping columns.
- property df#
- endemic_channel(historical_years=None, percentiles=(25, 50, 75))[source]#
Compute the endemic channel (historical percentile envelope).
Groups by ISO week number across historical years. Returns the percentile bands used for alert zone classification.
- filter_date(start=None, end=None)[source]#
Filter to a date range (inclusive).
- Parameters:
- Return type:
- filter_disease(disease)[source]#
Return a new dataset filtered to a single disease.
- Parameters:
disease (str)
- Return type:
- filter_district(district)[source]#
Return a new dataset filtered to a single district.
- Parameters:
district (str)
- Return type:
- classmethod from_csv(path, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None, **read_kwargs)[source]#
Load from CSV file.
- Parameters:
date_col (str) – Column name for date / week.
cases_col (str) – Column name for case counts.
deaths_col (str | None) – Column name for deaths (optional).
district_col (str | None) – Column name for district / site (optional).
disease_col (str | None) – Column name for disease / syndrome (optional).
population_col (str | None) – Column for population at risk (optional).
**read_kwargs – Passed to pd.read_csv.
- Returns:
SurveillanceDataset.
- Return type:
- classmethod from_dict(data, **kwargs)[source]#
Create from a plain dict of lists.
- Parameters:
- Return type:
- episia.report_from_model(model_result, title=None, author=None, institution=None, sensitivity_result=None, backend='plotly', theme='scientific')[source]#
Full model simulation report (SIR / SEIR / SEIRD).
- episia.report_from_result(result, title=None, author=None, backend='plotly', theme='scientific')[source]#
One-line report from any EpiResult.
Package Overview#
The episia package provides a comprehensive toolbox for epidemiological analysis.
The recommended entry point is the unified epi interface:
from episia import epi
# Unified API
model = epi.seir(N=1_000_000, I0=10, E0=50, beta=0.35, sigma=1/5.2, gamma=1/14)
rr = epi.risk_ratio(a=40, b=10, c=20, d=30)
report = epi.report(result)
For advanced usage, individual modules can be imported directly.
Version Information#
Lazy Loading#
Episia uses lazy loading to improve startup performance. Heavy modules
(scipy, sklearn, plotly, matplotlib) are only imported when
first used. This means:
from episia import epiis fastfrom episia import risk_ratiotriggers the import of required dependencies
The lazy loading is implemented via PEP 562 (__getattr__).
Plotly Renderer Configuration#
Episia automatically configures the Plotly renderer based on the environment:
In Jupyter notebooks: Renderer is left unchanged (inline display works normally)
In scripts/terminals: Renderer is set to
"browser"to open figures in your web browser
This prevents raw JSON from being dumped in the terminal when calling fig.show().
Unified Interface#
- episia.epi = EpisiaAPI()#
Unified Episia API single entry point for all functionality. Instantiated as the module-level epi singleton.
The main entry point for Episia functionality. Provides a unified interface to all modules through a single object.
- class episia.api.unified.EpisiaAPI[source]
Bases:
objectUnified Episia API single entry point for all functionality. Instantiated as the module-level epi singleton.
- static cumulative_incidence(*args, **kwargs)[source]
- static diagnostic(*args, **kwargs)[source]
- static get_available_themes()[source]
- static incidence_rate(*args, **kwargs)[source]
- static mean_ci(*args, **kwargs)[source]
- static odds_ratio(*args, **kwargs)[source]
- static plot_epicurve(*args, **kwargs)[source]
- static plot_forest(*args, **kwargs)[source]
- static plot_roc(*args, **kwargs)[source]
- static prevalence(*args, **kwargs)[source]
- static proportion_ci(*args, **kwargs)[source]
- static read_csv(path, **kwargs)[source]
- static report(result, title=None, **kwargs)[source]
Build a report from any EpiResult or ModelResult.
- static risk_ratio(*args, **kwargs)[source]
- static sample_size(*args, **kwargs)[source]
- static seir(N, I0, E0, beta, sigma, gamma, t_end=365, **kwargs)[source]
Convenience factory for SEIRModel.
- static seird(N, I0, E0, beta, sigma, gamma, mu, t_end=365, **kwargs)[source]
Convenience factory for SEIRDModel.
- static sir(N, I0, beta, gamma, t_end=160, **kwargs)[source]
Convenience factory for SIRModel.
- static surveillance_from_csv(path, **kwargs)[source]
Reporting#
- class episia.api.reporting.EpiReport(title='Epidemiological report', author=None, institution=None, date=None, description=None)[source]
Bases:
objectStructured epidemiological report builder.
Example:
report = EpiReport(title="Analyse SEIR", author="Dr. Ouedraogo") report.add_text("Introduction...", title="Introduction") report.add_metrics({"R0": 3.2, "Peak": 42500}) report.add_table(df, title="Results") report.save_html("rapport.html") report.save_markdown("rapport.md")
- Parameters:
- __init__(title='Epidemiological report', author=None, institution=None, date=None, description=None)[source]
- add_figure(figure, title=None, caption=None, width='100%')[source]
- add_metrics(metrics, title='Key indicators')[source]
- add_result(result, title=None)[source]
- add_table(data, title=None, caption=None, max_rows=100)[source]
- add_text(text, title=None, level=2)[source]
- episia.api.reporting.report_from_result(result, title=None, author=None, backend='plotly', theme='scientific')[source]
One-line report from any EpiResult.
- episia.api.reporting.report_from_model(model_result, title=None, author=None, institution=None, sensitivity_result=None, backend='plotly', theme='scientific')[source]
Full model simulation report (SIR / SEIR / SEIRD).
Surveillance Data#
- class episia.data.surveillance.SurveillanceDataset(df, *, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None)[source]
Bases:
objectStructured surveillance case count dataset.
- Wraps a pandas DataFrame with columns:
date / week / period time axis district / site spatial unit (optional) disease disease or syndrome name cases integer case count deaths integer death count (optional) population population at risk (optional)
Built from CSV, DHIS2 exports, or a plain DataFrame.
Example:
from episia.data.surveillance import SurveillanceDataset ds = SurveillanceDataset.from_csv("meningite_2024.csv", date_col="semaine", cases_col="cas") print(ds.summary()) ds.epicurve().plot().show() alerts = ds.alert_engine().run()
- Parameters:
- __init__(df, *, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None)[source]
- aggregate(freq='W', group_by=None)[source]
Aggregate cases by time frequency and optional grouping columns.
- attack_rate(population=None, per=100000)[source]
Compute overall attack rate.
- property df
- endemic_channel(historical_years=None, percentiles=(25, 50, 75))[source]
Compute the endemic channel (historical percentile envelope).
Groups by ISO week number across historical years. Returns the percentile bands used for alert zone classification.
- filter_date(start=None, end=None)[source]
Filter to a date range (inclusive).
- Parameters:
- Return type:
- filter_disease(disease)[source]
Return a new dataset filtered to a single disease.
- Parameters:
disease (str)
- Return type:
- filter_district(district)[source]
Return a new dataset filtered to a single district.
- Parameters:
district (str)
- Return type:
- classmethod from_csv(path, date_col='date', cases_col='cases', deaths_col=None, district_col=None, disease_col=None, population_col=None, **read_kwargs)[source]
Load from CSV file.
- Parameters:
date_col (str) – Column name for date / week.
cases_col (str) – Column name for case counts.
deaths_col (str | None) – Column name for deaths (optional).
district_col (str | None) – Column name for district / site (optional).
disease_col (str | None) – Column name for disease / syndrome (optional).
population_col (str | None) – Column for population at risk (optional).
**read_kwargs – Passed to pd.read_csv.
- Returns:
SurveillanceDataset.
- Return type:
- classmethod from_dataframe(df, **kwargs)[source]
Wrap an existing DataFrame.
- Return type:
- classmethod from_dict(data, **kwargs)[source]
Create from a plain dict of lists.
- Parameters:
- Return type:
- property n_records: int
- to_timeseries_result()[source]
Convert to api.results.TimeSeriesResult for viz integration.
- Returns:
TimeSeriesResult ready for plot_epicurve().
- property total_cases: int
- class episia.data.surveillance.AlertEngine(dataset)[source]
Bases:
objectThreshold-based and statistical alert detection for surveillance data.
Example:
engine = AlertEngine(dataset) alerts = engine.run( threshold=10, zscore_threshold=2.0, use_endemic_channel=True, ) for a in alerts: print(a.period, a.severity, a.message)
- Parameters:
dataset (SurveillanceDataset)
- __init__(dataset)[source]
- Parameters:
dataset (SurveillanceDataset)
- alert_summary(alerts)[source]
Summarise a list of alerts.
- run(threshold=None, zscore_threshold=2.0, use_endemic_channel=False, historical_years=None, freq='W')[source]
Run all enabled alert detectors.
- Parameters:
threshold (float | None) – Absolute case count threshold.
zscore_threshold (float) – Z-score threshold for statistical alert.
use_endemic_channel (bool) – Use endemic channel (requires ≥3 historical years).
historical_years (List[int] | None) – Years to use for endemic channel baseline.
freq (str) – Aggregation frequency (‘D’, ‘W’, ‘ME’).
- Returns:
List of Alert objects, sorted by period.
- Return type:
Available Lazy Imports#
The following names are lazily loaded from their respective modules:
Statistics:
- risk_ratio
- odds_ratio
- proportion_ci
- mean_ci
- diagnostic_test_2x2
- roc_analysis
- sample_size_risk_ratio
- sample_size_single_proportion
Visualization:
- set_theme
- get_available_themes
- plot_epicurve
- plot_roc
- plot_forest
Examples#
Basic usage with unified interface:
from episia import epi
# SEIR model
model = epi.seir(
N=1_000_000,
I0=10,
E0=50,
beta=0.35,
sigma=1/5.2,
gamma=1/14
)
result = model.run()
result.plot().show()
# Risk ratio
rr = epi.risk_ratio(a=40, b=10, c=20, d=30)
print(rr) # Risk Ratio: 2.667 (1.514-4.696)
# Generate report
report = epi.report(result, title="SEIR Analysis")
report.save_html("report.html")
Direct imports for advanced usage:
from episia.models import SEIRModel, SensitivityAnalysis
from episia.stats import roc_analysis, sample_size_risk_ratio
from episia.viz import plot_epicurve, set_theme
from episia.data import SurveillanceDataset
# Set theme globally
set_theme("dark")
# Load surveillance data
ds = SurveillanceDataset.from_csv("cases.csv")
# ROC analysis
roc_result = roc_analysis(y_true, y_scores)
Version check:
import episia
print(f"Episia version: {episia.__version__}")