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

Track Sources for outputs with BIDS URIs #966

Merged
merged 64 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
32f4ed1
Track sources for some outputs.
tsalo Oct 10, 2023
e64c4c1
Update bids.py
tsalo Oct 10, 2023
a64cddb
Fix maybe?
tsalo Oct 10, 2023
7edfd13
Well that's silly.
tsalo Oct 10, 2023
a54afa9
Try that.
tsalo Oct 10, 2023
e6395c3
Try patching connection.
tsalo Oct 10, 2023
b96b9c4
Whoops.
tsalo Oct 10, 2023
b391c0b
ugh
tsalo Oct 10, 2023
719f5ea
Update outputs.
tsalo Oct 10, 2023
b8df302
Update bids.py
tsalo Oct 10, 2023
e60a656
Update concatenation.py
tsalo Oct 10, 2023
9649f45
Merge branch 'main' into track-sources
tsalo Oct 10, 2023
7880f8a
Update concatenation.py
tsalo Oct 11, 2023
9d4287e
Update concatenation.py
tsalo Oct 11, 2023
6adc88d
Update expected outputs.
tsalo Oct 11, 2023
36128c2
Fix outputs.
tsalo Oct 11, 2023
dd4f805
More work.
tsalo Oct 11, 2023
7b4731f
Merge branch 'main' into track-sources
tsalo Oct 11, 2023
717564c
Whoops!
tsalo Oct 11, 2023
f6c367e
Connect the datasink.
tsalo Oct 11, 2023
caa9b15
Update outputs.
tsalo Oct 11, 2023
f948750
Make Sources an iterfield.
tsalo Oct 11, 2023
8f7d67f
Update outputs.py
tsalo Oct 11, 2023
9e923aa
Update.
tsalo Oct 11, 2023
41750ba
Add "Sources".
tsalo Oct 11, 2023
ad93edf
update
tsalo Oct 11, 2023
544a093
Give this a try.
tsalo Oct 13, 2023
6905ac9
Whoops
tsalo Oct 13, 2023
5e83d7d
Merge remote-tracking branch 'upstream/main' into track-sources
tsalo Oct 13, 2023
8642bfb
Try that!
tsalo Oct 13, 2023
dcaef91
Update expected outputs.
tsalo Oct 13, 2023
6712e0e
Fill in TODO list.
tsalo Oct 13, 2023
e80cce5
Reorder datasinks.
tsalo Oct 14, 2023
30463f5
Simplify outputs workflow.
tsalo Oct 14, 2023
ed154b6
Keep working.
tsalo Oct 14, 2023
66be748
Keep working.
tsalo Oct 14, 2023
305b990
Update outputs.py
tsalo Oct 14, 2023
23a5f09
Update things.
tsalo Oct 14, 2023
91c7df7
Update outputs.py
tsalo Oct 14, 2023
5c87661
Allow lists.
tsalo Oct 15, 2023
53f01cc
Copy the dictionary.
tsalo Oct 15, 2023
d5f1376
Transpose list of lists.
tsalo Oct 15, 2023
2d0d27f
Update concatenation.py
tsalo Oct 15, 2023
d3d5e09
update
tsalo Oct 15, 2023
8ee7fe6
Update outputs.py
tsalo Oct 15, 2023
223ef42
Update outputs.py
tsalo Oct 15, 2023
c560f30
Update things.
tsalo Oct 15, 2023
d815d7f
Update outputs.py
tsalo Oct 15, 2023
10379ff
Update outputs.py
tsalo Oct 15, 2023
4386480
Update expected outputs.
tsalo Oct 15, 2023
bdaf171
Add docstrings and tests.
tsalo Oct 16, 2023
aba3e1b
Update.
tsalo Oct 16, 2023
551bfc0
Try fixing tests.
tsalo Oct 16, 2023
2b169d6
Fix tests.
tsalo Oct 16, 2023
65a1da9
Maybe fix bug?
tsalo Oct 16, 2023
0aceec3
Add SamplingFrequency to time series files.
tsalo Oct 17, 2023
385f6f3
Try this.
tsalo Oct 17, 2023
dcc2ea8
Work around badness.
tsalo Oct 17, 2023
16a3c9f
Remove InferBIDSURIs.
tsalo Oct 17, 2023
922cfc7
Improve test coverage.
tsalo Oct 17, 2023
ae63e8e
Fix test maybe.
tsalo Oct 17, 2023
8a7e248
Fix test.
tsalo Oct 17, 2023
3567ff2
Merge remote-tracking branch 'upstream/main' into track-sources
tsalo Oct 20, 2023
8886cb8
Remove duplicate expected outputs.
tsalo Oct 20, 2023
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
40 changes: 12 additions & 28 deletions docs/outputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,21 +165,15 @@ Denoised or residual BOLD data
xcp_d/
sub-<label>/[ses-<label>/]
func/
# Nifti
# NIfTI
<source_entities>_space-<label>_desc-denoised_bold.nii.gz
<source_entities>_space-<label>_desc-denoised_bold.json
<source_entities>_space-<label>_desc-denoisedSmoothed_bold.nii.gz
<source_entities>_space-<label>_desc-denoisedSmoothed_bold.json
<source_entities>_space-<label>_desc-interpolated_bold.nii.gz
<source_entities>_space-<label>_desc-interpolated_bold.json

