Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate physutils - Physio object usage #54

Merged
merged 40 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2536086
Add physutils dependency placeholder
maestroque Jun 12, 2024
f047587
Initial Physio object integration in cardiac.py
maestroque Jun 12, 2024
c7fc2eb
Style fixes
maestroque Jun 12, 2024
ec8a3de
Minor cardiac.py physio initialization fix
maestroque Jun 12, 2024
67c4d21
Integrate Physio object for respiratory and multimodal metrics
maestroque Jun 12, 2024
2ffa465
Add sample support for object and function oriented usage of metric f…
maestroque Jun 12, 2024
9fa3467
Make metric functions operations
maestroque Jun 24, 2024
380ab65
Add Physio and non-Physio compatibility to cardiac.py
maestroque Jun 24, 2024
59ee6c8
Add Physio and non-Physio compatibility to chest_belt.py
maestroque Jun 24, 2024
56abb72
Add Physio and non-Physio compatibility to retroicor
maestroque Jun 24, 2024
2c19a65
Fix CRF, iCRF and RRF calculation
maestroque Jun 24, 2024
c28914c
Fix cardiac_phase test, return Physio object and metric to update his…
maestroque Jun 24, 2024
625d45f
Fix chest_belt tests, return Physio object and metric to update histo…
maestroque Jun 24, 2024
acf960d
Update RVT test
maestroque Jun 24, 2024
62e4b6f
Fix respiratory_phase_smoke test
maestroque Jun 24, 2024
e60d49e
Return physio in retroicor and specify raised error type in test_mirr…
maestroque Jun 24, 2024
3dbf656
Add loguru as a dependency
maestroque Jun 24, 2024
f7d7811
Add Physio object use cardiac phase unit test
maestroque Jun 25, 2024
907faba
Remove test log
maestroque Jun 25, 2024
2d9fd75
Add physutils dependency and peakdet version
maestroque Jul 18, 2024
366175a
Update peakdet dependency
maestroque Jul 19, 2024
533c80e
Minor fix
maestroque Jul 22, 2024
3fba78c
circleci: python version upgrade
maestroque Jul 22, 2024
43576d0
circleci: python version migration to 3.8 and 3.12
maestroque Jul 22, 2024
e2f2241
Minor CI fix
maestroque Jul 22, 2024
9efbf5f
CI: Change minimum python version to 3.9
maestroque Jul 22, 2024
ba5dcbc
CI: Test for python 3.9 and 3.11
maestroque Jul 22, 2024
9f5e162
Store computed metrics inside the Physio object
maestroque Jul 22, 2024
696d29c
Merge branch 'physiopy:master' into integrate-physutils
maestroque Jul 23, 2024
daaed9c
Update .all-contributorsrc
maestroque Jul 23, 2024
00b0f56
Merge branch 'physiopy:master' into integrate-physutils
maestroque Aug 9, 2024
bc300f0
Add wrapper to determine whether to return a metric or a physio object
maestroque Aug 10, 2024
9883ce2
[deps] Cap numpy to <2.0
maestroque Aug 10, 2024
181304f
[docs]: Update computing metrics
maestroque Aug 10, 2024
43107db
Metric or Physio returning optimization
maestroque Aug 11, 2024
b0f4110
Add Metric class for easier properties accessing
maestroque Aug 11, 2024
10509bd
More unit tests, physio/metric wrapper optimization, doc fixes
maestroque Aug 21, 2024
612c616
Minor fix
maestroque Aug 21, 2024
e528d21
[test] Fix failing warning assertion
maestroque Aug 25, 2024
6266b6f
Add updated physutils version
maestroque Aug 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions phys2denoise/metrics/cardiac.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def _cardiac_metrics(
peaks=None,
window=6,
central_measure="mean",
return_physio=False,
**kwargs,
):
"""
Compute cardiac metrics.
Expand Down Expand Up @@ -154,7 +154,7 @@ def _cardiac_metrics(
@due.dcite(references.CHANG_CUNNINGHAM_GLOVER_2009)
@return_physio_or_metric()
@physio.make_operation()
def heart_rate(data, fs=None, peaks=None, window=6, central_measure="mean"):
def heart_rate(data, fs=None, peaks=None, window=6, central_measure="mean", **kwargs):
"""
Compute average heart rate (HR) in a sliding window.
Expand Down Expand Up @@ -213,6 +213,7 @@ def heart_rate(data, fs=None, peaks=None, window=6, central_measure="mean"):
peaks=peaks,
window=window,
central_measure=central_measure,
**kwargs,
)

return data, hr
Expand All @@ -221,7 +222,9 @@ def heart_rate(data, fs=None, peaks=None, window=6, central_measure="mean"):
@due.dcite(references.PINHERO_ET_AL_2016)
@return_physio_or_metric()
@physio.make_operation()
def heart_rate_variability(data, fs=None, peaks=None, window=6, central_measure="mean"):
def heart_rate_variability(
data, fs=None, peaks=None, window=6, central_measure="mean", **kwargs
):
"""
Compute average heart rate variability (HRV) in a sliding window.
Expand Down Expand Up @@ -278,6 +281,7 @@ def heart_rate_variability(data, fs=None, peaks=None, window=6, central_measure=
peaks=peaks,
window=window,
central_measure=central_measure,
**kwargs,
)

return data, hrv
Expand All @@ -286,7 +290,9 @@ def heart_rate_variability(data, fs=None, peaks=None, window=6, central_measure=
@due.dcite(references.CHEN_2020)
@return_physio_or_metric()
@physio.make_operation()
def heart_beat_interval(data, fs=None, peaks=None, window=6, central_measure="mean"):
def heart_beat_interval(
data, fs=None, peaks=None, window=6, central_measure="mean", **kwargs
):
"""
Compute average heart beat interval (HBI) in a sliding window.
Expand Down Expand Up @@ -336,14 +342,15 @@ def heart_beat_interval(data, fs=None, peaks=None, window=6, central_measure="me
peaks=peaks,
window=window,
central_measure=central_measure,
**kwargs,
)

