Tagline

See coronary risk in 3D and understand why: per-artery stenosis prediction from routine clinical data, mapped onto an interactive heart.

Inspiration

Cardiovascular disease is still a leading cause of death. Risk models usually end in a single percentage, which tells a clinician or a patient little about where the problem may be or why the model thinks so. We wanted a tool that turns routine clinical data into an answer you can see and question.

What it does

CardioScope takes a patient's demographics, examination, ECG, lab and echocardiography values and predicts:

  • the probability of overall coronary artery disease (CAD);
  • the probability of significant stenosis in each of the three main arteries: LAD, LCX and RCA.

How the results are shown:

  • Interactive 3D heart: each artery is coloured by its probability, from green through amber to red, inside a transparent torso.
    • The heart muscle each artery supplies is tinted with the same risk colour.
    • You can rotate, zoom and click an artery to fly to it and see its details.
  • Clinical dashboard:
    • CAD gauge and per-vessel bars;
    • an exact SHAP waterfall showing why the model predicted this risk;
    • a physiology panel showing every measurement against its normal range, beside its contribution;
    • a vessel detail panel;
    • an "In plain words" summary.
  • Live updates: editing any value or moving a what-if slider updates the probabilities, the explanations and the 3D colours in under a second.
  • Example patients: one click loads real normal, single-vessel and multi-vessel patients.
  • Disclaimer: a permanent banner says it is for decision support and education only, not a substitute for angiography. We predict per-vessel status, not lesion location.

How we built it

Data:

  • The Extension of Z-Alizadeh Sani dataset (UCI): 303 patients, 54 model features.
  • features.yaml describes every feature: type, unit, normal range and group. The same file drives training, API validation and the dashboard form.

Machine learning (Python, scikit-learn, XGBoost, CatBoost):

  • For each of the four targets we compare logistic regression, random forest, XGBoost and CatBoost.
  • Nested cross-validation: repeated stratified 5-fold × 3, with hyper-parameter tuning in an inner loop. All preprocessing is refit inside every fold.
  • Calibration and thresholds: Platt calibration; decision thresholds tuned for recall (≥ 90 % CAD, ≥ 80 % vessels); bootstrap 95 % confidence intervals.
  • Leakage guard: an automated check stops LAD/LCX/RCA/Cath from ever being inputs.
  • Exact SHAP: native TreeSHAP for trees, exact linear SHAP for logistic regression.
  • Extra evaluation:
    • a 10-item bedside baseline;
    • a pre-specified ensemble;
    • decision-curve analysis;
    • a subgroup check by sex, age and diabetes.
  • One command trains everything, and two runs give identical results.

Backend:

  • FastAPI with /schema, /predict, /explain and /patients/sample.
  • The input model is generated from the feature config.
  • Deployed as a Docker service on Render.

Frontend:

  • React + TypeScript + React Three Fiber, deployed on Vercel.
  • The heart is a sculpted CC-licensed model, split into separate LAD/LCX/RCA meshes and compressed to 438 KB.
  • Rendering happens on demand, so it runs smoothly on an ordinary laptop with no GPU.
  • One shared vessels.json keeps the 3D arteries, API and model outputs consistent.

Quality: 111 automated tests (ML, API, frontend) run in GitHub Actions on every push.

Results (nested CV, mean [95 % CI])

Target ROC-AUC
Overall CAD 0.93 [0.90–0.96]
LAD 0.84 [0.80–0.88]
LCX 0.73 [0.67–0.78]
RCA 0.73 [0.68–0.78]
  • Every model beats "treat all" and "treat none" in decision-curve analysis.
  • For LAD the full model clearly beats a bedside baseline (+0.064 AUC).
  • For LCX and RCA it does not, and we say so.

Challenges we ran into

  • Honest validation on only 303 patients. We used nested CV, paired comparisons and bootstrap CIs instead of chasing a single high score.
  • Mapping risk to anatomy without overclaiming. The data gives per-vessel status, not lesion position, so the 3D view colours whole arteries and their supply territories. It never shows a "lesion spot".
  • A calibration solver that could diverge on spread-out scores. We found it, fixed it with a line search and added a regression test.
  • Security software: Windows Smart App Control blocked scikit-learn on our machine, so training moved to Linux (WSL), which also matches the deployed server.

Accomplishments that we're proud of

  • Explanations are exact: SHAP contributions add up to each displayed probability.
  • One config-driven pipeline from data to 3D. Adding a feature, model or vessel is a config change.
  • Under-a-second live what-if updates on a free deployment.

What we learned

On small clinical datasets, simple well-calibrated models are as good as complex ones. Honest uncertainty (CIs, reliability notes, subgroup gaps) builds more trust than a single big number.

What's next for CardioScope

  • External validation on a second hospital's data, under ethics approval and with clinical partners.
  • Vessel-specific inputs, e.g. coronary CT or perfusion imaging, to improve LCX/RCA.
  • Patient-specific anatomy.

Built With

Share this project:

Updates

Submission history