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

Fix: Update CuBIDS to allow both longitudinal and cross-sectional structure by adding is_longitudinal attribute to CUBIDS class #406

Merged
merged 14 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
18 changes: 12 additions & 6 deletions cubids/cubids.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class CuBIDS(object):
use_datalad : :obj:`bool`
If True, use datalad to track changes to the BIDS dataset.
is_longitudinal : :obj:`bool`
If True, includes "ses" in filepath. Default is False.
If True, adds "ses" in filepath.
tsalo marked this conversation as resolved.
Show resolved Hide resolved
"""

def __init__(
Expand All @@ -95,7 +95,6 @@ def __init__(
acq_group_level="subject",
grouping_config=None,
force_unlock=False,
is_longitudinal=False,
):
self.path = os.path.abspath(data_root)
self._layout = None
Expand All @@ -113,12 +112,15 @@ def __init__(
self.cubids_code_dir = Path(self.path + "/code/CuBIDS").is_dir()
self.data_dict = {} # data dictionary for TSV outputs
self.use_datalad = use_datalad # True if flag set, False if flag unset
self.is_longitudinal = is_longitudinal # True if flag set, False if flag unset
self.is_longitudinal = self._infer_longitudinal() # inferred from dataset structure

if self.use_datalad:
self.init_datalad()

if self.is_longitudinal and self.acq_group_level == "session":
NON_KEY_ENTITIES.remove("session")
elif not self.is_longitudinal and self.acq_group_level == "session":
raise ValueError('Data is not longitudinal, so "session" is not a valid grouping level.')

@property
def layout(self):
Expand All @@ -132,6 +134,10 @@ def layout(self):
# print("LAYOUT OBJECT SET")
return self._layout

def _infer_longitudinal(self):
"""Infer if the dataset is longitudinal based on its structure."""
return any("ses-" in str(f) for f in Path(self.path).rglob("*"))

def reset_bids_layout(self, validate=False):
"""Reset the BIDS layout.

Expand Down Expand Up @@ -1766,7 +1772,7 @@ def get_entity_value(path, key):
return part


def build_path(filepath, entities, out_dir, is_longitudinal=False):
def build_path(filepath, entities, out_dir, is_longitudinal):
"""Build a new path for a file based on its BIDS entities.

Parameters
Expand All @@ -1778,8 +1784,8 @@ def build_path(filepath, entities, out_dir, is_longitudinal=False):
This should include all of the entities in the filename *except* for subject and session.
out_dir : str
The output directory for the new file.
is_longitudinal : bool, optional
If True, add "ses" to file path. Default is False.
is_longitudinal : bool
If True, add "ses" to file path.

Returns
-------
Expand Down
4 changes: 2 additions & 2 deletions cubids/tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ def test_cubids_apply_intendedfor(
BIDS skeleton structure.
intended_for : str
IntendedFor field value.
is_longitudinal : bool
Indicate whether the data structure is longitudinal or cross-sectional.
expected : str or Exception
Expected result or exception.

Expand Down Expand Up @@ -339,7 +341,6 @@ def test_cubids_apply_intendedfor(
files_tsv=files_tsv,
new_tsv_prefix=None,
container=None,
is_longitudinal=is_longitudinal,
)

with open(fmap_json) as f:
Expand All @@ -357,5 +358,4 @@ def test_cubids_apply_intendedfor(
files_tsv=files_tsv,
new_tsv_prefix=None,
container=None,
is_longitudinal=is_longitudinal,
)
3 changes: 1 addition & 2 deletions cubids/tests/test_bond.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ def test_tsv_merge_changes(tmp_path):
The temporary path where the test data will be copied.
"""
data_root = get_data(tmp_path)
bod = CuBIDS(data_root / "inconsistent", use_datalad=True, is_longitudinal=True)
bod = CuBIDS(data_root / "inconsistent", use_datalad=True)
bod.datalad_save()
assert bod.is_datalad_clean()

Expand Down Expand Up @@ -950,7 +950,6 @@ def test_session_apply(tmp_path):
data_root / "inconsistent",
acq_group_level="session",
use_datalad=True,
is_longitudinal=True,
)

ses_cubids.get_tsvs(str(tmp_path / "originals"))
Expand Down
4 changes: 0 additions & 4 deletions cubids/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ def apply(
files_tsv,
new_tsv_prefix,
container,
is_longitudinal=False,
):
"""Apply the tsv changes.

Expand All @@ -454,8 +453,6 @@ def apply(
Path to the new tsv prefix.
container : :obj:`str`
Container in which to run the workflow.
is_longitudinal : :obj:`bool`
If True, includes "ses" in filepath. Default is False.
"""
# Run directly from python using
if container is None:
Expand All @@ -464,7 +461,6 @@ def apply(
use_datalad=use_datalad,
acq_group_level=acq_group_level,
grouping_config=config,
is_longitudinal=is_longitudinal,
)
if use_datalad:
if not bod.is_datalad_clean():
Expand Down
Loading