return data, hbi


@return_physio_or_metric()
@physio.make_operation()
def cardiac_phase(data, slice_timings, n_scans, t_r, fs=None, peaks=None):
def cardiac_phase(data, slice_timings, n_scans, t_r, fs=None, peaks=None, **kwargs):
"""Calculate cardiac phase from cardiac peaks.
Assumes that timing of cardiac events are given in same units
Expand Down
10 changes: 5 additions & 5 deletions phys2denoise/metrics/chest_belt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@return_physio_or_metric()
@physio.make_operation()
def respiratory_variance_time(
data, fs=None, peaks=None, troughs=None, lags=(0, 4, 8, 12)
data, fs=None, peaks=None, troughs=None, lags=(0, 4, 8, 12), **kwargs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data, fs=None, peaks=None, troughs=None, lags=(0, 4, 8, 12), **kwargs
data, peaks=None, troughs=None, fs=None, lags=(0, 4, 8, 12), **kwargs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have peaks and troughs first when possible (and, in general, avoid changing the order of inputs as much as possible), but if it makes things too complicated with the wrapper, then no problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

):
"""
Implement the Respiratory Variance over Time (Birn et al. 2006).
Expand Down Expand Up @@ -113,7 +113,7 @@ def respiratory_variance_time(
@due.dcite(references.POWER_2018)
@return_physio_or_metric()
@physio.make_operation()
def respiratory_pattern_variability(data, window):
def respiratory_pattern_variability(data, window, **kwargs):
"""Calculate respiratory pattern variability.
Parameters
Expand Down Expand Up @@ -161,7 +161,7 @@ def respiratory_pattern_variability(data, window):
@due.dcite(references.POWER_2020)
@return_physio_or_metric()
@physio.make_operation()
def env(data, fs=None, window=10):
def env(data, fs=None, window=10, **kwargs):
"""Calculate respiratory pattern variability across a sliding window.
Parameters
Expand Down Expand Up @@ -245,7 +245,7 @@ def _respiratory_pattern_variability(data, window):
@due.dcite(references.CHANG_GLOVER_2009)
@return_physio_or_metric()
@physio.make_operation()
def respiratory_variance(data, fs=None, window=6):
def respiratory_variance(data, fs=None, window=6, **kwargs):
"""Calculate respiratory variance.
Parameters
Expand Down Expand Up @@ -310,7 +310,7 @@ def respiratory_variance(data, fs=None, window=6):

@return_physio_or_metric()
@physio.make_operation()
def respiratory_phase(data, n_scans, slice_timings, t_r, fs=None):
def respiratory_phase(data, n_scans, slice_timings, t_r, fs=None, **kwargs):
"""Calculate respiratory phase from respiratory signal.
Parameters
Expand Down
1 change: 1 addition & 0 deletions phys2denoise/metrics/multimodal.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def retroicor(
physio_type=None,
fs=None,
cardiac_peaks=None,
**kwargs,
):
"""Compute RETROICOR regressors.
Expand Down
5 changes: 3 additions & 2 deletions phys2denoise/metrics/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,9 @@ def wrapper(*args, **kwargs):
physio._computed_metrics[func.__name__] = dict(
metric=metric, args=kwargs
)
if return_physio:
return physio, metric
return_physio_value = kwargs.get("return_physio", return_physio)
if return_physio_value:
return physio
else:
return metric
else:
Expand Down
18 changes: 17 additions & 1 deletion phys2denoise/tests/test_metrics_cardiac.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,28 @@ def test_cardiac_phase_smoke_physio_obj():
data = np.zeros(peaks.shape)
phys = physio.Physio(data, sample_rate, physio_type="cardiac")
phys._metadata["peaks"] = peaks
phys, card_phase = cardiac.cardiac_phase(

# Test where the physio object is returned
phys = cardiac.cardiac_phase(
phys,
slice_timings=slice_timings,
n_scans=n_scans,
t_r=t_r,
)
assert phys.history[0][0] == "phys2denoise.metrics.cardiac.cardiac_phase"
assert phys.computed_metrics["cardiac_phase"]["metric"].ndim == 2
maestroque marked this conversation as resolved.
Show resolved Hide resolved
assert phys.computed_metrics["cardiac_phase"]["metric"].shape == (
n_scans,
slice_timings.size,
)

# Test where the metric is returned
card_phase = cardiac.cardiac_phase(
phys,
slice_timings=slice_timings,
n_scans=n_scans,
t_r=t_r,
return_physio=False,
)
assert card_phase.ndim == 2
assert card_phase.shape == (n_scans, slice_timings.size)