# Cifti
# CIFTI
<source_entities>_space-fsLR_den-91k_desc-denoised_bold.dtseries.nii
<source_entities>_space-fsLR_den-91k_desc-denoised_bold.json
<source_entities>_space-fsLR_den-91k_desc-denoisedSmoothed_bold.dtseries.nii
<source_entities>_space-fsLR_den-91k_desc-denoisedSmoothed_bold.json
<source_entities>_space-fsLR_den-91k_desc-interpolated_bold.dtseries.nii
<source_entities>_space-fsLR_den-91k_desc-interpolated_bold.json

.. important::

Expand Down Expand Up @@ -212,21 +206,21 @@ This includes the atlases used to extract the timeseries.
.. code-block::

xcp_d/
# Nifti
# NIfTI
space-<label>_atlas-<label>_dseg.nii.gz

# Cifti
# CIFTI
space-<label>_atlas-<label>_dseg.dlabel.nii

sub-<label>/[ses-<label>/]
func/
# Nifti
# NIfTI
<source_entities>_space-<label>_atlas-<label>_coverage.tsv
<source_entities>_space-<label>_atlas-<label>_timeseries.tsv
<source_entities>_space-<label>_atlas-<label>_measure-pearsoncorrelation_conmat.tsv
<source_entities>_space-<label>_atlas-<label>_measure-pearsoncorrelation_desc-<INT>volumes_conmat.tsv

# Cifti
# CIFTI
<source_entities>_space-fsLR_atlas-<label>_den-91k_coverage.tsv
<source_entities>_space-fsLR_atlas-<label>_den-91k_coverage.pscalar.nii
<source_entities>_space-fsLR_atlas-<label>_den-91k_timeseries.tsv
Expand Down Expand Up @@ -259,14 +253,14 @@ data.
xcp_d/
sub-<label>/[ses-<label>/]
func/
# Nifti
# NIfTI
<source_entities>_space-<label>_reho.nii.gz
<source_entities>_space-<label>_alff.nii.gz
<source_entities>_space-<label>_desc-smooth_alff.nii.gz
<source_entities>_space-<label>_atlas-<atlas>_alff.tsv
<source_entities>_space-<label>_atlas-<atlas>_reho.tsv

# Cifti
# CIFTI
<source_entities>_space-fsLR_den-91k_reho.dscalar.nii
<source_entities>_space-fsLR_den-91k_alff.dscalar.nii
<source_entities>_space-fsLR_den-91k_desc-smooth_alff.dscalar.nii
Expand All @@ -284,21 +278,15 @@ Other outputs include quality control, framewise displacement, and confounds fil

sub-<label>/[ses-<label>/]
func/
# Nifti
<source_entities>_space-<label>_desc-linc_qc.csv
<source_entities>[_desc-filtered]_motion.tsv
<source_entities>[_desc-filtered]_motion.json
<source_entities>_outliers.tsv
<source_entities>_outliers.json
<source_entities>_design.tsv

# Cifti
# NIfTI
<source_entities>_space-<label>_desc-linc_qc.csv

# CIFTI
<source_entities>_space-fsLR_desc-linc_qc.csv
<source_entities>[_desc-filtered]_motion.tsv
<source_entities>[_desc-filtered]_motion.json
<source_entities>_outliers.tsv
<source_entities>_outliers.json
<source_entities>_design.tsv

``[desc-filtered]_motion.tsv`` is a tab-delimited file with seven columns:
one for each of the six filtered motion parameters, as well as "framewise_displacement".
Expand Down Expand Up @@ -327,10 +315,6 @@ to 1mm FD in 0.01 steps.
xcp_d/
sub-<label>/[ses-<label>/]
func/
# Nifti
<source_entities>_desc-dcan_qc.hdf5

# Cifti
<source_entities>_desc-dcan_qc.hdf5

