A validation and Table-One generation tool for all 16 beta-ready CLIF 2.1 tables see data dictionary.
- Python 3.11+
uvpackage manager:curl -LsSf https://astral.sh/uv/install.sh | sh- CLIF 2.1 data in
parquet(orcsv/fst) format
cd CLIF-TableOne
uv syncAlways invoke commands through
uv runso the project's virtualenv (not your system Python) is used.
Copy the template and fill in your site details:
cp config/config_template.json config/config.jsonEdit config/config.json:
{
"site_name": "Your_Site_Name",
"tables_path": "/path/to/your/clif/data",
"file_type": "parquet",
"timezone": "US/Central"
}uv is cross-platform — the command below works on Linux, macOS, and Windows:
uv run python run_project.py --no-summaryThis validates all 16 CLIF tables, builds the critical-illness and ward Table One, and computes ECDF/bins distributions. Ward and ECDF are included by default.
| Flag | Purpose |
|---|---|
--no-summary |
Skip per-table summary statistics generation |
--no-ecdf |
Skip ECDF generation (saves memory on constrained systems) |
--no-ward |
Skip ward Table One generation |
--ward-only |
Only generate the ward Table One (skip validation + CI Table One) |
--validate-only |
Run validation only |
--tableone-only |
Run Table One only (CI + ward, no validation/ECDF) |
--get-ecdf-only |
Run ECDF only |
--force-refresh |
Bypass filtered-table cache and rebuild from raw source |
For the full flag list: uv run python run_project.py --help. Advanced workflows and granular per-table commands live in advanced_usage.md.
The uv run command above works on Windows as-is. The wrappers below are an optional convenience that pre-set PYTHONIOENCODING=utf-8 / PYTHONUTF8=1 so emojis and Unicode log output render correctly in the Windows console:
Using Batch files:
run_project_windows.bat --no-summaryUsing PowerShell:
.\run_project_windows.ps1 --no-summaryIf you encounter Unicode/emoji display issues, see the Windows Unicode Troubleshooting section below.
Companion run_analysis_windows.bat / .ps1 wrap run_analysis.py the same way. Ward and ECDF are now included by default — use --no-ward or --no-ecdf to skip them.
In addition to the critical-illness cohort (see §8.4 for the exact definition), it generates a parallel ward Table One whose cohort is every adult hospitalization that touched a ward at any point. If you want to run just the ward tableone:
uv run python run_project.py --ward-onlyWhat's in the ward Table One:
- Cohort: every adult hospitalization that touched a ward — includes ward→ICU, ward→death, ward-only, etc.
- Encounter Types section has 5 rows showing how many ward encounters fall into each critical-illness stratum:
- ICU encounters (ward→ICU subset)
- Advanced respiratory support
- Vasoactive support
- Other critically ill (died on ED/ward without escalation)
- Ward only (survived, no critical care) — the survivor catch-all
uv run uvicorn server.main:app --reloadOpen http://127.0.0.1:8000 in a browser.
| Flag | Purpose |
|---|---|
--reload |
Auto-restart on code changes (development mode) |
--host 0.0.0.0 |
Allow access from other machines on the network |
--port 8080 |
Use a different port (default: 8000) |
The uv run uvicorn ... command above works on Windows as-is. The wrappers below are an optional convenience that pre-set PYTHONIOENCODING=utf-8 / PYTHONUTF8=1 for correct emoji/Unicode rendering in the Windows console:
Using Batch files:
app_fastapi_windows.batUsing PowerShell:
.\app_fastapi_windows.ps1If you encounter Unicode/emoji display issues, see the Windows Unicode Troubleshooting section below.
Tabs:
- Table One Results — Cohort analysis: demographics, medications, IMV, SOFA/CCI, outcomes
- Validation — Overall DQA results
- Feedback — Classify validation errors as Accepted / Rejected / Pending; saves to
output/final/validation/feedback/<table>_validation_response.jsonand updates the table status
- Feedback — Classify validation errors as Accepted / Rejected / Pending; saves to
The feedback workflow lets reviewers classify validation errors:
- Open the Validation tab
- For each error, choose:
- Accepted — legitimate issue requiring attention
- Rejected — site-specific variation (provide a justification)
- Pending — not yet reviewed
- Save feedback. Table status is recomputed, any accepted or pending error keeps the table at its original status
If you see encoding errors with emojis/Unicode characters:
# Command Prompt
set PYTHONIOENCODING=utf-8
python run_project.py# PowerShell
$env:PYTHONIOENCODING="utf-8"
python run_project.py- Go to Settings → Time & Language → Language → Administrative language settings
- Click "Change system locale"
- Check "Beta: Use Unicode UTF-8 for worldwide language support"
- Restart your computer
python -X utf8 run_project.pyadult_encounters = adult_encounters[
(adult_encounters['age_at_admission'] >= 18) & (adult_encounters['age_at_admission'].notna())
]All cohorts require age_at_admission >= 18.
Linked admissions are joined into a single encounter_block before cohort selection, using clifpy.utils.stitching_encounters.stitch_encounters (modules/tableone/generator.py:62) with a 6-hour window — any two hospitalization_ids where discharge-to-next-admission ≤ 6 h get merged. Every flag below is computed at the encounter-block level, not the hospitalization_id level — so a patient discharged and readmitted within 6 hours counts as one encounter, not two.
Every flag is a 0/1 indicator on the stitched encounter block. The strata in §9 are just filters on these flags.
| Flag | Definition |
|---|---|
icu_enc |
Encounter ever had a row with location_category containing 'icu' |
death_enc |
Encounter ever had a row with discharge_category in ('expired', 'hospice') |
ward_enc |
Encounter ever had a row with location_category == 'ward' |
high_support_enc |
Encounter ever received imv / nippv / cpap (unconditionally) or high flow nc with lpm_set >= 30 (respiratory_support.device_category) |
nippv_hfnc_enc |
Encounter ever received nippv or high flow nc with lpm_set >= 30 (respiratory_support.device_category) |
vaso_support_enc |
Encounter ever received norepinephrine, epinephrine, phenylephrine, vasopressin, dopamine, or angiotensin (medication_admin_continuous.med_category) |
vaso_ed_icu_enc |
First vasopressor was administered in the ED AND any subsequent ADT location includes ICU |
vaso_ed_ward_enc |
First vasopressor was administered in the ED AND any subsequent ADT location includes ward but NOT ICU |
no_imv_enc |
Encounter is in the critical-illness cohort AND never received invasive mechanical ventilation (on_vent == 0; on_vent is set to 1 when the encounter has any IMV observation in the respiratory support data) |
no_imv_icu_enc |
no_imv_enc AND icu_enc |
no_imv_no_icu_enc |
no_imv_enc AND NOT icu_enc |
is_procedural_ld_only |
icu_enc == 0 AND any(loc in {'procedural', 'l&d'}) |
other_critically_ill |
death_enc==1 AND icu_enc==0 AND vaso_support_enc==0 AND high_support_enc==0 — i.e. the encounter expired/hospice-discharged but never touched ICU, never received vasoactive medications, and never received advanced respiratory support (IMV/NIPPV/CPAP/HFNC≥30); net effect is death in ED or on the ward without escalation |
# modules/tableone/generator.py:1837-1841
final_cohort['cohort_enc'] = (
(final_cohort['icu_enc'] | final_cohort['death_enc']
| final_cohort['high_support_enc'] | final_cohort['vaso_support_enc'])
& (~final_cohort['is_procedural_ld_only'].astype(bool))
).astype(int)Adults whose encounter block touched an ICU OR discharged as expired/hospice in ED/Ward OR received advanced respiratory support OR received vasoactive medications — excluding encounters flagged
is_procedural_ld_only.
This means the cohort includes ward survivors who received vasoactive medications or advanced respiratory support but never touched an ICU. Concretely: an adult who got norepinephrine on the ward, never touched ICU, and survived → in the critical-illness cohort. The no_icu sub-strata (§9) therefore contain both deaths and ward survivors with support, not exclusively deaths.
The strata directories under output/final/strata/ are subsets of the critical-illness cohort, filtered by a single flag. The mapping is the single source of truth in modules/strata.py:24-41:
| Directory | Flag | Definition | ECDF temporal window |
|---|---|---|---|
strata/icu/ |
icu_enc |
Encounter touched a location with location_category == 'icu' |
ICU stay (in_dttm → out_dttm from ADT) |
strata/advanced_resp/ |
high_support_enc |
Received imv / nippv / cpap (unconditionally) or high flow nc with lpm_set >= 30 at any point |
First qualifying device recorded_dttm → discharge_dttm |
strata/advanced_resp/icu/ |
high_support_icu_enc |
Advanced resp AND ICU | Same as advanced_resp/ |
strata/advanced_resp/no_icu/ |
high_support_no_icu_enc |
Advanced resp AND NOT ICU (includes deaths and ward survivors with support) | Same as advanced_resp/ |
strata/nippv_hfnc/ |
nippv_hfnc_enc |
Received nippv or high flow nc with lpm_set >= 30 |
First qualifying device recorded_dttm → discharge_dttm |
strata/nippv_hfnc/icu/ |
nippv_hfnc_icu_enc |
NIPPV/HFNC AND ICU | Same as nippv_hfnc/ |
strata/nippv_hfnc/no_icu/ |
nippv_hfnc_no_icu_enc |
NIPPV/HFNC AND NOT ICU (includes deaths and ward survivors with support) | Same as nippv_hfnc/ |
strata/vaso/ |
vaso_support_enc |
Received norepinephrine, epinephrine, phenylephrine, vasopressin, dopamine, or angiotensin |
First vasopressor admin_dttm → discharge_dttm |
strata/vaso/icu/ |
vaso_icu_enc |
Vaso AND ICU | Same as vaso/ |
strata/vaso/no_icu/ |
vaso_no_icu_enc |
Vaso AND NOT ICU (includes deaths and ward survivors on vasopressors) | Same as vaso/ |
strata/vaso/ed_icu/ |
vaso_ed_icu_enc |
First vasopressor in ED AND any subsequent location includes ICU | Same as vaso/ |
strata/vaso/ed_ward/ |
vaso_ed_ward_enc |
First vasopressor in ED AND any subsequent location includes ward but NOT ICU | Same as vaso/ |
strata/no_imv/ |
no_imv_enc |
Critically ill but never received invasive mechanical ventilation (on_vent == 0) |
ICU stay |
strata/no_imv/icu/ |
no_imv_icu_enc |
No IMV AND ICU | Same as no_imv/ |
strata/no_imv/no_icu/ |
no_imv_no_icu_enc |
No IMV AND NOT ICU (includes deaths and ward survivors without IMV) | Same as no_imv/ |
strata/deaths/ |
death_enc |
ED/ward discharge_category in ('expired', 'hospice') |
ICU stay (in_dttm → out_dttm from ADT) |
output/
├── final/
│ ├── overall/ Critical-illness cohort
│ │ ├── tableone/ Demographics, mortality, comorbidities, ventilator, medications, ...
│ │ ├── figures/ CONSORT, sankey, venn, upset, area curves, KM time-to-extubation, daily P/F-S/F
│ │ ├── ecdf/ {labs,vitals,respiratory_support}/ ECDF parquets
│ │ ├── bins/ {labs,vitals,respiratory_support}/ quantile-bin parquets
│ │ ├── summary_stats/ Per-category mean/median/IQR
│ │ ├── mcide/ Minimum CDE value counts
│ │ └── ventilated_aggregates/ Cross-site KM + daily P/F|S/F aggregates (no PHI)
│ │ ├── km_time_to_extubation.csv Kaplan-Meier numbers per (stratum, timepoint)
│ │ └── min_pf_sf_per_day_post_intubation.csv Daily min P/F & S/F median/IQR (long format)
│ ├── overall_ward/ Ward cohort (only present when --ward is used)
│ │ └── {tableone,figures,summary_stats}/
│ ├── strata/ Stratified critical-illness subsets
│ │ ├── icu/ {tableone,figures,ecdf,bins,summary_stats}/
│ │ ├── advanced_resp/ {... + icu/ + no_icu/}
│ │ ├── nippv_hfnc/ {... + icu/ + no_icu/}
│ │ ├── vaso/ {... + icu/ + no_icu/ + ed_icu/ + ed_ward/}
│ │ ├── no_imv/ {... + icu/ + no_icu/}
│ │ └── deaths/ {tableone,figures,ecdf,bins,summary_stats}/
│ ├── validation/ Data quality assessment
│ │ ├── json_reports/ <table>_dqa.json + supporting CSVs
│ │ ├── consolidated/ consolidated_validation.csv + summary JSONs
│ │ ├── feedback/ <table>_validation_response.json (user-classified errors)
│ │ ├── monthly_trends/ Monthly trend CSVs
│ │ └── pdf_reports/ Per-table PDFs + combined PDF
│ ├── stats/ collection_statistics.csv (+ per-stratum variants)
│ └── meta/ Execution reports, workflow logs, run metadata
│ ├── configs/ Snapshot of config files used for the run
│ └── workflow_logs/ Timestamped pipeline stdout/stderr
└── intermediate/ Debug logs + scratch (critical-illness only)
├── vent_hours_debug.log Per-encounter waterfall + IMV-hours debug trace
└── imv_episodes.csv Per-IMV-episode timestamps (repeated-measures analyses)
For what each file contains, the cohort filter applied, and which module generates it, see OUTPUT_REFERENCE.md.
You can use an AI coding assistant to interactively review your validation results, diagnose issues, and get specific fix recommendations. The repo ships with CLAUDE.md and AGENTS.md that give the assistant full context about the pipeline, validation checks, and common fixes.
Using Claude Code:
cd CLIF-TableOne
claude # Opens Claude Code with CLAUDE.md context auto-loaded
# Then ask: "Review my validation results and tell me what to fix"Using Codex or other tools:
Open the repo in your AI tool of choice — it will pick up AGENTS.md automatically.
What the assistant can do:
- Read your
*_dqa.jsonfiles and summarize pass/fail by table - Explain what each validation error means and whether it's critical
- Suggest specific ETL fixes for unit mismatches, missing columns, or relational errors
- Cross-check your Table One numbers for internal consistency
- Diagnose pipeline crashes from the workflow log
OUTPUT_REFERENCE.md— Per-file detail for everything underoutput/final/advanced_usage.md— Granular per-table validation, sampling workflows, ECDF configurationCLAUDE.md— AI assistant context for validation review
For issues or questions, please open an issue in the project repository.