Getting started tutorial

Here is a quick overview of physio

import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path

import physio

physio module overview  ———————-

physio has utility functions for reading some formats like:

  • micromed

  • brainvision

 Here, we use an internal file in the numpy format for the demo

raw_resp = np.load('resp1.npy')
raw_ecg = np.load('ecg1.npy')
srate = 1000.
times = np.arange(raw_resp.size) / srate

fig, axs = plt.subplots(nrows=2, sharex=True)
ax = axs[0]
ax.plot(times, raw_resp)
ax.set_ylabel('raw resp')

ax = axs[1]
ax.plot(times, raw_ecg)
ax.set_ylabel('raw ECG')

ax.set_xlim(185, 225)
example 01 getting started
(185.0, 225.0)

Analyze respiration

compute_respiration() is an easy function to:

  • preprocess the respiratory signal (resp)

  • compute cycle features (resp_cycles)

resp, resp_cycles = physio.compute_respiration(raw_resp, srate)

fig, ax = plt.subplots()
ax.plot(times, raw_resp)
ax.plot(times, resp)
ax.set_xlim(185, 225)
example 01 getting started
(185.0, 225.0)

Respiration cycles and features

resp_cycles is a dataframe containing all respiratory cycles as rows. Columns contain features like duration, amplitudes, volumes.

print(resp_cycles.shape)
print(resp_cycles.columns)

columns = ['cycle_duration', 'inspi_volume', 'expi_volume', 'total_amplitude' ]
resp_cycles[columns].plot(kind='hist', subplots=True, sharex=False, layout=(2, 2), bins=50)

resp_cycles
example 01 getting started
(30, 17)
Index(['inspi_index', 'expi_index', 'next_inspi_index', 'inspi_time',
       'expi_time', 'next_inspi_time', 'cycle_duration', 'inspi_duration',
       'expi_duration', 'cycle_freq', 'cycle_ratio', 'inspi_volume',
       'expi_volume', 'total_amplitude', 'inspi_amplitude', 'expi_amplitude',
       'total_volume'],
      dtype='object')