These files have the following keys:
Expand Down
273 changes: 252 additions & 21 deletions xcp_d/tests/data/test_ds001419_cifti_outputs.txt

Large diffs are not rendered by default.

234 changes: 209 additions & 25 deletions xcp_d/tests/data/test_ds001419_nifti_outputs.txt

Large diffs are not rendered by default.

138 changes: 125 additions & 13 deletions xcp_d/tests/data/test_fmriprep_without_freesurfer_outputs.txt

Large diffs are not rendered by default.

92 changes: 79 additions & 13 deletions xcp_d/tests/data/test_nibabies_outputs.txt

Large diffs are not rendered by default.

121 changes: 110 additions & 11 deletions xcp_d/tests/data/test_pnc_cifti_outputs.txt

Large diffs are not rendered by default.

119 changes: 109 additions & 10 deletions xcp_d/tests/data/test_pnc_cifti_t2wonly_outputs.txt

Large diffs are not rendered by default.

146 changes: 129 additions & 17 deletions xcp_d/tests/data/test_pnc_nifti_outputs.txt

Large diffs are not rendered by default.

89 changes: 84 additions & 5 deletions xcp_d/tests/test_utils_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,22 @@ def test_write_dataset_description(datasets, tmp_path_factory, caplog):

# It will work when we give it a real fmri_dir.
fmri_dir = datasets["ds001419"]
xbids.write_dataset_description(fmri_dir, tmpdir)
xbids.write_dataset_description(fmri_dir, tmpdir, custom_confounds_folder="/fake/path4")
assert os.path.isfile(dset_description)

# Now overwrite the description.
xbids.write_dataset_description(fmri_dir, tmpdir)
assert os.path.isfile(dset_description)

# Now change the version and re-run the function.
with open(dset_description, "r") as fo:
desc = json.load(fo)

assert "'preprocessed' is already a dataset link" not in caplog.text
assert "'xcp_d' is already a dataset link" not in caplog.text
assert "'custom_confounds' is already a dataset link" not in caplog.text
xbids.write_dataset_description(tmpdir, tmpdir, custom_confounds_folder="/fake/path4")
assert "'preprocessed' is already a dataset link" in caplog.text
assert "'xcp_d' is already a dataset link" in caplog.text
assert "'custom_confounds' is already a dataset link" in caplog.text

# Now change the version and re-run the function.
desc["GeneratedBy"][0]["Version"] = "0.0.1"
with open(dset_description, "w") as fo:
json.dump(desc, fo, indent=4)
Expand Down Expand Up @@ -294,3 +299,77 @@ def test_group_across_runs():
"/path/sub-01_task-rest_dir-LR_run-2_bold.nii.gz",
"/path/sub-01_task-rest_dir-RL_run-2_bold.nii.gz",
]


def test_make_uri():
"""Test _make_uri."""
in_file = "/path/to/dset/sub-01/func/sub-01_task-rest_bold.nii.gz"
dataset_name = "test"
dataset_path = "/path/to/dset"
uri = xbids._make_uri(in_file, dataset_name=dataset_name, dataset_path=dataset_path)
assert uri == "bids:test:sub-01/func/sub-01_task-rest_bold.nii.gz"

dataset_path = "/another/path/haha"
with pytest.raises(ValueError, match="does not start with"):
xbids._make_uri(in_file, dataset_name=dataset_name, dataset_path=dataset_path)


def test_make_xcpd_uri():
"""Test _make_xcpd_uri."""
out_file = "/path/to/dset/xcp_d/sub-01/func/sub-01_task-rest_bold.nii.gz"
uri = xbids._make_xcpd_uri(out_file, output_dir="/path/to/dset")
assert uri == ["bids:xcp_d:sub-01/func/sub-01_task-rest_bold.nii.gz"]

xbids._make_xcpd_uri([out_file], output_dir="/path/to/dset")
assert uri == ["bids:xcp_d:sub-01/func/sub-01_task-rest_bold.nii.gz"]


