{
"cells": [
{
"cell_type": "markdown",
"id": "178597e4054ba0a6",
"metadata": {},
"source": [
"# B Point Plotting Example\n",
"\n",
"This notebook demonstrates running a B-point extraction (Pale et al., 2021) on the example dataset and several\n",
"plotting styles: low-level plotting, split/zoomed axes, showing reference points, detected points, and heartbeat borders."
]
},
{
"cell_type": "markdown",
"id": "7caa710a8f6b4214",
"metadata": {},
"source": [
"## Setup and imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3632144a56f5392d",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:04.245053Z",
"start_time": "2026-02-01T16:26:02.956217Z"
}
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"from fau_colors import cmaps\n",
"\n",
"from pepbench.algorithms.icg import BPointExtractionPale2021, CPointExtractionScipyFindPeaks\n",
"from pepbench.example_data import get_example_dataset\n",
"from pepbench.plotting.algorithms import plot_b_point_extraction_pale2021\n",
"\n",
"%matplotlib inline\n",
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "markdown",
"id": "ac6b05c6275d34ee",
"metadata": {},
"source": [
"## Plotting style"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6c11b0c5633e3b61",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:04.265481Z",
"start_time": "2026-02-01T16:26:04.251001Z"
}
},
"outputs": [],
"source": [
"plt.close(\"all\")\n",
"palette = sns.color_palette(cmaps.faculties)\n",
"sns.set_theme(context=\"notebook\", style=\"ticks\", font=\"sans-serif\", palette=palette)\n",
"plt.rcParams[\"figure.figsize\"] = (10, 4)"
]
},
{
"cell_type": "markdown",
"id": "7c93a99454736b04",
"metadata": {},
"source": [
"## Load example dataset using get_example_dataset()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "4fbc5bf4e76bbc17",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:04.294575Z",
"start_time": "2026-02-01T16:26:04.265963Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"
ExampleDataset [2 groups/rows]\n",
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" participant | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" VP_001 | \n",
"
\n",
" \n",
" | 1 | \n",
" VP_002 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"ExampleDataset [2 groups/rows]\n",
"\n",
" participant\n",
" 0 VP_001\n",
" 1 VP_002"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# This will download the example zip automatically if it's not present locally\n",
"dataset = get_example_dataset(return_clean=True)\n",
"dataset"
]
},
{
"cell_type": "markdown",
"id": "338e3841dccd71bb",
"metadata": {},
"source": [
"### Pick the first available participant/phase from the example dataset"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "dd9cf7803c43f958",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:04.358414Z",
"start_time": "2026-02-01T16:26:04.311262Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset index (first rows):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" participant | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" VP_001 | \n",
"
\n",
" \n",
" | 1 | \n",
" VP_002 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" participant\n",
"0 VP_001\n",
"1 VP_002"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using: VP_001 None None\n"
]
},
{
"data": {
"text/html": [
"ExampleDataset [1 groups/rows]\n",
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" participant | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" VP_001 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"ExampleDataset [1 groups/rows]\n",
"\n",
" participant\n",
" 0 VP_001"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"Dataset index (first rows):\")\n",
"display(dataset.index.head(10))\n",
"\n",
"row = dataset.index.iloc[0]\n",
"participant, condition, phase = row[\"participant\"], row.get(\"condition\", None), row.get(\"phase\", None)\n",
"print(\"Using:\", participant, condition, phase)\n",
"\n",
"# create a datapoint subset for this entry\n",
"datapoint = dataset.get_subset(participant=participant)\n",
"datapoint"
]
},
{
"cell_type": "markdown",
"id": "2d930377bf78376",
"metadata": {},
"source": [
"## Run the algorithms (C-point then B-point) on the datapoint"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b6cada1a54898a9",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:04.812050Z",
"start_time": "2026-02-01T16:26:04.380786Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" b_point_sample | \n",
" nan_reason | \n",
"
\n",
" \n",
" | heartbeat_id | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 179 | \n",
" NaN | \n",
"
\n",
" \n",
" | 1 | \n",
" 533 | \n",
" NaN | \n",
"
\n",
" \n",
" | 2 | \n",
" 1009 | \n",
" NaN | \n",
"
\n",
" \n",
" | 3 | \n",
" 1466 | \n",
" NaN | \n",
"
\n",
" \n",
" | 4 | \n",
" 1873 | \n",
" NaN | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" b_point_sample nan_reason\n",
"heartbeat_id \n",
"0 179 NaN\n",
"1 533 NaN\n",
"2 1009 NaN\n",
"3 1466 NaN\n",
"4 1873 NaN"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# C-point extraction (used by Pale et al. B-point algorithm)\n",
"c_algo = CPointExtractionScipyFindPeaks()\n",
"c_algo.extract(icg=datapoint.icg, heartbeats=datapoint.heartbeats, sampling_rate_hz=datapoint.sampling_rate_icg)\n",
"\n",
"# B-point extraction (Pale et al. 2021)\n",
"b_algo = BPointExtractionPale2021()\n",
"b_algo.extract(\n",
" icg=datapoint.icg,\n",
" heartbeats=datapoint.heartbeats,\n",
" c_points=c_algo.points_,\n",
" sampling_rate_hz=datapoint.sampling_rate_icg,\n",
")\n",
"\n",
"\n",
"# show detected points table (head)\n",
"display(b_algo.points_.head())"
]
},