inspi_index expi_index next_inspi_index inspi_time expi_time next_inspi_time cycle_duration inspi_duration expi_duration cycle_freq cycle_ratio inspi_volume expi_volume total_amplitude inspi_amplitude expi_amplitude total_volume
0 963 3849 8755 0.963 3.849 8.755 7.792 2.886 4.906 0.128337 0.370380 163.426788 127.473507 195.890794 93.101770 102.789023 290.900295
1 8755 12470 16629 8.755 12.470 16.629 7.874 3.715 4.159 0.127000 0.471806 127.912620 120.308562 204.261166 111.836892 92.424274 248.221182
2 16629 20085 25589 16.629 20.085 25.589 8.960 3.456 5.504 0.111607 0.385714 117.322121 107.558724 178.600929 64.548937 114.051992 224.880845
3 25589 28826 35467 25.589 28.826 35.467 9.878 3.237 6.641 0.101235 0.327698 82.220884 97.420046 125.979297 46.007447 79.971850 179.640929
4 35467 39250 45631 35.467 39.250 45.631 10.164 3.783 6.381 0.098386 0.372196 101.588255 116.508693 127.910587 47.063516 80.847071 218.096948
5 45631 48992 55914 45.631 48.992 55.914 10.283 3.361 6.922 0.097248 0.326850 82.862181 101.559723 132.522182 44.166802 88.355380 184.421903
6 55914 59772 67325 55.914 59.772 67.325 11.411 3.858 7.553 0.087635 0.338095 120.667807 100.884166 138.805077 58.638983 80.166094 221.551973
7 67325 70801 78023 67.325 70.801 78.023 10.698 3.476 7.222 0.093475 0.324921 79.043735 93.372582 123.666977 45.443175 78.223802 172.416317
8 78023 81420 86030 78.023 81.420 86.030 8.007 3.397 4.610 0.124891 0.424254 106.575911 134.036611 183.326805 61.358012 121.968793 240.612522
9 86030 89213 94623 86.030 89.213 94.623 8.593 3.183 5.410 0.116374 0.370418 72.404075 89.502706 153.248258 44.234641 109.013617 161.906780
10 94623 97972 104423 94.623 97.972 104.423 9.800 3.349 6.451 0.102041 0.341735 636.536901 446.964751 485.434574 308.901992 176.532582 1083.501652
11 104423 108683 114252 104.423 108.683 114.252 9.829 4.260 5.569 0.101740 0.433411 111.393347 125.571094 173.558532 61.310891 112.247642 236.964441
12 114252 117877 124700 114.252 117.877 124.700 10.448 3.625 6.823 0.095712 0.346956 85.802485 129.556603 176.487994 42.373720 134.114274 215.359089
13 124700 127879 134461 124.700 127.879 134.461 9.761 3.179 6.582 0.102449 0.325684 99.368718 127.133681 180.930699 59.422501 121.508199 226.502400
14 134461 138178 145780 134.461 138.178 145.780 11.319 3.717 7.602 0.088347 0.328386 91.107038 105.150867 120.530583 46.826341 73.704242 196.257905
15 145780 149124 156359 145.780 149.124 156.359 10.579 3.344 7.235 0.094527 0.316098 54.976681 88.156066 107.621249 29.892126 77.729124 143.132747
16 156359 159809 165930 156.359 159.809 165.930 9.571 3.450 6.121 0.104482 0.360464 81.043434 91.381354 111.249025 46.559908 64.689117 172.424788
17 165930 169247 175415 165.930 169.247 175.415 9.485 3.317 6.168 0.105430 0.349710 87.795188 91.883290 116.860425 48.317537 68.542888 179.678477
18 175415 178225 184867 175.415 178.225 184.867 9.452 2.810 6.642 0.105798 0.297292 56.670496 72.894943 98.581205 33.366724 65.214481 129.565439
19 184867 188712 195179 184.867 188.712 195.179 10.312 3.845 6.467 0.096974 0.372867 68.358008 104.282206 131.036618 40.379954 90.656664 172.640214
20 195179 199483 205152 195.179 199.483 205.152 9.973 4.304 5.669 0.100271 0.431565 81.222469 105.761289 108.186857 51.809933 56.376923 186.983757
21 205152 209074 214162 205.152 209.074 214.162 9.010 3.922 5.088 0.110988 0.435294 106.968152 111.652420 110.797636 47.691581 63.106055 218.620572
22 214162 217778 223497 214.162 217.778 223.497 9.335 3.616 5.719 0.107124 0.387359 96.273488 110.147711 131.741321 55.426862 76.314458 206.421199
23 223497 227737 233353 223.497 227.737 233.353 9.856 4.240 5.616 0.101461 0.430195 101.875446 120.651586 124.177712 57.961557 66.216154 222.527032
24 233353 237747 242949 233.353 237.747 242.949 9.596 4.394 5.202 0.104210 0.457899 111.570671 142.699240 151.433624 55.897519 95.536105 254.269911
25 242949 247667 253240 242.949 247.667 253.240 10.291 4.718 5.573 0.097172 0.458459 147.507051 170.988683 165.743584 72.974277 92.769307 318.495735
26 253240 257182 263116 253.240 257.182 263.116 9.876 3.942 5.934 0.101256 0.399149 125.281328 132.751964 138.701424 61.828053 76.873371 258.033292
27 263116 266749 273102 263.116 266.749 273.102 9.986 3.633 6.353 0.100140 0.363809 92.320485 112.162236 142.799229 61.377405 81.421824 204.482721
28 273102 277759 284946 273.102 277.759 284.946 11.844 4.657 7.187 0.084431 0.393195 106.627863 137.053786 122.342380 45.115735 77.226645 243.681649
29 284946 288731 295014 284.946 288.731 295.014 10.068 3.785 6.283 0.099325 0.375944 81.769137 107.515945 118.126812 41.632810 76.494002 189.285082


inspi_ind = resp_cycles['inspi_index'].values
expi_ind = resp_cycles['expi_index'].values

fig, ax = plt.subplots()
ax.plot(times, resp)
ax.scatter(times[inspi_ind], resp[inspi_ind], color='green')
ax.scatter(times[expi_ind], resp[expi_ind], color='red')
ax.set_xlim(185, 225)
example 01 getting started
(185.0, 225.0)

Analyse ECG

compute_ecg() is an easy function to:

  • Preprocess the ECG signal output, which is normalized by default (ecg)

  • Detect R peaks (ecg_peaks)

ecg, ecg_peaks = physio.compute_ecg(raw_ecg, srate)

