From 89883a1a111f9f8acbb52fc42be503b8d02e441f Mon Sep 17 00:00:00 2001 From: Patryk Mikulski Date: Fri, 5 Apr 2024 15:12:08 +0200 Subject: [PATCH] chore: refactoring --- .pre-commit-config.yaml | 48 +++++++ docs/Makefile | 20 --- docs/make.bat | 36 ----- docs/source/about.rst | 23 ---- docs/source/conf.py | 181 ------------------------- docs/source/devdoc.rst | 13 -- docs/source/documentation.rst | 2 - docs/source/examples.rst | 38 ------ docs/source/examples_text.rst | 23 ---- docs/source/handle_multi.rst | 7 - docs/source/index.rst | 25 ---- docs/source/install.rst | 49 ------- docs/source/modules.rst | 7 - docs/source/phase_transfer_entropy.rst | 7 - docs/source/pyPTE.examples.models.rst | 38 ------ docs/source/pyPTE.examples.rst | 22 --- docs/source/pyPTE.rst | 30 ---- docs/source/pyPTE.utils.rst | 30 ---- docs/source/usage.rst | 39 ------ docs/source/utils.rst | 38 ------ mypy.ini | 2 - pyPTE/__init__.py | 21 --- pyPTE/adapters/mne_adapter.py | 9 +- pyPTE/adapters/pandas_adapter.py | 3 +- pyPTE/core/__init__.py | 0 pyPTE/core/handle_multi.py | 9 +- pyPTE/core/pyPTE.py | 44 +++--- pyproject.toml | 50 ++++--- {pyPTE/core => tests}/test_pyPTE.py | 12 +- 29 files changed, 115 insertions(+), 711 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 docs/Makefile delete mode 100644 docs/make.bat delete mode 100644 docs/source/about.rst delete mode 100644 docs/source/conf.py delete mode 100644 docs/source/devdoc.rst delete mode 100644 docs/source/documentation.rst delete mode 100644 docs/source/examples.rst delete mode 100644 docs/source/examples_text.rst delete mode 100644 docs/source/handle_multi.rst delete mode 100644 docs/source/index.rst delete mode 100644 docs/source/install.rst delete mode 100644 docs/source/modules.rst delete mode 100644 docs/source/phase_transfer_entropy.rst delete mode 100644 docs/source/pyPTE.examples.models.rst delete mode 100644 docs/source/pyPTE.examples.rst delete mode 100644 docs/source/pyPTE.rst delete mode 100644 docs/source/pyPTE.utils.rst delete mode 100644 docs/source/usage.rst delete mode 100644 docs/source/utils.rst delete mode 100644 mypy.ini delete mode 100644 pyPTE/__init__.py create mode 100644 pyPTE/core/__init__.py rename {pyPTE/core => tests}/test_pyPTE.py (89%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..96efe0b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,48 @@ +ci: + skip: [pytest] + +default_language_version: + python: python3.12 + +repos: + # general checks (see here: https://pre-commit.com/hooks.html) + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + args: [--allow-multiple-documents] + - id: end-of-file-fixer + - id: trailing-whitespace + + # black - formatting + - repo: https://github.com/psf/black + rev: 24.2.0 + hooks: + - id: black + name: black + args: + - "--config" + - "./pyproject.toml" + + # ruff - linting + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.3.0" + hooks: + - id: ruff + name: ruff + + # mypy - lint-like type checking + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + name: mypy + + - repo: local + hooks: + - id: pytest + name: pytest + entry: poetry run pytest --cov=src tests + language: system + types: [python] + pass_filenames: false \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index a4c27c0..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = pyPTE -SOURCEDIR = source -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/make.bat b/docs/make.bat deleted file mode 100644 index 882d24d..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build -set SPHINXPROJ=pyPTE - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/source/about.rst b/docs/source/about.rst deleted file mode 100644 index a42bfcf..0000000 --- a/docs/source/about.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. =========== -.. About pyPTE -.. =========== - -pyPTE is an open-source implementation of the Phase Transfer Entropy method based on the publications [Lobier2014]_ and [Hillebrand2016]_. It is fully implemented in Python and requires only the Python libraries NumPy and SciPy. - -This implementation estimates the Phase Transfer Entropy which is defined for two given time-series X and Y with a known analysis lag delta as: - -.. math:: - {PTE}_{X \rightarrow Y} &=& H(\theta_Y(t), \theta_Y(t-\delta) \\ - &+& H(\theta_Y(t-\delta),\theta_X(t-\delta)) \\ - &-& H(\theta_Y(t-\delta)) \\ - &-& H(\theta_Y(t), \theta_Y(t-\delta), \theta_X(t-\delta)) -, where the entropy terms H are defined as: - -.. math:: - H(\theta_Y(t), \theta_Y(t)) = - \sum p(\theta_Y(t),\theta_Y(t-\delta)) log p(\theta_Y(t), \theta_Y(t-\delta)) \\ - H(\theta_Y(t-\delta), \theta_X(t-\delta)) = -\sum p(\theta_Y(t),\theta_X(t-\delta)) log p(\theta_Y(t), \theta_X(t-\delta)) \\ - H(\theta_Y(t-\delta)) = -\sum p(\theta_Y(t)) log p(\theta_Y(t)) \\ - H(\theta_Y(t-\delta), \theta_Y(t-\delta), \theta_X(t-\delta)) = - \sum p(\theta_Y(t),\theta_Y(t-\delta), \theta_X(t-\delta)) log p(\theta_Y(t), \theta_Y(t-\delta), \theta_X(t-\delta)) \\ -.. [Lobier2014] Muriel Lobier, Felix Siebenhühner, Satu Palva and J. Matias Palva. Phase transfer entropy: A novel phase-based measure for directed connectivity in networks coupled by oscillatory interactions. *NeuroImage*, 2014. `doi:10.1016/j.neuroimage.2013.08.056 `_ - -.. [Hillebrand2016] Arjan Hillebrand, Preejaas Tewarie, Edwin van Dellen, Meichen Yu, Ellen W. S. Carbo, Linda Douw, Alida A. Gouw, Elisabeth C.W. van Straaten and Cornelies J. Stam. Direction of information flow in large-scale resting-state networks is frequency-dependent. *Proceedings of the National Academy of Sciences of the United States of America*, 113(14):3867-72, 2016. `doi:10.1073/pnas.1515657113 `_ diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index c82efe5..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- 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 -sys.path.insert(0, os.path.abspath('../../pyPTE/')) -import sphinx_readable_theme - -html_theme_path = [sphinx_readable_theme.get_html_theme_path()] -html_theme = 'readable' - -# -- Project information ----------------------------------------------------- - -project = 'pyPTE' -copyright = '2018, Patryk Mikulski' -author = 'Patryk Mikulski' - -# The short X.Y version -version = '' -# The full version, including alpha/beta/rc tags -release = '0.1dev' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'numpydoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', - 'sphinx.ext.mathjax' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -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 = [] - -# 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. -# -# html_theme = 'alabaster' - -# 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'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'pyPTEdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'pyPTE.tex', 'pyPTE Documentation', - 'Patryk Mikulski', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pypte', 'pyPTE Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'pyPTE', 'pyPTE Documentation', - author, 'pyPTE', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for intersphinx extension --------------------------------------- - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} - -# -- Options for todo extension ---------------------------------------------- - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True diff --git a/docs/source/devdoc.rst b/docs/source/devdoc.rst deleted file mode 100644 index e97461a..0000000 --- a/docs/source/devdoc.rst +++ /dev/null @@ -1,13 +0,0 @@ -========================= -Developer's documentation -========================= - -To-do -===== -Different approaches to estimate the predicition delay used for the Phase Transfer Entropy method shall be implemented and evaluated. -Especially, a more sophisticated estimation as suggested by [Wibral2013]_ is desirable. - -.. [Wibral2013] Wibral, Michael and Pampu, Nicolae and Priesemann, Viola and Siebenhühner, Felix and Seiwert, Hannes and Lindner, Michael and Lizier, Joseph T and Vicente, Raul. Measuring Information-Transfer Delays. *PLOS ONE 8(2): e55809*, 2013. `doi:10.1371/journal.pone.0055809 `_ - - - diff --git a/docs/source/documentation.rst b/docs/source/documentation.rst deleted file mode 100644 index 9d89971..0000000 --- a/docs/source/documentation.rst +++ /dev/null @@ -1,2 +0,0 @@ -Documentation -============= diff --git a/docs/source/examples.rst b/docs/source/examples.rst deleted file mode 100644 index 1d23eed..0000000 --- a/docs/source/examples.rst +++ /dev/null @@ -1,38 +0,0 @@ -examples package -================ - -Submodules ----------- - -examples\.kuramoto\_global module ---------------------------------- - -.. automodule:: examples.kuramoto_global - :members: - :undoc-members: - :show-inheritance: - -examples\.kuramoto\_local module --------------------------------- - -.. automodule:: examples.kuramoto_local - :members: - :undoc-members: - :show-inheritance: - -examples\.neural\_mass\_model module ------------------------------------- - -.. automodule:: examples.neural_mass_model - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: examples - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/examples_text.rst b/docs/source/examples_text.rst deleted file mode 100644 index da60f48..0000000 --- a/docs/source/examples_text.rst +++ /dev/null @@ -1,23 +0,0 @@ -======== -Examples -======== - -Currently the pyPTE package delivers three examples which shall demonstrate the usage of the phase transfer entropy method. - -Standard Kuramoto model -======================= - -The standard Kuramoto model is a globally coupled system of linear differential equations of first order. It represents the phase behaviour of a set of coupled oscillators with respect to their intrinsinc frequencies and a global coupling strength. - -Neural mass model -================= -This example incorporates an implementation of the stochastic non-linear dynamics of coupled cortical columns based on [Jansen1995]_ and [Wendling2000]_ - -.. [Jansen1995] Ben H. Jansen and Vincent G. Rit. Electroencephalogram and visual evoked potential generation in a mathematical model of coupled cortical columns. *Biological Cybernetics*, 73:357-366, 1995 `doi:10.1007/BF00199471 `_ - -.. [Wendling2000] Wendling, F. and Bellanger, J. J. and Bartolomei, F. and Chauvel, P. Relevance of nonlinear lumped-parameter models in the analysis of depth-EEG epileptic signals. *Biological Cybernetics*. 2000 `doi:10.1007/s004220000160 `_ - -mne-python sample data set -========================== - -This example illustrates how to extract data from a mne raw object, which can be fed into pyPTE. If you want to incorporate data from other software packages than MNE, please refer to the MNE documentation how to import raw data from other fileformats. diff --git a/docs/source/handle_multi.rst b/docs/source/handle_multi.rst deleted file mode 100644 index a4d0b24..0000000 --- a/docs/source/handle_multi.rst +++ /dev/null @@ -1,7 +0,0 @@ -handle\_multi module -==================== - -.. automodule:: handle_multi - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index e305ce1..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. pyPTE documentation master file, created by - sphinx-quickstart on Mon May 14 18:03:03 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -pyPTE documentation! -================================= -.. include:: about.rst - -.. toctree:: - :maxdepth: 2 - - - install - usage - examples_text - devdoc - about - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/install.rst b/docs/source/install.rst deleted file mode 100644 index f8538fe..0000000 --- a/docs/source/install.rst +++ /dev/null @@ -1,49 +0,0 @@ -================== -Installation Guide -================== - -The prerequisites for this package are: - -Mandantory: - -- a working Python installation, version 3.6 or higher -- git -- NumPy -- SciPy - -Optional: - -- mne-python -- pandas -- seaborn - -Recommended: - -To prevent Python module incompatibilities using a virtual environment like - -- conda -- pyenv - -is highly recommendable. If you are planning to use mne-python, an Anaconda3 installation is mandandory. - -Step 1: Download pyPTE via GitHub -================================= - -Clone into the public GitHub repository using: -:: - > git clone https://github.com/patrk/pyPTE.git - -Step 2: Build pyPTE -=================== -Build the pyPTE package and make it available to your Python interpreter by: -:: - > cd pyPTE - > python setup.py install - -Step 3: Test pyPTE -================== -To test the installation of pyPTE simply run: -:: - > cd test - > py.test - diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100644 index 9c35cf9..0000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -pyPTE -===== - -.. toctree:: - :maxdepth: 4 - - pyPTE diff --git a/docs/source/phase_transfer_entropy.rst b/docs/source/phase_transfer_entropy.rst deleted file mode 100644 index ad4dfd1..0000000 --- a/docs/source/phase_transfer_entropy.rst +++ /dev/null @@ -1,7 +0,0 @@ -phase\_transfer\_entropy module -=============================== - -.. automodule:: phase_transfer_entropy - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/pyPTE.examples.models.rst b/docs/source/pyPTE.examples.models.rst deleted file mode 100644 index cd1e171..0000000 --- a/docs/source/pyPTE.examples.models.rst +++ /dev/null @@ -1,38 +0,0 @@ -pyPTE\.examples\.models package -=============================== - -Submodules ----------- - -pyPTE\.examples\.models\.kuramoto\_global module ------------------------------------------------- - -.. automodule:: pyPTE.examples.models.kuramoto_global - :members: - :undoc-members: - :show-inheritance: - -pyPTE\.examples\.models\.kuramoto\_local module ------------------------------------------------ - -.. automodule:: pyPTE.examples.models.kuramoto_local - :members: - :undoc-members: - :show-inheritance: - -pyPTE\.examples\.models\.neural\_mass\_model module ---------------------------------------------------- - -.. automodule:: pyPTE.examples.models.neural_mass_model - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: pyPTE.examples.models - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/pyPTE.examples.rst b/docs/source/pyPTE.examples.rst deleted file mode 100644 index c2f8bb0..0000000 --- a/docs/source/pyPTE.examples.rst +++ /dev/null @@ -1,22 +0,0 @@ -pyPTE\.examples package -======================= - -Submodules ----------- - -pyPTE\.examples\.mne\_demo module ---------------------------------- - -.. automodule:: pyPTE.examples.mne_demo - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: pyPTE.examples - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/pyPTE.rst b/docs/source/pyPTE.rst deleted file mode 100644 index 8bf44ee..0000000 --- a/docs/source/pyPTE.rst +++ /dev/null @@ -1,30 +0,0 @@ -pyPTE package -============= - -Submodules ----------- - -pyPTE\.handle\_multi module ---------------------------- - -.. automodule:: pyPTE.handle_multi - :members: - :undoc-members: - :show-inheritance: - -pyPTE\.pyPTE module -------------------- - -.. automodule:: pyPTE.pyPTE - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: pyPTE - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/pyPTE.utils.rst b/docs/source/pyPTE.utils.rst deleted file mode 100644 index 0d7d788..0000000 --- a/docs/source/pyPTE.utils.rst +++ /dev/null @@ -1,30 +0,0 @@ -pyPTE\.utils package -==================== - -Submodules ----------- - -pyPTE\.utils\.mne\_tools module -------------------------------- - -.. automodule:: pyPTE.utils.mne_tools - :members: - :undoc-members: - :show-inheritance: - -pyPTE\.utils\.stats module --------------------------- - -.. automodule:: pyPTE.utils.stats - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: pyPTE.utils - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/usage.rst b/docs/source/usage.rst deleted file mode 100644 index e05b0b3..0000000 --- a/docs/source/usage.rst +++ /dev/null @@ -1,39 +0,0 @@ -===== -Usage -===== - -The main functionality of this package, calculating the Phase Transfer Entropy (PTE) for a set of time-series is accessible via the following functions: - -If you are using MNE_ for analyzing EEG or MEG recordings an mne.io.Raw_ object can be passed to: - -.. _MNE: https://www.martinos.org/mne/stable/index.html -.. _mne.io.Raw: https://martinos.org/mne/dev/generated/mne.io.Raw.html - -.. code-block:: python - - from pyPTE.utils.mne_tools import PTE_from_mne - - dPTE, rPTE = PTE_from_mne(raw) - -which returns a tuple of the normalized dPTE, containing information about the directionality and the raw PTE matrix, whereas the matrices are pandas DataFrames indexed by the channel names from the mne.io.Raw_ object. - -In other domains the PTE calculation can be called directly by either passing a pandas.DataFrame_ to: - -.. _pandas.DataFrame: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html - -.. code-block:: python - - from pyPTE import pyPTE - dPTE, rPTE = pyPTE.PTE_from_dataframe(dataframe) - -or by passing a (m x n) numpy.ndarray_, where m is the number of samples and n is the number of time-series: - -.. _numpy.ndarray: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html -.. code-block:: python - - from pyPTE import pyPTE - dPTE, rPTE = pyPTE.PTE(timeseries) - -where the returned tuple consists of the above mentioned dPTE, rPTE matrices as (n x n) numpy.ndarray objects ordered in the same way as the input object. - -If you are interested in further aspects of the implementation see Developer's documentation. diff --git a/docs/source/utils.rst b/docs/source/utils.rst deleted file mode 100644 index f0be025..0000000 --- a/docs/source/utils.rst +++ /dev/null @@ -1,38 +0,0 @@ -utils package -============= - -Submodules ----------- - -utils\.dict\_helpers module ---------------------------- - -.. automodule:: utils.dict_helpers - :members: - :undoc-members: - :show-inheritance: - -utils\.network\_helpers module ------------------------------- - -.. automodule:: utils.network_helpers - :members: - :undoc-members: - :show-inheritance: - -utils\.visualize module ------------------------ - -.. automodule:: utils.visualize - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: utils - :members: - :undoc-members: - :show-inheritance: diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index ac733bc..0000000 --- a/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy-scipy.*] -ignore_missing_imports = True \ No newline at end of file diff --git a/pyPTE/__init__.py b/pyPTE/__init__.py deleted file mode 100644 index bbde829..0000000 --- a/pyPTE/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from .core.pyPTE import ( - get_delay, - get_phase, - get_discretized_phase, - get_binsize, - get_bincount, - compute_PTE, - compute_dPTE_rawPTE, - PTE, -) - -__all__ = [ - "get_delay", - "get_phase", - "get_discretized_phase", - "get_binsize", - "get_bincount", - "compute_PTE", - "compute_dPTE_rawPTE", - "PTE", -] diff --git a/pyPTE/adapters/mne_adapter.py b/pyPTE/adapters/mne_adapter.py index 2d33508..4236051 100644 --- a/pyPTE/adapters/mne_adapter.py +++ b/pyPTE/adapters/mne_adapter.py @@ -1,5 +1,6 @@ from pyPTE.core import pyPTE + def interpolate_mne(raw, raw_reference): """ This is a utility function which circumvents the issue that MNE allows to interpolate only channels, @@ -30,15 +31,16 @@ def interpolate_mne(raw, raw_reference): d = raw.copy() if len(diff) > 0: - b.pick_channels(b.ch_names[:len(diff)]) + b.pick_channels(b.ch_names[: len(diff)]) ac = raw.copy().pick_channels(diff) b.info = ac.info d.add_channels([b]) - d.info['bads'] = diff + d.info["bads"] = diff d.interpolate_bads(verbose=False) return d + def PTE_from_mne(mne_raw): """ This is a wrapper which allows calculating dPTE,PTE matrices by passing an mne.io.Raw object @@ -57,6 +59,5 @@ def PTE_from_mne(mne_raw): """ - data_frame = mne_raw.to_data_frame() - return pyPTE.PTE_from_dataframe(data_frame) \ No newline at end of file + return pyPTE.PTE_from_dataframe(data_frame) diff --git a/pyPTE/adapters/pandas_adapter.py b/pyPTE/adapters/pandas_adapter.py index 888d514..4e0bf3d 100644 --- a/pyPTE/adapters/pandas_adapter.py +++ b/pyPTE/adapters/pandas_adapter.py @@ -2,6 +2,7 @@ from pyPTE.core import pyPTE + def PTE_from_dataframe(data_frame): """ This is a wrapper which allows calculating dPTE,PTE matrices by passing an pandas.DataFrame @@ -23,4 +24,4 @@ def PTE_from_dataframe(data_frame): dPTE, rPTE = pyPTE.PTE(time_series) dPTE_df = pd.DataFrame(dPTE, index=data_frame.columns, columns=data_frame.columns) rPTE_df = pd.DataFrame(rPTE, index=data_frame.columns, columns=data_frame.columns) - return dPTE_df, rPTE_df \ No newline at end of file + return dPTE_df, rPTE_df diff --git a/pyPTE/core/__init__.py b/pyPTE/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyPTE/core/handle_multi.py b/pyPTE/core/handle_multi.py index 2929d75..4229fae 100644 --- a/pyPTE/core/handle_multi.py +++ b/pyPTE/core/handle_multi.py @@ -1,6 +1,7 @@ from multiprocessing import Pool, cpu_count from pyPTE.core import pyPTE + def _PTE_process(item): """ Multi processing pool worker for PTE computation - wraps PTE method @@ -20,7 +21,7 @@ def _PTE_process(item): key, value = item print(key) # dPTE, rawPTE = phase_transfer_entropy(value, method='myPTE') - raw_PTE = pyPTE.PTE(value, method='myPTE') + raw_PTE = pyPTE.PTE(value, method="myPTE") result = dict() # result[key] = dPTE, rawPTE result[key] = raw_PTE @@ -44,7 +45,9 @@ def multi_process(measurements): results = [] print(cpu_count()) pool = Pool(processes=cpu_count()) - r = pool.map_async(_PTE_process, list(measurements.items()), callback=results.append) + r = pool.map_async( + _PTE_process, list(measurements.items()), callback=results.append + ) r.wait() pool.close() - return results \ No newline at end of file + return results diff --git a/pyPTE/core/pyPTE.py b/pyPTE/core/pyPTE.py index 84f8e6b..9f46388 100644 --- a/pyPTE/core/pyPTE.py +++ b/pyPTE/core/pyPTE.py @@ -21,11 +21,11 @@ def get_delay(phase: npt.NDArray) -> int: """ phase = phase m, n = phase.shape - c1 = n*(m-2) + c1 = n * (m - 2) r_phase = np.roll(phase, 2, axis=0) phase_product = np.multiply(phase, r_phase)[1:-1] c2 = (phase_product < 0).sum() - delay = int(np.round(c1/c2)) + delay = int(np.round(c1 / c2)) return delay @@ -49,6 +49,7 @@ def get_phase(time_series: npt.ArrayLike) -> npt.NDArray: phase = np.angle(complex_series) return phase + def get_discretized_phase(phase: npt.NDArray, binsize: float) -> npt.NDArray: """ Discretizes the phase series to rectangular bins @@ -70,7 +71,7 @@ def get_discretized_phase(phase: npt.NDArray, binsize: float) -> npt.NDArray: return d_phase -def get_binsize(phase: npt.NDArray, c: float=3.49) -> float: +def get_binsize(phase: npt.NDArray, c: float = 3.49) -> float: """ Computes the bin size for the phase binning @@ -90,6 +91,7 @@ def get_binsize(phase: npt.NDArray, c: float=3.49) -> float: binsize = c * np.mean(np.std(phase, axis=0, ddof=1)) * n ** (-1.0 / 3) return binsize + def get_bincount(binsize: float) -> int: """ Get bin count for the interval [0, 2*pi] for given binsize @@ -128,7 +130,7 @@ def compute_PTE(phase: npt.NDArray, delay: int) -> npt.NDArray: m x m matrix containing the PTE value for each channel pair """ m, n = phase.shape - PTE = np.zeros((m,m), dtype=float) + PTE = np.zeros((m, m), dtype=float) for i in range(0, m): for j in range(0, m): @@ -137,7 +139,7 @@ def compute_PTE(phase: npt.NDArray, delay: int) -> npt.NDArray: y = phase[:-delay, j] x = phase[:-delay, i] - P_y = np.zeros([y.max() +1]) + P_y = np.zeros([y.max() + 1]) np.add.at(P_y, [y], 1) max_dim_ypr_y = max(ypr.max(), y.max()) + 1 @@ -149,19 +151,24 @@ def compute_PTE(phase: npt.NDArray, delay: int) -> npt.NDArray: max_dim_ypr_y_x = max(ypr.max(), y.max(), x.max()) + 1 P_ypr_y_x = np.zeros([max_dim_ypr_y_x, max_dim_ypr_y_x, max_dim_ypr_y_x]) - P_y /= (m-delay) - P_ypr_y /= (m-delay) - P_y_x /= (m-delay) - P_ypr_y_x /= (m-delay) + P_y /= m - delay + P_ypr_y /= m - delay + P_y_x /= m - delay + P_ypr_y_x /= m - delay - Hy = -np.nansum(np.multiply(P_y,np.log2(P_y))) - Hypr_y = - np.nansum(np.nansum(np.multiply(P_ypr_y, np.log2(P_ypr_y)))) + Hy = -np.nansum(np.multiply(P_y, np.log2(P_y))) + Hypr_y = -np.nansum(np.nansum(np.multiply(P_ypr_y, np.log2(P_ypr_y)))) Hy_x = -np.nansum(np.nansum(np.multiply(P_y_x, np.log2(P_y_x)))) - Hypr_y_x = -np.nansum(np.nansum(np.nansum(np.multiply(P_ypr_y_x, np.log2(P_ypr_y_x))))) + Hypr_y_x = -np.nansum( + np.nansum(np.nansum(np.multiply(P_ypr_y_x, np.log2(P_ypr_y_x)))) + ) PTE[i, j] = Hypr_y + Hy_x - Hy - Hypr_y_x return PTE -def compute_dPTE_rawPTE(phase: npt.NDArray, delay: int) -> Tuple[npt.NDArray, npt.NDArray]: + +def compute_dPTE_rawPTE( + phase: npt.NDArray, delay: int +) -> Tuple[npt.NDArray, npt.NDArray]: """ This function calls pyPTE.pyPTE.compute_PTE to obtain a PTE matrix and performs a normalization yielding dPTE to easily investigate directionality information. @@ -187,10 +194,11 @@ def compute_dPTE_rawPTE(phase: npt.NDArray, delay: int) -> Tuple[npt.NDArray, np raw_PTE = compute_PTE(phase, delay) tmp = np.triu(raw_PTE) + np.tril(raw_PTE).T - with np.errstate(divide='ignore',invalid='ignore'): - dPTE = np.triu(raw_PTE/tmp,1) + np.tril(raw_PTE/tmp.T,-1) + with np.errstate(divide="ignore", invalid="ignore"): + dPTE = np.triu(raw_PTE / tmp, 1) + np.tril(raw_PTE / tmp.T, -1) return dPTE, raw_PTE + def PTE(time_series: npt.ArrayLike) -> Tuple[npt.NDArray, npt.NDArray]: """ This function performs the whole procedure of calculating the PTE: @@ -220,9 +228,3 @@ def PTE(time_series: npt.ArrayLike) -> Tuple[npt.NDArray, npt.NDArray]: d_phase = get_discretized_phase(phase_inc, binsize) return compute_dPTE_rawPTE(d_phase, delay) - - - - - - diff --git a/pyproject.toml b/pyproject.toml index ab759ea..efa26fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,9 @@ -[build-system] -requires = ["setuptools>=42", "wheel"] -build-backend = "setuptools.build_meta" - -[project] +[tool.poetry] name = "pyPTE" version = "0.1.0" description = "Pythonic implementation of the Phase Transfer Entropy using NumPy and SciPy" -authors = [ - { name = "Patryk Mikulski"}, -] -license = { file = "LICENSE" } +authors = ["Patryk Mikulski"] +license = "GPL-3.0-or-later" readme = "README.md" keywords = ["PTE", "phase transfer entropy", "neuroscience", "signal processing"] classifiers = [ @@ -23,17 +17,31 @@ classifiers = [ "Topic :: Scientific/Engineering", ] -dependencies = [ - "numpy==1.26.4", - "pandas==2.2.1", - "scipy==1.13.0", - "mne==1.6.1", -] +[tool.poetry.dependencies] +python = "^3.12.2" +numpy = "1.26.4" +pandas = "2.2.1" +scipy = "1.13.0" +mne = "1.6.1" +[tool.poetry.dev-dependencies] +pytest = "^8.1.1" +black = "^24.3.0" +mypy = "^1.9.0" +ruff = "^0.3.0" -[project.optional-dependencies] -dev = [ - "pytest>=6.0", - "black", - # any other development dependencies like linters, doc generators -] +[tool.pytest.ini_options] +pythonpath = ["."] + +[tool.ruff] + line-length = 88 + # pyflakes, pycodestyle, isort + select = ["F", "E", "W", "I001"] + +[tool.black] +line-length = 88 +target-version = ['py312'] + +[build-system] +requires = ["poetry-core>=1.9"] +build-backend = "poetry.core.masonry.api" diff --git a/pyPTE/core/test_pyPTE.py b/tests/test_pyPTE.py similarity index 89% rename from pyPTE/core/test_pyPTE.py rename to tests/test_pyPTE.py index ac23141..9eacaf4 100644 --- a/pyPTE/core/test_pyPTE.py +++ b/tests/test_pyPTE.py @@ -1,14 +1,12 @@ import numpy as np -from pyPTE import get_phase +from pyPTE.core.pyPTE import get_phase, get_binsize, get_discretized_phase +from pyPTE.core.pyPTE import compute_PTE, PTE def test_get_phase_zeros_input(): time_series = np.array([[0, 0, 0], [0, 0, 0]]) expected_phase_result = np.array([[0, 0, 0], [0, 0, 0]]) np.testing.assert_almost_equal(get_phase(time_series), expected_phase_result, decimal=5) - -from pyPTE import get_discretized_phase - def test_get_discretized_phase(): phase_data = np.array([np.pi/4, np.pi/2, 3*np.pi/4]) binsize = np.pi/4 @@ -16,18 +14,12 @@ def test_get_discretized_phase(): discretized_phase = get_discretized_phase(phase_data, binsize) np.testing.assert_array_equal(discretized_phase, expected_discretized_phase, "Discretized phase did not match expected values.") - -from pyPTE import compute_PTE, get_binsize - def test_PTE_integration(): time_series = np.random.rand(5, 100) dPTE, raw_PTE = PTE(time_series) assert dPTE.shape == (5, 5), f"Expected dPTE shape (5, 5), got {dPTE.shape}" assert raw_PTE.shape == (5, 5), f"Expected raw_PTE shape (5, 5), got {raw_PTE.shape}" - -from pyPTE import PTE # Adjust the import path as necessary - def test_PTE_with_independent_signals(): signal_length = 1000 s1 = np.random.normal(0, 1, signal_length)