B Point Plotting Example#

This notebook demonstrates running a B-point extraction (Pale et al., 2021) on the example dataset and several plotting styles: low-level plotting, split/zoomed axes, showing reference points, detected points, and heartbeat borders.

Setup and imports#

[1]:
import matplotlib.pyplot as plt
import seaborn as sns
from fau_colors import cmaps

from pepbench.algorithms.icg import BPointExtractionPale2021, CPointExtractionScipyFindPeaks
from pepbench.example_data import get_example_dataset
from pepbench.plotting.algorithms import plot_b_point_extraction_pale2021

%matplotlib inline
%load_ext autoreload
%autoreload 2

Plotting style#

[2]:
plt.close("all")
palette = sns.color_palette(cmaps.faculties)
sns.set_theme(context="notebook", style="ticks", font="sans-serif", palette=palette)
plt.rcParams["figure.figsize"] = (10, 4)

Load example dataset using get_example_dataset()#

[3]:
# This will download the example zip automatically if it's not present locally
dataset = get_example_dataset(return_clean=True)
dataset
[3]:

ExampleDataset [2 groups/rows]

participant
0 VP_001
1 VP_002

Pick the first available participant/phase from the example dataset#

[4]:
print("Dataset index (first rows):")
display(dataset.index.head(10))

row = dataset.index.iloc[0]
participant, condition, phase = row["participant"], row.get("condition", None), row.get("phase", None)
print("Using:", participant, condition, phase)

# create a datapoint subset for this entry
datapoint = dataset.get_subset(participant=participant)
datapoint
Dataset index (first rows):
participant
0 VP_001
1 VP_002
Using: VP_001 None None
[4]:

ExampleDataset [1 groups/rows]

participant
0 VP_001

Run the algorithms (C-point then B-point) on the datapoint#

[5]:
# C-point extraction (used by Pale et al. B-point algorithm)
c_algo = CPointExtractionScipyFindPeaks()
c_algo.extract(icg=datapoint.icg, heartbeats=datapoint.heartbeats, sampling_rate_hz=datapoint.sampling_rate_icg)

# B-point extraction (Pale et al. 2021)
b_algo = BPointExtractionPale2021()
b_algo.extract(
    icg=datapoint.icg,
    heartbeats=datapoint.heartbeats,
    c_points=c_algo.points_,
    sampling_rate_hz=datapoint.sampling_rate_icg,
)


# show detected points table (head)
display(b_algo.points_.head())
b_point_sample nan_reason
heartbeat_id
0 179 NaN
1 533 NaN
2 1009 NaN
3 1466 NaN
4 1873 NaN

1) High-level helper plot (recommended)#

Use the provided plotting helper plot_b_point_extraction_pale2021 to visualise multiple heartbeats with reference labels, detected C/B points and heartbeat borders.

[6]:
datapoint.heartbeats.index.min()
[6]:
np.int64(0)
[ ]:
hb_ids = datapoint.heartbeats.index.get_level_values("heartbeat_id").unique()[:5].tolist()
print("Plotting heartbeat ids:", hb_ids)
fig, ax = plot_b_point_extraction_pale2021(datapoint, heartbeat_subset=hb_ids, normalize_time=True)

2) Low-level plotting: raw ICG with detected & reference markers and heartbeat borders#

[ ]:
# plot raw ICG and overlay reference/detected B-points and heartbeat borders
fig, ax = plt.subplots(figsize=(20, 5))
icg = datapoint.icg.squeeze()
ax.plot(icg.index, icg.values, label="ICG (preprocessed)")

# detected b points (from algorithm result)
b_samples = b_algo.points_["b_point_sample"].dropna().astype(int)
ax.scatter(icg.index[b_samples], icg.values[b_samples], color="C1", marker="o", label="Detected B")

# reference b points if available
try:
    ref_b = datapoint.reference_labels_icg.reindex(["ICG"], level="channel")["sample_relative"]
    ref_b = ref_b.droplevel(["channel"]).astype(int)
    ax.scatter(icg.index[ref_b], icg.values[ref_b], color="C2", marker="X", label="Reference B")
except Exception:
    pass

# heartbeat borders (start samples)
hb_borders = datapoint.heartbeats
ax.vlines(
    icg.index[hb_borders["start_sample"]],
    ymin=icg.min(),
    ymax=icg.max(),
    colors="C3",
    linestyles="--",
    alpha=0.6,
    label="Heartbeat borders",
)

ax.legend(loc="upper right")
ax.set_title("Raw ICG with detected and reference B-points")
plt.show()

4) Show heartbeat borders and annotations using plotting utilities#

Use the internal plotting utilities to add heartbeat borders and legend handling.

[ ]:
from pepbench.plotting._utils import _add_heartbeat_borders, _add_icg_b_points, _add_pep_from_reference

fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(icg.index, icg.values, label="ICG")
# heartbeat borders (use utility)
_add_heartbeat_borders(datapoint.heartbeats, ax)
# add detected B points using internal helper
_add_icg_b_points(datapoint.icg.squeeze(), b_samples, ax)
# add reference PEP spans if available
try:
    _add_pep_from_reference(
        datapoint.ecg,
        datapoint.icg,
        datapoint.reference_labels_ecg.join(datapoint.reference_labels_icg),
        ax,
        pep_hatch=None,
    )
except Exception:
    pass
ax.set_title("ICG with heartbeat borders and annotations")
ax.legend()
plt.show()
[ ]:

Download Notebook
(Right-Click -> Save Link As...)