r_peak_ind = ecg_peaks['peak_index'].values

fig, axs = plt.subplots(nrows=2, sharex=True)
ax = axs[0]
ax.plot(times, raw_ecg)
ax.scatter(times[r_peak_ind], raw_ecg[r_peak_ind], color='#A8AE27')

ax = axs[1]
ax.plot(times, ecg)
ax.scatter(times[r_peak_ind], ecg[r_peak_ind], color='#A8AE27')
ax.set_xlim(185, 225)
example 01 getting started
(185.0, 225.0)
ECG metrics

 compute_ecg_metrics() is a simple function to compute time-domain Heart Rate Variability (HRV) metrics.

 We can visualize these metrics and the RR interval distribution.

ecg_metrics = physio.compute_ecg_metrics(ecg_peaks)

fig, ax = plt.subplots()
ax.hist(np.diff(ecg_peaks['peak_time']) * 1000., bins=np.arange(0, 1400, 10), alpha=0.5)
ax.axvline(ecg_metrics['HRV_Mean'], color='orange', label='HRV_Mean')
ax.axvline(ecg_metrics['HRV_Median'], color='violet', label='HRV_Median')
ax.set_xlabel('HRV [ms]')
ax.legend()
print(ecg_metrics)
example 01 getting started
HRV_Mean         734.444717
HRV_SD           145.936125
HRV_Median       678.000000
HRV_Mad          115.642973
HRV_CV             0.198703
HRV_MCV            0.170565
HRV_Asymmetry    -56.444717
HRV_RMSSD        103.553299
dtype: float64
Cyclic deformation

 deform_traces_to_cycle_template() is a tool to deform traces  to a cycle template by stretching with linear resampling to a fixed number of

points per cycle.

This is helpful to explore if features of a signal are driven by a cyclic phenomenon like respiration.

 Here, we deform the signal trace by “itself” : the respiratory cycle.  This leads to an average respiratory template.

 Importantly, this can be done using one or several segment inside the cycle.

# here we have 3 times per cycle so 2 segments
cycle_times = resp_cycles[['inspi_time', 'expi_time', 'next_inspi_time']].values
deformed_resp_1seg = physio.deform_traces_to_cycle_template(resp, times, cycle_times,
                                                points_per_cycle=40, segment_ratios=0.4,
                                                output_mode='stacked')
print(deformed_resp_1seg.shape, cycle_times.shape)

# here we have 2 times per cycle so 1 segment
cycle_times = resp_cycles[['inspi_time', 'next_inspi_time']].values
deformed_resp_2seg = physio.deform_traces_to_cycle_template(resp, times, cycle_times,
                                                points_per_cycle=40, segment_ratios=None,
                                                output_mode='stacked')
print(deformed_resp_2seg.shape, cycle_times.shape)

fig, axs = plt.subplots(ncols=2, sharey=True)
physio.plot_cyclic_deformation(deformed_resp_1seg, segment_ratios=None, two_cycles=False, ax=axs[0])
axs[0].set_title('Deformation 2 segments')
physio.plot_cyclic_deformation(deformed_resp_2seg, segment_ratios=None, two_cycles=False, ax=axs[1])
axs[1].set_title('Deformation 1 segment')
Deformation 2 segments, Deformation 1 segment
(30, 40) (30, 3)
(30, 40) (30, 2)

Text(0.5, 1.0, 'Deformation 1 segment')
Cyclic deformation on ECG

 Let’s use the same for ECG trace

We can also use a simple vector in this case it is converted a a 1 segment case.

# This is 1 segment
cycle_times = ecg_peaks['peak_time'].values
deformed_ecg = physio.deform_traces_to_cycle_template(ecg, times, cycle_times,
                                                points_per_cycle=300, segment_ratios=None,
                                                output_mode='stacked')
print(deformed_ecg.shape, cycle_times.shape)

fig, ax = plt.subplots()
physio.plot_cyclic_deformation(deformed_ecg, two_cycles=True, ax=ax)
ax.set_title('Two ECG cycle averaged')
Two ECG cycle averaged
(407, 300) (408,)

Text(0.5, 1.0, 'Two ECG cycle averaged')
plt.show()

Total running time of the script: (0 minutes 2.252 seconds)

Gallery generated by Sphinx-Gallery