
{
"cell_type": "markdown",
"id": "25f9c4ef5d5b7e75",
"metadata": {},
"source": [
"## 1) High-level helper plot (recommended)\n",
"Use the provided plotting helper `plot_b_point_extraction_pale2021` to visualise multiple heartbeats with\n",
"reference labels, detected C/B points and heartbeat borders."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6592ef9d08aa7811",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:28:53.537866Z",
"start_time": "2026-02-01T16:28:53.421093Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"np.int64(0)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"datapoint.heartbeats.index.min()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b1359ddd019a8bd",
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-01T16:26:05.736709Z",
"start_time": "2026-02-01T16:26:04.949624Z"
}
},
"outputs": [],
"source": [
"hb_ids = datapoint.heartbeats.index.get_level_values(\"heartbeat_id\").unique()[:5].tolist()\n",
"print(\"Plotting heartbeat ids:\", hb_ids)\n",
"fig, ax = plot_b_point_extraction_pale2021(datapoint, heartbeat_subset=hb_ids, normalize_time=True)"
]
},
{
"cell_type": "markdown",
"id": "5912d0ef67fc7ebe",
"metadata": {},
"source": [
"## 2) Low-level plotting: raw ICG with detected & reference markers and heartbeat borders"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "259f5054bcc865c7",
"metadata": {},
"outputs": [],
"source": [
"# plot raw ICG and overlay reference/detected B-points and heartbeat borders\n",
"fig, ax = plt.subplots(figsize=(20, 5))\n",
"icg = datapoint.icg.squeeze()\n",
"ax.plot(icg.index, icg.values, label=\"ICG (preprocessed)\")\n",
"\n",
"# detected b points (from algorithm result)\n",
"b_samples = b_algo.points_[\"b_point_sample\"].dropna().astype(int)\n",
"ax.scatter(icg.index[b_samples], icg.values[b_samples], color=\"C1\", marker=\"o\", label=\"Detected B\")\n",
"\n",
"# reference b points if available\n",
"try:\n",
" ref_b = datapoint.reference_labels_icg.reindex([\"ICG\"], level=\"channel\")[\"sample_relative\"]\n",
" ref_b = ref_b.droplevel([\"channel\"]).astype(int)\n",
" ax.scatter(icg.index[ref_b], icg.values[ref_b], color=\"C2\", marker=\"X\", label=\"Reference B\")\n",
"except Exception:\n",
" pass\n",
"\n",
"# heartbeat borders (start samples)\n",
"hb_borders = datapoint.heartbeats\n",
"ax.vlines(\n",
" icg.index[hb_borders[\"start_sample\"]],\n",
" ymin=icg.min(),\n",
" ymax=icg.max(),\n",
" colors=\"C3\",\n",
" linestyles=\"--\",\n",
" alpha=0.6,\n",
" label=\"Heartbeat borders\",\n",
")\n",
"\n",
"ax.legend(loc=\"upper right\")\n",
"ax.set_title(\"Raw ICG with detected and reference B-points\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "7e1545bc04e017fb",
"metadata": {},
"source": [
"## 4) Show heartbeat borders and annotations using plotting utilities\n",
"Use the internal plotting utilities to add heartbeat borders and legend handling."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a759603b1e1966a1",
"metadata": {},
"outputs": [],
"source": [
"from pepbench.plotting._utils import _add_heartbeat_borders, _add_icg_b_points, _add_pep_from_reference\n",
"\n",
"fig, ax = plt.subplots(figsize=(12, 3))\n",
"ax.plot(icg.index, icg.values, label=\"ICG\")\n",
"# heartbeat borders (use utility)\n",
"_add_heartbeat_borders(datapoint.heartbeats, ax)\n",
"# add detected B points using internal helper\n",
"_add_icg_b_points(datapoint.icg.squeeze(), b_samples, ax)\n",
"# add reference PEP spans if available\n",
"try:\n",
" _add_pep_from_reference(\n",
" datapoint.ecg,\n",
" datapoint.icg,\n",
" datapoint.reference_labels_ecg.join(datapoint.reference_labels_icg),\n",
" ax,\n",
" pep_hatch=None,\n",
" )\n",
"except Exception:\n",
" pass\n",
"ax.set_title(\"ICG with heartbeat borders and annotations\")\n",
"ax.legend()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a9cb9a9d2288679",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}