def test_make_xcpd_uri_lol():
"""Test _make_xcpd_uri_lol."""
in_list = [
[
"/path/to/dset/xcp_d/sub-01/func/sub-01_task-rest_run-1_bold.nii.gz",
"/path/to/dset/xcp_d/sub-02/func/sub-01_task-rest_run-1_bold.nii.gz",
"/path/to/dset/xcp_d/sub-03/func/sub-01_task-rest_run-1_bold.nii.gz",
],
[
"/path/to/dset/xcp_d/sub-01/func/sub-01_task-rest_run-2_bold.nii.gz",
"/path/to/dset/xcp_d/sub-02/func/sub-01_task-rest_run-2_bold.nii.gz",
"/path/to/dset/xcp_d/sub-03/func/sub-01_task-rest_run-2_bold.nii.gz",
],
]
uris = xbids._make_xcpd_uri_lol(in_list, output_dir="/path/to/dset/")
assert uris == [
[
"bids:xcp_d:sub-01/func/sub-01_task-rest_run-1_bold.nii.gz",
"bids:xcp_d:sub-01/func/sub-01_task-rest_run-2_bold.nii.gz",
],
[
"bids:xcp_d:sub-02/func/sub-01_task-rest_run-1_bold.nii.gz",
"bids:xcp_d:sub-02/func/sub-01_task-rest_run-2_bold.nii.gz",
],
[
"bids:xcp_d:sub-03/func/sub-01_task-rest_run-1_bold.nii.gz",
"bids:xcp_d:sub-03/func/sub-01_task-rest_run-2_bold.nii.gz",
],
]


def test_make_preproc_uri():
"""Test _make_preproc_uri."""
out_file = "/path/to/dset/sub-01/func/sub-01_task-rest_bold.nii.gz"
uri = xbids._make_preproc_uri(out_file, fmri_dir="/path/to/dset")
assert uri == ["bids:preprocessed:sub-01/func/sub-01_task-rest_bold.nii.gz"]

xbids._make_preproc_uri([out_file], fmri_dir="/path/to/dset")
assert uri == ["bids:preprocessed:sub-01/func/sub-01_task-rest_bold.nii.gz"]


def test_make_custom_uri():
"""Test _make_custom_uri."""
out_file = "/path/to/dset/sub-01_task-rest_bold.nii.gz"
uri = xbids._make_custom_uri(out_file)
assert uri == ["bids:custom_confounds:sub-01_task-rest_bold.nii.gz"]

xbids._make_custom_uri([out_file])
assert uri == ["bids:custom_confounds:sub-01_task-rest_bold.nii.gz"]
85 changes: 85 additions & 0 deletions xcp_d/tests/test_utils_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,88 @@ def test_select_first():

lst = "abc"
assert utils._select_first(lst) == "a"


def test_listify():
"""Test _listify."""
inputs = [
1,
(1,),
"a",
["a"],
["a", ["b", "c"]],
("a", "b"),
]
outputs = [
[1],
(1,),
["a"],
["a"],
["a", ["b", "c"]],
("a", "b"),
]
for i, input_ in enumerate(inputs):
expected_output = outputs[i]
output = utils._listify(input_)
assert output == expected_output


def test_make_dictionary():
"""Test _make_dictionary."""
metadata = {"Sources": ["a"]}
out_metadata = utils._make_dictionary(metadata, Sources=["b"])
# Ensure the original dictionary isn't modified.
assert metadata["Sources"] == ["a"]
assert out_metadata["Sources"] == ["a", "b"]

metadata = {"Test": "a"}
out_metadata = utils._make_dictionary(metadata, Sources=["b"])
assert out_metadata["Sources"] == ["b"]

metadata = {"Test": ["a"]}
out_metadata = utils._make_dictionary(metadata, Sources="b")
assert out_metadata["Sources"] == "b"

metadata = {"Sources": "a"}
out_metadata = utils._make_dictionary(metadata, Sources=["b"])
# Ensure the original dictionary isn't modified.
assert metadata["Sources"] == "a"
assert out_metadata["Sources"] == ["a", "b"]

metadata = {"Sources": ["a"]}
out_metadata = utils._make_dictionary(metadata, Sources="b")
# Ensure the original dictionary isn't modified.
assert metadata["Sources"] == ["a"]
assert out_metadata["Sources"] == ["a", "b"]

out_metadata = utils._make_dictionary(metadata=None, Sources=["b"])
assert out_metadata["Sources"] == ["b"]


def test_transpose_lol():
"""Test _transpose_lol."""
inputs = [
[
["a", "b", "c"],
[1, 2, 3],
],
[
["a", "b", "c", "d"],
[1, 2, 3],
],
]
outputs = [
[
["a", 1],
["b", 2],
["c", 3],
],
[
["a", 1],
["b", 2],
["c", 3],
],
]
for i, input_ in enumerate(inputs):
expected_output = outputs[i]
assert utils._transpose_lol(input_) == expected_output
2 changes: 1 addition & 1 deletion xcp_d/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def reorder_expected_outputs():
with open(expected_output_file, "r") as fo:
file_contents = fo.readlines()

file_contents = sorted(file_contents)
file_contents = sorted(list(set(file_contents)))

with open(expected_output_file, "w") as fo:
fo.writelines(file_contents)
Loading
Loading