diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..4316096 --- /dev/null +++ b/README.rst @@ -0,0 +1,22 @@ +phys2denoise: A toolbox for physiological metrics calculation +============================================================= + +This package is designed for calculating physiological metrics, derived specifically cardiac and respiratory signals, to use in fMRI denoising. + + +.. image:: https://readthedocs.org/projects/phys2denoise/badge/?version=latest + :target: http://phys2denoise.readthedocs.io/en/latest +.. image:: https://img.shields.io/badge/license-Apache%202-blue.svg + :target: http://www.apache.org/licenses/LICENSE-2.0 +.. image:: https://img.shields.io/badge/python-3.6+-blue.svg + :target: https://www.python.org/downloads/ + + +.. _licensing: + +License Information +------------------- + +This codebase is licensed under the Apache License, Version 2.0. The full +license can be found in the `LICENSE `_ file in the ``phys2denoise`` distribution. You may also +obtain a copy of the license at: http://www.apache.org/licenses/LICENSE-2.0. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..f610428 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = phys2denoise +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..b419f38 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,34 @@ +.. _api_ref: +API +=== + +.. py:module:: phys2denoise + +Cardiac data +------------ + +.. automodule:: phys2denoise.metrics.cardiac + :members: heart_rate, heart_rate_variability, heart_beat_interval, cardiac_phase + +Respiratory data +---------------- + +.. automodule:: phys2denoise.metrics.chest_belt + :members: respiratory_cariance_time, respiratory_pattern_variability, env, respiratory_variance, respiratory_phase + +Multimodal data +--------------- + +.. autofunction:: phys2denoise.multimodal.retroicor + +Response functions +------------------ + +.. automodule:: phys2denoise.metrics.responses + :members: crf, icrf, rrf + +Utilities +--------- + +.. automodule:: phys2denoise.metrics.utils + :members: print_metric_call, mirrorpad_1d, rms_envelope_1d, apply_lags, apply_function_in_sliding_window, convolve_and_rescale, export_metric diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..e42ac87 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +import os +import sys + +import matplotlib as mpl + +mpl.use("Agg") + +# -- Project information ----------------------------------------------------- + +# Add project name, copyright holder, and author(s) +project = "phys2denoise" +copyright = "2024, physiopy" +author = "physiopy" + +# Import project to get version info +sys.path.insert(0, os.path.abspath(os.path.pardir)) +import phys2denoise # noqa + +# The short X.Y version +version = phys2denoise.__version__ +# The full version, including alpha/beta/rc tags +release = phys2denoise.__version__ + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "matplotlib.sphinxext.plot_directive", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", +] + +# Generate the API documentation when building +autosummary_generate = True +numpydoc_show_class_members = False +autoclass_content = "class" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +import sphinx_rtd_theme # noqa + +html_theme = "sphinx_rtd_theme" +html_show_sourcelink = False + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = "peakdetdoc" + +# -- Extension configuration ------------------------------------------------- +intersphinx_mapping = { + "matplotlib": ("https://matplotlib.org", None), + "numpy": ("https://docs.scipy.org/doc/numpy", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), +} + +plot_include_source = True +plot_formats = [("png", 90)] +plot_html_show_formats = False +plot_html_show_source_link = False diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..590f394 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,11 @@ +.. include:: ../README.rst + +Contents +-------- + +.. toctree:: + :maxdepth: 1 + + installation + usage + api diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..fc61add --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,35 @@ +.. _installation_setup: + +Installation and setup +====================== + +.. _basic_installation: + +Basic installation +------------------ + +The easiest way to install ``phys2denoise`` is to use ``pip``. Assuming you have +Python >= 3.6 installed, you can install ``phys2denoise`` by opening a terminal +and running the following: + +.. code-block:: bash + + pip install phys2denoise + +.. warning:: + + If you encounter an ImportError related to numpy.core.multiarray, please try to update + your matplotlib version to 3.9. + +Developer installation +---------------------- + +This package requires Python >= 3.6. Assuming you have the correct version of +Python installed, you can install ``phys2denoise`` by opening a terminal and running +the following: + +.. code-block:: bash + + git clone https://github.com/physiopy/phys2denoise.git + cd phys2denoise + pip install -e .[dev] diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..ed30bc9 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +-r ../requirements.txt +sphinx>=1.2 +sphinx_rtd_theme diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..58b7c89 --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,10 @@ +.. _usage: + +User guide +========== + +.. toctree:: + :numbered: + + user_guide/metrics.rst + user_guide/exporting.rst diff --git a/docs/user_guide/exporting.rst b/docs/user_guide/exporting.rst new file mode 100644 index 0000000..5674a34 --- /dev/null +++ b/docs/user_guide/exporting.rst @@ -0,0 +1,33 @@ +.. _usage_exporting: + +Exporting physiological data metrics +------------------------------------ +Another feature of the :py:mod:`phys2denoise` package is the ability to export the computed physiological data metrics to a file, with various parameters. +This can be done using the :py:func:`export_metric` function, which provides the following capabilities: + +- Exporting the computed metrics, resampled at the TR of the fMRI data, along with the original data. +- Flagging if the exported data is the convolved version or if the metric contains lags of itself, resulting in appropriate file naming. +- Defining the output file extension and file prefix. +- Defining the number of timepoints to be considered. + +The following example shows how to export the computed respiratory variance time using a Physio object. In the following example, +we consider that the Physio object is ``resp``, containing the respiratory data, peaks and troughs. + +.. code-block:: python + + from phys2denoise.metrics.chest_belt import respiratory_variance_time + from phys2denoise.metrics.utils import export_metric + + RVT = respiratory_variance_time( + resp.data, resp.peaks, resp.troughs, resp.fs, lags=(0, 4, 8, 12) + ) + + export_metric( + RVT, + resp.fs, + tr=1.5, + fileprefix="data/sub-002_ses-01_task-rest_run-01_RVT", + ntp=400, + is_convolved=False, + has_lags=True, + ) diff --git a/docs/user_guide/metrics.rst b/docs/user_guide/metrics.rst new file mode 100644 index 0000000..e387600 --- /dev/null +++ b/docs/user_guide/metrics.rst @@ -0,0 +1,76 @@ +.. _usage_metrics: + +Computing physiological data metrics +------------------------------------- +The :py:mod:`phys2denoise` package provides a set of functions to compute physiological data metrics. The set of supported metrics +includes: + +- Cardiac metrics + - Cardiac phase + - Heart rate + - Heart rate variability + - Heart beat interval +- Respiratory metrics + - Respiratory phase + - Respiratory variance + - Respiratory pattern variability + - Envelope +- Multimodal metrics + - RETROICOR + +All of the metrics computation function definitions, descriptions and references can be found in :ref:`api_ref`. + + +Using a Physio object +##################### + +Physiological data metrics can be easily computed using Physio objects, from the :py:mod:`physutils` module, +on which the physiological data will be loaded. + +The following example shows how to compute the respiratory variance time using a Physio object. + +.. code-block:: python + + from physutils import io + from phys2denoise.metrics.chest_belt import respiratory_variance_time + # peakdet is an example package that provides peak/trough detection for the respiratory signal + from peakdet import operations + + # Load the physiological data + sample_rate = 1000 + physio = io.load_physio('path/to/physiological/data', fs=sample_rate) + + # Peak/trough detection for the respiratory signal, using the peakdet package + physio = operations.peakfind_physio(physio) + + # Compute RVT + physio, rvt = respiratory_variance_time(physio) + +:py:func:`respiratory_variance_time` returns a tuple with the updated Physio object and the computed respiratory variance time. + +:py:mod:`peakdet` is used in this example as it is also compatible with the Physio object. However, any other peak/trough detection +package can be used. In this case, the peak and trough values should be stored in the Physio object manually as follows: + +.. code-block:: python + + # Store the peak and trough values in the Physio object + physio._metadata["peaks"] = peaks + physio._metadata["troughs"] = troughs + +The benefit of using a Physio object other than the encapsulation of all the desired parameters in a single object is the fact that +the object retains a history of all the operations performed on it. This allows for easy debugging and reproducibility of the results. +For further information refer to the :py:mod:`physutils` documentation. + +Without using a Physio object +############################# + +However, if the use of the ``Physio`` object from the :py:mod:`physutils` module is not preferred, the metrics can be also computed without it. The following +example shows how to compute the heart rate and the heart rate variability using the :py:mod:`phys2denoise` package. + +.. code-block:: python + + from phys2denoise.metrics.chest_belt import respiratory_variance_time + + # Given that the respiratory signal is stored in `data`, the peaks in `peaks`, the troughs in `troughs` + # and the sample rate in `sample_rate` + _, rvt = respiratory_variance_time(data, peaks, troughs, sample_rate)