-
Notifications
You must be signed in to change notification settings - Fork 4
Add BIDS reading support and prepare input loading for pydra workflow #7
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
Changes from 12 commits
557513e
52cc61e
9c224f0
05d90ea
cb67b7c
e10c9b2
717ff0e
db56954
6c9a6d2
67ee789
3a08510
1cd7539
a19bc19
34fc89d
94b711c
1a72423
f2a2d92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d | |
| <td align="center"><a href="http://rossmarkello.com"><img src="https://avatars0.githubusercontent.com/u/14265705?v=4" width="100px;" alt=""/><br /><sub><b>Ross Markello</b></sub></a><br /><a href="https://github.com/physiopy/phys2bids/commits?author=rmarkello" title="Code">💻</a> <a href="#ideas-rmarkello" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-rmarkello" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/physiopy/phys2bids/pulls?q=is%3Apr+reviewed-by%3Armarkello" title="Reviewed Pull Requests">👀</a></td> | ||
| <td align="center"><a href="https://github.com/smoia"><img src="https://avatars3.githubusercontent.com/u/35300580?v=4" width="100px;" alt=""/><br /><sub><b>Stefano Moia</b></sub></a><br /><a href="https://github.com/physiopy/phys2bids/commits?author=smoia" title="Code">💻</a> <a href="#data-smoia" title="Data">🔣</a> <a href="#ideas-smoia" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-smoia" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#projectManagement-smoia" title="Project Management">📆</a></td> | ||
| <td align="center"><a href="https://github.com/eurunuela"><img src="https://avatars0.githubusercontent.com/u/13706448?v=4" width="100px;" alt=""/><br /><sub><b>Eneko Uruñuela</b></sub></a><br /><a href="https://github.com/physiopy/phys2bids/commits?author=eurunuela" title="Code">💻</a> <a href="https://github.com/physiopy/phys2bids/pulls?q=is%3Apr+reviewed-by%3Aeurunuela" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/physiopy/phys2bids/commits?author=eurunuela" title="Tests">⚠️</a></td> | ||
| <td align="center"><a href="https://github.com/maestroque"><img src="https://avatars.githubusercontent.com/u/74024609?v=4?s=100" width="100px;" alt="George Kikas"/><br /><sub><b>George Kikas</b></sub></a><br /><a href="https://github.com/physiopy/phys2denoise/commits?author=maestroque" title="Code">💻</a> <a href="#ideas-maestroque" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-maestroque" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/physiopy/phys2denoise/issues?q=author%3Amaestroque" title="Bug reports">🐛</a> <a href="https://github.com/physiopy/phys2denoise/commits?author=maestroque" title="Tests">⚠️</a> <a href="https://github.com/physiopy/phys2denoise/pulls?q=is%3Apr+reviewed-by%3Amaestroque" title="Reviewed Pull Requests">👀</a></td> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't worry about this, I'll regenerate the table later |
||
| </tr> | ||
| </table> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,85 @@ | ||||||
| import logging | ||||||
| from functools import wraps | ||||||
|
|
||||||
| from bids import BIDSLayout | ||||||
| from loguru import logger | ||||||
|
|
||||||
| from physutils.io import load_from_bids, load_physio | ||||||
| from physutils.physio import Physio | ||||||
|
|
||||||
| LGR = logging.getLogger(__name__) | ||||||
| LGR.setLevel(logging.DEBUG) | ||||||
|
|
||||||
| try: | ||||||
| import pydra | ||||||
|
|
||||||
| pydra_imported = True | ||||||
| except ImportError: | ||||||
| pydra_imported = False | ||||||
|
|
||||||
|
|
||||||
| def mark_task(pydra_imported=pydra_imported): | ||||||
| def decorator(func): | ||||||
| if pydra_imported: | ||||||
| # If the decorator exists, apply it | ||||||
| @wraps(func) | ||||||
| def wrapped_func(*args, **kwargs): | ||||||
| logger.debug(f"Creating pydra task for {func.__name__}") | ||||||
| return pydra.mark.task(func)(*args, **kwargs) | ||||||
|
|
||||||
| return wrapped_func | ||||||
| # Otherwise, return the original function | ||||||
| return func | ||||||
|
|
||||||
| return decorator | ||||||
|
||||||
|
|
||||||
|
|
||||||
| def is_bids_directory(directory): | ||||||
| try: | ||||||
| # Attempt to create a BIDSLayout object | ||||||
| _ = BIDSLayout(directory) | ||||||
| return True | ||||||
| except Exception as e: | ||||||
| # Catch other exceptions that might indicate the directory isn't BIDS compliant | ||||||
| logger.error( | ||||||
| f"An error occurred while trying to load {directory} as a BIDS Layout object: {e}" | ||||||
| ) | ||||||
| return False | ||||||
|
|
||||||
|
|
||||||
| @mark_task(pydra_imported=pydra_imported) | ||||||
| def transform_to_physio( | ||||||
| input_file: str, mode="physio", fs=None, bids_parameters=dict(), bids_channel=None | ||||||
|
||||||
| ) -> Physio: | ||||||
| if not pydra_imported: | ||||||
| LGR.warning( | ||||||
|
||||||
| LGR.warning( | |
| LGR.debug( |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused about these two lines, was there something you were trying to check?
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "SamplingFrequency": 10000.0, | ||
| "StartTime": -3, | ||
| "Columns": [ | ||
| "time", | ||
| "respiratory_chest", | ||
| "trigger", | ||
| "cardiac", | ||
| "respiratory_CO2", | ||
| "respiratory_O2" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "SamplingFrequency": 10000.0, | ||
| "StartTime": -3, | ||
| "Columns": [ | ||
| "time", | ||
| "respiratory_chest", | ||
| "trigger", | ||
| "cardiac", | ||
| "respiratory_CO2", | ||
| "respiratory_O2" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| """Tests for physutils.tasks and their integration.""" | ||
|
|
||
| import os | ||
|
|
||
| import physutils.tasks as tasks | ||
| from physutils import physio | ||
| from physutils.tests.utils import create_random_bids_structure | ||
|
|
||
|
|
||
| def test_transform_to_physio_phys_file(): | ||
| """Test transform_to_physio task.""" | ||
| physio_file = os.path.abspath("physutils/tests/data/ECG.phys") | ||
| task = tasks.transform_to_physio(input_file=physio_file, mode="physio") | ||
| assert task.inputs.input_file == physio_file | ||
| assert task.inputs.mode == "physio" | ||
| assert task.inputs.fs is None | ||
|
Comment on lines
+14
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pytest is failing..
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| task() | ||
me-pic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| physio_obj = task.result().output.out | ||
| assert isinstance(physio_obj, physio.Physio) | ||
| assert physio_obj.fs == 1000 | ||
| assert physio_obj.data.shape == (44611,) | ||
|
|
||
|
|
||
| def test_transform_to_physio_bids_file(): | ||
| """Test transform_to_physio task.""" | ||
| create_random_bids_structure("physutils/tests/data", recording_id="cardiac") | ||
| bids_parameters = { | ||
| "subject": "01", | ||
| "session": "01", | ||
| "task": "rest", | ||
| "run": "01", | ||
| "recording": "cardiac", | ||
| } | ||
| bids_dir = os.path.abspath("physutils/tests/data/bids-dir") | ||
| task = tasks.transform_to_physio( | ||
| input_file=bids_dir, | ||
| mode="bids", | ||
| bids_parameters=bids_parameters, | ||
| bids_channel="cardiac", | ||
|
||
| ) | ||
|
|
||
| assert task.inputs.input_file == bids_dir | ||
| assert task.inputs.mode == "bids" | ||
| assert task.inputs.fs is None | ||
| assert task.inputs.bids_parameters == bids_parameters | ||
| assert task.inputs.bids_channel == "cardiac" | ||
|
|
||
| task() | ||
|
|
||
| physio_obj = task.result().output.out | ||
| assert isinstance(physio_obj, physio.Physio) | ||
|
|
||
|
|
||
| def test_transform_to_physio_auto(): | ||
| create_random_bids_structure("physutils/tests/data", recording_id="cardiac") | ||
| bids_parameters = { | ||
| "subject": "01", | ||
| "session": "01", | ||
| "task": "rest", | ||
| "run": "01", | ||
| "recording": "cardiac", | ||
| } | ||
| bids_dir = os.path.abspath("physutils/tests/data/bids-dir") | ||
| task = tasks.transform_to_physio( | ||
| input_file=bids_dir, | ||
| mode="auto", | ||
| bids_parameters=bids_parameters, | ||
| bids_channel="cardiac", | ||
me-pic marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| assert task.inputs.input_file == bids_dir | ||
| assert task.inputs.mode == "auto" | ||
| assert task.inputs.fs is None | ||
| assert task.inputs.bids_parameters == bids_parameters | ||
| assert task.inputs.bids_channel == "cardiac" | ||
|
|
||
| task() | ||
|
|
||
| physio_obj = task.result().output.out | ||
| assert isinstance(physio_obj, physio.Physio) | ||
|
|
||
|
|
||
| def test_transform_to_physio_auto_error(caplog): | ||
| bids_dir = os.path.abspath("physutils/tests/data/non-bids-dir") | ||
| task = tasks.transform_to_physio( | ||
| input_file=bids_dir, | ||
| mode="auto", | ||
| bids_channel="cardiac", | ||
| ) | ||
|
|
||
| assert task.inputs.input_file == bids_dir | ||
| assert task.inputs.mode == "auto" | ||
| assert task.inputs.fs is None | ||
| assert task.inputs.bids_channel == "cardiac" | ||
|
|
||
| try: | ||
| task() | ||
| except Exception: | ||
| assert caplog.text.count("ERROR") == 1 | ||
| assert ( | ||
| caplog.text.count( | ||
| "dataset_description.json' is missing from project root. Every valid BIDS dataset must have this file." | ||
| ) | ||
| == 1 | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ classifiers = | |
| License :: OSI Approved :: Apache Software License | ||
| Programming Language :: Python :: 3 | ||
| license = Apache-2.0 | ||
| description = Set of utilities meant to be used with Physiopy's libraries | ||
| description = Set of utilities meant to be used with Physiopy libraries | ||
| long_description = file:README.md | ||
| long_description_content_type = text/markdown; charset=UTF-8 | ||
| platforms = OS Independent | ||
|
|
@@ -23,8 +23,8 @@ python_requires = >=3.6.1 | |
| install_requires = | ||
| matplotlib | ||
| numpy >=1.9.3 | ||
| scipy | ||
| loguru | ||
| pydra | ||
|
||
| pybids | ||
|
||
| tests_require = | ||
| pytest >=3.6 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maestroque please put yourself before Vicente (in alphabetical order of family name). You have all of the above, minus review, but plus documentation.
@me-pic and @m-miedema please add yourselves as well, mentoring and review.