.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/example_01_getting_started.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_example_01_getting_started.py: Getting started tutorial ======================== Here is a quick overview of :py:mod:`physio` .. GENERATED FROM PYTHON SOURCE LINES 7-13 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt from pathlib import Path import physio .. GENERATED FROM PYTHON SOURCE LINES 14-33 Reading data ------------ :py:mod:`physio` aims to process physiological signals in NumPy format. Therefore, the first step is to load your data into a NumPy array. :py:mod:`physio` provides utility functions for reading certain formats, such as: * micromed * brainvision For example, cardiac activity recorded by a BrainVision system with the channel name "ECG" can be read using :py:func:`~physio.read_one_channel` by specifying: * the path to the file ("/path/to/the/file.vhdr") * the format ("brainvision") * the channel name ("ECG"). For this tutorial, we will use internal files already stored in NumPy format for demonstration purposes. Let's load them and plot a sample. .. GENERATED FROM PYTHON SOURCE LINES 34-60 .. code-block:: Python raw_resp = np.load('resp1_airflow.npy') # load respi raw_ecg = np.load('ecg1.npy') # load ecg srate = 1000. # our example signals have been recorded at 1000 Hz times = np.arange(raw_resp.size) / srate # build time vector linewidth = 0.8 fig, axs = plt.subplots(nrows=2, sharex=True) ax = axs[0] ax.plot(times, raw_resp, lw = linewidth) ax.set_title('Raw respiratory airflow signal') ax.set_ylabel('Amplitude (AU)') ax.set_ylim(-1750, -1500) ax = axs[1] ax.plot(times, raw_ecg, lw = linewidth) ax.set_title('Raw ECG (electrocardiogram)') ax.set_ylabel('Amplitude (V)') ax.set_ylim(0.012, 0.015) ax.set_xlabel('Time (s)') ax.set_xlim(185, 225) .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_001.png :alt: Raw respiratory airflow signal, Raw ECG (electrocardiogram) :srcset: /examples/images/sphx_glr_example_01_getting_started_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (185.0, 225.0) .. GENERATED FROM PYTHON SOURCE LINES 61-80 Analyze respiration ------------------- :py:func:`~physio.compute_respiration` is a high-level wrapper function that simplifies respiratory signal analysis. To use this function, you must provide: * `raw_resp` : the raw respiratory signal as a NumPy array. * `srate` : the sampling rate of the respiratory signal * `parameter_preset` : a string specifying the type of respiratory data, which determines the set of parameters used for processing. Can be one of: `human_airflow`, `human_co2`, `human_belt`, `rat_plethysmo`, or `rat_etisens_belt`. When called, :py:func:`~physio.compute_respiration` performs the following: * Preprocesses the respiratory signal (returns a NumPy array: `resp`) * Computes cycle-by-cycle features (returns a pd.DataFrame: `resp_cycles`) **Warning:** The orientation of the `raw_resp` trace is important (multiply it by -1 for reversing it if necessary). Inspiration must point downward for `human_airflow` or `human_co2`, because downward deflections are interpreted by :py:func:`~physio.compute_respiration` as inspiration. For `rat_plethysmo` or `rat_etisens_belt`, the inspiration–expiration transition must point upward. .. GENERATED FROM PYTHON SOURCE LINES 81-98 .. code-block:: Python resp, resp_cycles = physio.compute_respiration(raw_resp, srate, parameter_preset = 'human_airflow') # set 'human_airflow' as preset because example resp is an airflow from humans linewidth = 0.9 fig, ax = plt.subplots() ax.plot(times, raw_resp, lw = linewidth, label = 'raw resp signal') ax.plot(times, resp, lw = linewidth, label = 'preprocessed resp signal') ax.set_ylabel('Amplitude (AU)') ax.set_ylim(-1750, -1500) ax.set_xlim(185, 225) ax.set_xlabel('Time (s)') ax.set_title('From raw to preprocessed respiratory airflow signal') ax.legend(loc = 'upper right') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_002.png :alt: From raw to preprocessed respiratory airflow signal :srcset: /examples/images/sphx_glr_example_01_getting_started_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 99-105 Respiration cycles and features ------------------------------- `resp_cycles` is a pd.DataFrame where each row corresponds to a respiratory cycle. Columns contain cycle-specific features such as duration, amplitude, volume, etc ... See :ref:`sphx_glr_examples_example_02_respiration.py` for a complete description of the columns. .. GENERATED FROM PYTHON SOURCE LINES 106-127 .. code-block:: Python print(resp_cycles.shape) print(resp_cycles.columns) columns = ['cycle_duration', 'inspi_volume', 'expi_volume', 'total_amplitude'] # selection of some columns / metrics colors = ['tab:blue','darkorange','green','red'] # set colors units = ['s','AU','AU','AU'] # set units fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(8, 6)) fig.suptitle(f'Distribution of some metrics from N = {resp_cycles.shape[0]} detected cycles') for ax, col, color, unit in zip(axs.flatten(), columns, colors, units): ax.hist(resp_cycles[col], bins=30, color=color, edgecolor = 'k') ax.set_title(col) ax.set_xlabel(f'{col} ({unit})') ax.set_ylabel("Count") fig.tight_layout() resp_cycles .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_003.png :alt: Distribution of some metrics from N = 30 detected cycles, cycle_duration, inspi_volume, expi_volume, total_amplitude :srcset: /examples/images/sphx_glr_example_01_getting_started_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (30, 21) 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', 'inspi_peak_index', 'expi_peak_index', 'inspi_peak_time', 'expi_peak_time', 'total_volume'], dtype='str') .. raw:: html
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 inspi_peak_index expi_peak_index inspi_peak_time expi_peak_time 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.997642 195.890794 93.101770 102.789023 2993 4969 2.993 4.969 291.424431
1 8755 12470 16629 8.755 12.470 16.629 7.874 3.715 4.159 0.127000 0.471806 127.912620 120.766841 204.261166 111.836892 92.424274 9640 13479 9.640 13.479 248.679461
2 16629 20085 25589 16.629 20.085 25.589 8.960 3.456 5.504 0.111607 0.385714 117.322121 108.021751 178.600929 64.548937 114.051992 18014 20995 18.014 20.995 225.343872
3 25589 28826 35467 25.589 28.826 35.467 9.878 3.237 6.641 0.101235 0.327698 82.220884 98.005772 125.979297 46.007447 79.971850 26607 30576 26.607 30.576 180.226656
4 35467 39250 45631 35.467 39.250 45.631 10.164 3.783 6.381 0.098386 0.372196 101.588255 117.184560 127.910587 47.063516 80.847071 37283 41144 37.283 41.144 218.772816
5 45631 48992 55914 45.631 48.992 55.914 10.283 3.361 6.922 0.097248 0.326850 82.862181 102.441040 132.522182 44.166802 88.355380 46392 50698 46.392 50.698 185.303221
6 55914 59772 67325 55.914 59.772 67.325 11.411 3.858 7.553 0.087635 0.338095 120.667807 102.270537 138.805077 58.638983 80.166094 57002 61809 57.002 61.809 222.938344
7 67325 70801 78023 67.325 70.801 78.023 10.698 3.476 7.222 0.093475 0.324921 79.043735 94.684808 123.666977 45.443175 78.223802 68674 72750 68.674 72.750 173.728543
8 78023 81420 86030 78.023 81.420 86.030 8.007 3.397 4.610 0.124891 0.424254 106.575911 134.553459 183.326805 61.358012 121.968793 78917 82834 78.917 82.834 241.129370
9 86030 89213 94623 86.030 89.213 94.623 8.593 3.183 5.410 0.116374 0.370418 72.404075 89.801492 153.248258 44.234641 109.013617 86990 90996 86.990 90.996 162.205566
10 94623 97972 104423 94.623 97.972 104.423 9.800 3.349 6.451 0.102041 0.341735 636.536901 447.267064 485.434574 308.901992 176.532582 96491 100891 96.491 100.891 1083.803965
11 104423 108683 114252 104.423 108.683 114.252 9.829 4.260 5.569 0.101740 0.433411 111.393347 125.823770 173.558532 61.310891 112.247642 105392 110518 105.392 110.518 237.217117
12 114252 117877 124700 114.252 117.877 124.700 10.448 3.625 6.823 0.095712 0.346956 85.802485 130.310932 176.487994 42.373720 134.114274 115469 119319 115.469 119.319 216.113417
13 124700 127879 134461 124.700 127.879 134.461 9.761 3.179 6.582 0.102449 0.325684 99.368718 127.697288 180.930699 59.422501 121.508199 125935 129999 125.935 129.999 227.066006
14 134461 138178 145780 134.461 138.178 145.780 11.319 3.717 7.602 0.088347 0.328386 91.107038 105.601792 120.530583 46.826341 73.704242 135851 140396 135.851 140.396 196.708830
15 145780 149124 156359 145.780 149.124 156.359 10.579 3.344 7.235 0.094527 0.316098 54.976681 90.049016 107.621249 29.892126 77.729124 146325 151674 146.325 151.674 145.025697
16 156359 159809 165930 156.359 159.809 165.930 9.571 3.450 6.121 0.104482 0.360464 81.043434 92.559758 111.249025 46.559908 64.689117 157165 161764 157.165 161.764 173.603192
17 165930 169247 175415 165.930 169.247 175.415 9.485 3.317 6.168 0.105430 0.349710 87.795188 92.158942 116.860425 48.317537 68.542888 166838 171542 166.838 171.542 179.954129
18 175415 178225 184867 175.415 178.225 184.867 9.452 2.810 6.642 0.105798 0.297292 56.670496 73.249906 98.581205 33.366724 65.214481 175990 180364 175.990 180.364 129.920402
19 184867 188712 195179 184.867 188.712 195.179 10.312 3.845 6.467 0.096974 0.372867 68.358008 104.624509 131.036618 40.379954 90.656664 185838 190757 185.838 190.757 172.982517
20 195179 199483 205152 195.179 199.483 205.152 9.973 4.304 5.669 0.100271 0.431565 81.222469 105.898526 108.186857 51.809933 56.376923 196397 201509 196.397 201.509 187.120995
21 205152 209074 214162 205.152 209.074 214.162 9.010 3.922 5.088 0.110988 0.435294 106.968152 111.748564 110.797636 47.691581 63.106055 206634 210793 206.634 210.793 218.716716
22 214162 217778 223497 214.162 217.778 223.497 9.335 3.616 5.719 0.107124 0.387359 96.273488 110.557056 131.741321 55.426862 76.314458 215470 220553 215.470 220.553 206.830544
23 223497 227737 233353 223.497 227.737 233.353 9.856 4.240 5.616 0.101461 0.430195 101.875446 120.943199 124.177712 57.961557 66.216154 224499 229680 224.499 229.680 222.818645
24 233353 237747 242949 233.353 237.747 242.949 9.596 4.394 5.202 0.104210 0.457899 111.570671 142.748661 151.433624 55.897519 95.536105 234310 239786 234.310 239.786 254.319332
25 242949 247667 253240 242.949 247.667 253.240 10.291 4.718 5.573 0.097172 0.458459 147.507051 171.319857 165.743584 72.974277 92.769307 243912 249696 243.912 249.696 318.826908
26 253240 257182 263116 253.240 257.182 263.116 9.876 3.942 5.934 0.101256 0.399149 125.281328 132.788731 138.701424 61.828053 76.873371 254007 259468 254.007 259.468 258.070059
27 263116 266749 273102 263.116 266.749 273.102 9.986 3.633 6.353 0.100140 0.363809 92.320485 112.500656 142.799229 61.377405 81.421824 263675 269279 263.675 269.279 204.821141
28 273102 277759 284946 273.102 277.759 284.946 11.844 4.657 7.187 0.084431 0.393195 106.627863 137.735911 122.342380 45.115735 77.226645 274201 279953 274.201 279.953 244.363774
29 284946 288731 295014 284.946 288.731 295.014 10.068 3.785 6.283 0.099325 0.375944 81.769137 107.776736 118.126812 41.632810 76.494002 285985 291162 285.985 291.162 189.545873


