"""
File: app/mimic3bp_data_visualization.py
Project: 22HLT01 QUMPHY
Contact: nando.hegemann@ptb.de
Gitlab: https://gitlab.com/qumphy
Description: Create images of samples from MIMIC III BP dataset.
"""
import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from tqdm.auto import tqdm
import qumphy # local import
[docs]
def normalize_signals(signals: np.ndarray) -> np.ndarray:
"""Normalize signal data to [0, 1].
Parameters
----------
signals : np.ndarray
Signal array.
Returns
-------
:
Normalized signal array.
"""
shift = np.min(signals, axis=1).reshape(-1, 1)
scale = 1 / (np.max(signals, axis=1).reshape(-1, 1) - shift)
return scale * (signals - shift)
[docs]
def plot_signal_grid(
labels: np.ndarray,
signals: np.ndarray,
subject_ids: np.ndarray,
tag: str,
save_path: str,
dpi: int = 300,
) -> None:
"""Save a 6x6 grid of randomly sampled PPG signals colored by blood pressure.
Inner line color encodes systolic BP, outer line color encodes diastolic BP.
Parameters
----------
labels : np.ndarray
Systolic/diastolic blood pressure values, shape ``(n_samples, 2)``.
signals : np.ndarray
PPG time series.
subject_ids : np.ndarray
Subject IDs.
tag : str
Filename stem and figure title suffix.
save_path : str
Directory the ``<tag>.png`` image is written to.
dpi : int, optional
Resolution of image, by default 300.
"""
cmap = matplotlib.cm.get_cmap("rainbow", 8)
cmin = np.array([40, 40])
cmax = np.array([200, 120])
scale = 1 / (cmax - cmin)
n_rows, n_cols = 6, 6
idxs = np.random.randint(labels.shape[0], size=(n_rows, n_cols))
# create plot
layout = [[f"{i}-{j}" for j in range(n_cols)] + ["cmap1"] for i in range(n_rows)]
for i in range(n_rows):
for j in range(n_cols):
if i <= 1 and j >= n_cols - 3:
layout[i][j] = "big"
fig, ax = plt.subplot_mosaic(
layout, constrained_layout=True, figsize=(3 * n_cols + 6, 2 * n_rows)
)
for i in range(n_rows):
for j in range(n_cols):
if i > 1 or j < n_cols - 3:
label = labels[idxs[i, j]]
signal = signals[idxs[i, j]]
sid = subject_ids[idxs[i, j]]
color = cmap(scale * (label - cmin))
ax[f"{i}-{j}"].plot(signal, color=color[1], lw=3)
ax[f"{i}-{j}"].plot(signal, color=color[0], lw=1)
ax[f"{i}-{j}"].set_axis_off()
ax[f"{i}-{j}"].set_title(f"subject id: {sid}")
label = labels[idxs[0, n_cols - 1]]
signal = signals[idxs[0, n_cols - 1]]
sid = subject_ids[idxs[0, n_cols - 1]]
color = cmap(scale * (label - cmin))
ax["big"].plot(signal, color=color[1], lw=9)
ax["big"].plot(signal, color=color[0], lw=3)
ax["big"].set_axis_off()
ax["big"].set_title(f"subject id: {sid}")
norm1 = matplotlib.colors.Normalize(vmin=cmin[0], vmax=cmax[0])
norm2 = matplotlib.colors.Normalize(vmin=cmin[1], vmax=cmax[1])
ax["cmap1"].set_axis_off()
fig.colorbar(
matplotlib.cm.ScalarMappable(norm=norm1, cmap=cmap),
ax=ax["cmap1"],
label="systolic BP [mmHg]",
pad=-0.85,
fraction=0.5,
)
fig.colorbar(
matplotlib.cm.ScalarMappable(norm=norm2, cmap=cmap),
ax=ax["cmap1"],
orientation="vertical",
label="diastolic BP [mmHg]",
pad=-0.4,
fraction=0.5,
)
plt.suptitle(
"MIMIC III BP formatted"
+ f" -- {tag}"
+ " -- systolic BP = innter color"
+ " -- diastolic BP = outer color",
fontsize=30,
)
plt.savefig(save_path + tag + ".png", dpi=dpi)
plt.close()
[docs]
def main() -> None:
"""Render one PNG grid per MIMIC III BP split into ``../img/mimic3bp/``."""
# load data
data_path = "../data/mimic3bp/"
save_path = "../img/mimic3bp/"
os.makedirs(save_path, exist_ok=True)
file_ids = ["test", "validate"] + [f"train{j+1:02d}" for j in range(28)]
for fid in tqdm(file_ids):
labels, signals, subject_ids = qumphy.data.mimic3bp.load(fid, data_path)
signals = normalize_signals(signals)
# add samples of training data to tensorboard
plot_signal_grid(
labels, signals, subject_ids, tag=fid, save_path=save_path, dpi=300
)
del labels, signals, subject_ids
if __name__ == "__main__":
main()