.. GENERATED FROM PYTHON SOURCE LINES 128-129 All these metrics highly depend on the quality of detection of the start points of inspiration and expiration, which can be verified by visual inspection: .. GENERATED FROM PYTHON SOURCE LINES 129-146 .. code-block:: Python inspi_ind = resp_cycles['inspi_index'].values # get index of inspiration start points expi_ind = resp_cycles['expi_index'].values # get index of expiration start points fig, ax = plt.subplots() ax.plot(times, resp) ax.scatter(times[inspi_ind], resp[inspi_ind], color='green', label = 'inspiration start') ax.scatter(times[expi_ind], resp[expi_ind], color='red', label = 'expiration start') ax.set_xlim(185, 225) ax.set_xlabel('Time (s)') ax.set_ylabel('Amplitude (AU)') ax.set_ylim(-1750, -1500) ax.set_title('Visual inspection of resp cycle detection') ax.legend(loc = 'upper right') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_004.png :alt: Visual inspection of resp cycle detection :srcset: /examples/images/sphx_glr_example_01_getting_started_004.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 147-166 Analyze ECG ----------- :py:func:`~physio.compute_ecg` is a high-level wrapper function that simplifies ECG signal analysis. To use this function, you must provide: * `raw_ecg` : the raw ECG signal as a NumPy array * `srate` : the sampling rate of the ECG signal * `parameter_preset` : a string specifying the type of ECG data, which determines the set of parameters used for processing. Can be one of: `human_ecg` or `rat_ecg`. When called, :py:func:`~physio.compute_ecg` performs the following: * Preprocesses the ECG signal (returns a NumPy array: `ecg`). By default, `ecg` is normalized. * Detects R peaks (returns a pd.DataFrame: `ecg_peaks`) **Warning:** The orientation of the `raw_ecg` trace is important (multiply it by -1 for reversing it if necessary). R peaks must point upward for the highest probability of detection by :py:func:`~physio.compute_ecg`. Sometimes the R and S peaks of the QRS complex are equivalent, so orientation does not matter, because either the R or S peak will be detected and used to mark heartbeats. .. GENERATED FROM PYTHON SOURCE LINES 167-194 .. code-block:: Python ecg, ecg_peaks = physio.compute_ecg(raw_ecg, srate, parameter_preset = 'human_ecg') # set 'human_ecg' as preset because example ecg is from human r_peak_ind = ecg_peaks['peak_index'].values # get index of R peaks linewidth = 0.8 fig, axs = plt.subplots(nrows=2, sharex=True) ax = axs[0] ax.plot(times, raw_ecg, lw = linewidth) ax.scatter(times[r_peak_ind], raw_ecg[r_peak_ind], color="#C3CB22", label = 'R peak') ax.set_ylim(0.012, 0.015) ax.set_ylabel('Amplitude (V)') ax.set_title('R peak detection, plotted on raw ECG') ax.legend(loc = 'upper right') ax = axs[1] ax.plot(times, ecg, lw = linewidth) ax.scatter(times[r_peak_ind], ecg[r_peak_ind], color='#A8AE27', label = 'R peak') ax.set_xlim(185, 225) ax.set_ylim(-35, 50) ax.set_ylabel('Amplitude (AU)') ax.set_title('R peak detection, plotted on preprocessed ECG') ax.legend(loc = 'upper right') ax.set_xlabel('Time (s)') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_005.png :alt: R peak detection, plotted on raw ECG, R peak detection, plotted on preprocessed ECG :srcset: /examples/images/sphx_glr_example_01_getting_started_005.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 23.52222222222222, 'Time (s)') .. GENERATED FROM PYTHON SOURCE LINES 195-204 Heart Rate Variability metrics (time-domain) --------------------------------------------- :py:func:`~physio.compute_ecg_metrics` is a high-level wrapper function that computes time-domain Heart Rate Variability (HRV) metrics from previously detected R peaks (`ecg_peaks`). To use this function, you must provide the previously detected R peaks, `ecg_peaks`: * `ecg_peaks` : pd.DataFrame, output of the function :py:func:`~physio.compute_ecg` We can visualize these metrics and the RR interval distribution. See :ref:`sphx_glr_examples_example_03_ecg.py` for a complete description of the metrics. .. GENERATED FROM PYTHON SOURCE LINES 205-225 .. code-block:: Python ecg_metrics = physio.compute_ecg_metrics(ecg_peaks) # ecg_metrics = a pd.Series containing HRV time domain results peak_times = ecg_peaks['peak_time'].values # get R peak times of detection rri_s = np.diff(peak_times) # compute RR intervals in seconds rri_ms = rri_s * 1000 # seconds to milliseconds fig, ax = plt.subplots() ax.hist(rri_ms, bins=np.arange(500, 1400, 25), edgecolor = 'k') # plot distribution of RR intervals ax.axvline(ecg_metrics['HRV_Mean'], color='orange', label='Mean RRi') # vertical line at the mean RRi ax.axvline(ecg_metrics['HRV_Median'], color='violet', label='Median RRi') # vertical line at the median RRi ax.axvspan(ecg_metrics['HRV_Median'] - 2*ecg_metrics['HRV_Mad'], ecg_metrics['HRV_Median'] + 2*ecg_metrics['HRV_Mad'], color = 'orange', alpha = 0.1, label = 'Median +/- 2 * Median Absolute Deviation') # vertical span at the med + 2*mad ax.axvspan(ecg_metrics['HRV_Mean'] - 2*ecg_metrics['HRV_SD'], ecg_metrics['HRV_Mean'] + 2*ecg_metrics['HRV_SD'], color = 'violet', alpha = 0.1, label = 'Mean +/- 2 * Standard-Deviation') # vertical span at the mean + 2*sd ax.set_xlabel('RR interval (ms)') ax.set_ylabel('Count') ax.set_ylim(-5, 90) ax.legend(loc = 'upper center', ncols = 2) ax.set_title('Distribution or RR intervals + Heart Rate Variability metrics') print(ecg_metrics) .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_006.png :alt: Distribution or RR intervals + Heart Rate Variability metrics :srcset: /examples/images/sphx_glr_example_01_getting_started_006.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none 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 .. GENERATED FROM PYTHON SOURCE LINES 226-241 Heart Rate Variability metrics (frequency-domain) ------------------------------------------------- :py:func:`~physio.compute_hrv_psd` is a high-level wrapper function that computes frequency-domain Heart Rate Variability (HRV) metrics from previously detected R peaks (`ecg_peaks`). To use this function, you must provide the previously detected R peaks, `ecg_peaks`: * `ecg_peaks` : pd.DataFrame, output of the function :py:func:`~physio.compute_ecg` Many others parameters can be set for this function (frequency bands, size of the Welch's window, etc...). See :ref:`sphx_glr_examples_example_03_ecg.py` for more information about these. When called, :py:func:`~physio.compute_hrv_psd` performs the following: * Compute an instantaneous heart rate vector from ecg peaks and compute a Fourier transform using Welch method (returns two NumPy arrays: `psd_freqs` and `psd` giving frequency vector and power vector, respectively). * Compute HRV frequency metrics by getting power for each frequency band using trapezoïdal rule (returns a pd.Series: `psd_metrics`) We can visualize these metrics and the RR interval distribution. See :ref:`sphx_glr_examples_example_03_ecg.py` for a complete description of the metrics. .. GENERATED FROM PYTHON SOURCE LINES 242-260 .. code-block:: Python frequency_bands = {'lf': (0.04, .15), 'hf' : (0.15, .4)} # set classical cutoffs of low and high frequency bands, in a dictionnary psd_freqs, psd, psd_metrics = physio.compute_hrv_psd(ecg_peaks=ecg_peaks, frequency_bands=frequency_bands) print(psd_metrics) fig, ax = plt.subplots() ax.plot(psd_freqs, psd) colors = {'lf': '#B8860B', 'hf' : '#D2691E'} for name, freq_band in frequency_bands.items(): ax.axvspan(*freq_band, alpha=0.1, color=colors[name], label=f'{name} : {round(psd_metrics[name], 2)}') # plot one vertical span for each frequency band ax.set_xlim(0, 0.6) ax.set_xlabel('Frequency (Hz)') ax.set_ylabel('Power Spectral Density') ax.legend(loc = 'upper right') ax.set_title('HRV Power Spectral Density\n-> Frequency-Domain metrics') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_007.png :alt: HRV Power Spectral Density -> Frequency-Domain metrics :srcset: /examples/images/sphx_glr_example_01_getting_started_007.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none lf 189.890278 hf 33.775978 dtype: float64 Text(0.5, 1.0, 'HRV Power Spectral Density\n-> Frequency-Domain metrics') .. GENERATED FROM PYTHON SOURCE LINES 261-276 Cyclic deformation ------------------ :py:func:`~physio.deform_traces_to_cycle_template` is a tool used to deform traces to a cycle template. It works by stretching a trace using linear resampling based on 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. To use this function, you must provide: * `data` : nd.array. Axis of the time must always be 0, meaning of shape (n_times,...). * `times` : np.array. Time vector of the data. Shape = (n_times,) * `cycle_times` : nd.array with shape (n_cycles, n_segments + 1). Typically, for respiration, `cycle_times` is an array with 3 columns (inspi_time + expi_time + next_inspi_time) that will make deformation with 2 segments. If cycle_times is 1D, then it is converted to shape (size-1, 2). The end of every cycles must match the start of the next cycle. * `points_per_cycle` : Number of phase points per cycle * `segment_ratios` : None or float or list of float. None if 1 segment. Float or list of float if 2 segments. List of floats if > 2 segments. This is a ratio between 0 and 1 where cycle is divided. * `output_mode` : 'stacked' / 'unstacked' / 'unstacked_full'. Format of the outputs. Stacked -> 2D matrix : cycles / points per cycle. Unstacked -> 1D matrix : flattened version of the stacked. Unstacked_full returns extra-outputs. .. GENERATED FROM PYTHON SOURCE LINES 276-324 .. code-block:: Python # Here, we deform the respiratory trace by "itself": the respiratory cycle. # This leads to an average respiratory template. Importantly, this can be done using one or several segments inside the cycle. # here we have 3 times per cycle so 2 segments : # segment 1: inspiration to expiration # segment 2: expiration to next inspiration cycle_times = resp_cycles[['inspi_time', 'expi_time', 'next_inspi_time']].values # get 3 timepoints per cycle, dividing each cycle in 2 segments segment_ratios = 0.4 # ratio between 0 and 1 where cycle is divided into 2 segments deformed_resp_2seg = physio.deform_traces_to_cycle_template(resp, # resp trace to deform times, # time vector of resp trace to deform cycle_times, # times of resp cycles, used to strech points_per_cycle=40, # number of points per cycle used for linear resampling segment_ratios=segment_ratios, # ratio between 0 and 1 where cycle is divided into 2 segments output_mode='stacked' # choose a stacked version of the returned matrix (see docstrings) ) print(deformed_resp_2seg.shape, cycle_times.shape) # here we have 2 times per cycle so 1 segment: # segment 1: inspiration to next inspiration cycle_times = resp_cycles[['inspi_time', 'next_inspi_time']].values # get 2 timepoints per cycle, dividing each cycle in 1 segment (so not dividing) deformed_resp_1seg = physio.deform_traces_to_cycle_template(resp, # resp trace to deform times, # time vector of resp trace to deform cycle_times, # times of resp cycles, used to strech points_per_cycle=40, # number of points per cycle used for linear resampling segment_ratios=None, # ratio between 0 and 1 where cycle is divided into 2 segments. None in this case because 1 segment output_mode='stacked' # choose a stacked version of the returned matrix (see docstrings) ) print(deformed_resp_1seg.shape, cycle_times.shape) fig, axs = plt.subplots(ncols=2, sharey=True, figsize = (8,4)) ax = axs[0] physio.plot_cyclic_deformation(deformed_resp_2seg, segment_ratios=0.4, two_cycles=False, ax=ax) # using function physio.plot_cyclic_deformation to plot ax.set_title('Deformation: 2 segments') ax.set_ylabel('Resp Amplitude (AU)') ax = axs[1] physio.plot_cyclic_deformation(deformed_resp_1seg, segment_ratios=None, two_cycles=False, ax=ax) # using function physio.plot_cyclic_deformation to plot ax.set_title('Deformation: 1 segment') for ax in axs: ax.set_xlabel('Points per cycle (= respiratory phase)') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_008.png :alt: Deformation: 2 segments, Deformation: 1 segment :srcset: /examples/images/sphx_glr_example_01_getting_started_008.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (30, 40) (30, 3) (30, 40) (30, 2) .. GENERATED FROM PYTHON SOURCE LINES 325-330 Cyclic deformation on ECG ------------------------- Let's use the same :py:func:`~physio.deform_traces_to_cycle_template` tool for ECG trace. We can use a simple time vector: the R peak times. In this case, the ECG trace is converted as a 1-segment. .. GENERATED FROM PYTHON SOURCE LINES 331-349 .. code-block:: Python cycle_times = ecg_peaks['peak_time'].values # one cycle = R to R -> one segment by R to R period deformed_ecg = physio.deform_traces_to_cycle_template(ecg, # ecg trace to deform times, # time vector of ecg trace to deform cycle_times, # times of ecg cycles = R to R periods, used to strech points_per_cycle=300, # number of points per cycle used for linear resampling (more than for resp because ecg trace has faster dynamics) segment_ratios=None, # 1 segment so 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) # set two_cycles = True to see a concatenation of two cyclical deformations, so that we can see the whole PQRST complex ax.set_title('Two ECG cyclical deformations concatenated:\nnormalized view of the whole PQRST complex') ax.set_ylabel('Amplitude (AU)') ax.set_xlabel('Points per cycle * 2') .. image-sg:: /examples/images/sphx_glr_example_01_getting_started_009.png :alt: Two ECG cyclical deformations concatenated: normalized view of the whole PQRST complex :srcset: /examples/images/sphx_glr_example_01_getting_started_009.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (407, 300) (408,) Text(0.5, 23.52222222222222, 'Points per cycle * 2') .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.306 seconds) .. _sphx_glr_download_examples_example_01_getting_started.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: example_01_getting_started.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: example_01_getting_started.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: example_01_getting_started.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_