Skip to content

Commit

Permalink
[ENH] support querying for scans.tsv and sessions.tsv (#550)
Browse files Browse the repository at this point in the history
* add querying for scans

* add querying for sessions

* count sessions and scans as suffixes

* fix tests
  • Loading branch information
Remi-Gau authored Apr 28, 2023
1 parent 554f792 commit f423ea6
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 10 deletions.
7 changes: 7 additions & 0 deletions +bids/copy_to_derivative.m
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ function copy_session_scan_tsv(BIDS, derivatives_folder, args)

function copy_file(BIDS, derivatives_folder, data_file, unzip_files, force, skip_dep, verbose)

bf = bids.File(data_file);
is_scans_or_sessions_tsv = ismember(bf.suffix, {'scans', 'sessions'});
if is_scans_or_sessions_tsv
% copy_session_scan_tsv handles it
return
end

info = bids.internal.return_file_info(BIDS, data_file);

if ~isfield(info, 'sub_idx') || ~isfield(info, 'modality') || ...
Expand Down
15 changes: 15 additions & 0 deletions +bids/layout.m
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,10 @@

for iFile = 1:size(file_list, 1)

if is_scans_or_sessions_tsv(file_list{iFile})
continue
end

info_src = bids.internal.return_file_info(BIDS, file_list{iFile});
% skip files in the root folder with no sub entity
if isempty(info_src.sub_idx) || isempty(info_src.file_idx)
Expand Down Expand Up @@ -764,6 +768,17 @@

end

function status = is_scans_or_sessions_tsv(file)

bf = bids.File(file);

status = false;
if ismember(bf.suffix, {'scans', 'sessions'})
status = true;
end

end

function perf = manage_M0(perf, pth, verbose)

tolerant = true;
Expand Down
45 changes: 45 additions & 0 deletions +bids/query.m
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ case cat(2, {'suffixes', 'suffixes', 'extensions', 'prefixes'}, valid_entity_qu

end

result = update_result_scans_sessions_tsv(query, result, this_subject, options);

end

result = update_result_with_root_content(query, options, result, BIDS);
Expand Down Expand Up @@ -485,6 +487,49 @@ case valid_entity_queries()
end
end

function result = update_result_scans_sessions_tsv(query, result, this_subject, options)
%
% add scans.tsv and sessions.tsv to results list:
% - if user asked for data
% - filter by entities
%

if strcmp(query, 'data')

bf = bids.File(this_subject.scans);
status = bids.internal.keep_file_for_query(bf, options);
if status
result{end + 1} = this_subject.scans;
end

bf = bids.File(this_subject.sess);
status = bids.internal.keep_file_for_query(bf, options);
if status
result{end + 1} = this_subject.sess;
result = unique(result);
end

end

if strcmp(query, 'suffixes')
if ~isempty(this_subject.scans)
bf = bids.File(this_subject.scans);
status = bids.internal.keep_file_for_query(bf, options);
if status
result{end + 1} = 'scans';
end
end
if ~isempty(this_subject.sess)
bf = bids.File(this_subject.sess);
status = bids.internal.keep_file_for_query(bf, options);
if status
result{end + 1} = 'sessions';
end
end
end

end

function result = update_result_with_root_content(query, options, result, BIDS)

d = BIDS.root;
Expand Down
83 changes: 77 additions & 6 deletions tests/tests_query/test_bids_query.m
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ function test_query_exclude_entity()
assertEqual(bids.query(BIDS, 'modalities', filter), {'meg'});

filter = struct('sub', '0001', 'acq', '');
assertEqual(bids.query(BIDS, 'suffixes', filter), {'T1w', 'channels', 'headshape', 'meg'});
assertEqual(bids.query(BIDS, 'suffixes', filter), ...
{'T1w', 'channels', 'headshape', 'meg', 'scans'});

end

Expand Down Expand Up @@ -276,19 +277,89 @@ function test_query_sessions_tsv()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, '7t_trt'));
BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));

suffixes = bids.query(BIDS, 'suffixes');
assert(ismember('sessions', suffixes));

sessions_tsv = bids.query(BIDS, 'data', 'suffix', 'sessions');
assertEqual(numel(sessions_tsv), 5);

sessions_tsv = bids.query(BIDS, 'data', 'suffix', 'sessions', ...
'sub', '01');
assertEqual(numel(sessions_tsv), 1);

assert(~isempty(BIDS.subjects(1).sess));
assert(~isempty(BIDS.subjects(1).scans));
sessions_tsv = bids.query(BIDS, 'data', 'suffix', 'sessions', ...
'sub', '01', ...
'ses', 'joy');
assertEqual(numel(sessions_tsv), 0);

sessions_tsv = bids.query(BIDS, 'data', 'suffix', 'sessions', ...
'sub', '0[1-3]');
assertEqual(numel(sessions_tsv), 3);

data = bids.query(BIDS, 'data', 'sub', '01');
assertEqual(numel(data), 23);
assert(ismember('sub-01_sessions.tsv', ...
bids.internal.file_utils(data, 'filename')));

data = bids.query(BIDS, 'data', 'sub', '01', ...
'suffix', 'events');
assertEqual(numel(data), 1);
assert(~ismember('sub-01_sessions.tsv', ...
bids.internal.file_utils(data, 'filename')));

data = bids.query(BIDS, 'data', 'sub', '01', ...
'task', 'nback');
assertEqual(numel(data), 13);
assert(~ismember('sub-01_sessions.tsv', ...
bids.internal.file_utils(data, 'filename')));

end

function test_query_scans_tsv()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ds009'));
BIDS = bids.layout(fullfile(pth_bids_example, 'motion_spotrotation'));

suffixes = bids.query(BIDS, 'suffixes');
assert(ismember('scans', suffixes));

scans_tsv = bids.query(BIDS, 'data', 'suffix', 'scans');
assertEqual(numel(scans_tsv), 10);

scans_tsv = bids.query(BIDS, 'data', 'suffix', 'scans', ...
'sub', '01');
assertEqual(numel(scans_tsv), 2);

assert(~isempty(BIDS.subjects(1).scans));
scans_tsv = bids.query(BIDS, 'data', 'suffix', 'scans', ...
'sub', '01', ...
'ses', 'joy');
assertEqual(numel(scans_tsv), 1);

scans_tsv = bids.query(BIDS, 'data', 'suffix', 'scans', ...
'sub', '0[1-3]', ...
'ses', '.*o.*');
assertEqual(numel(scans_tsv), 6);

data = bids.query(BIDS, 'data', 'sub', '01', ...
'ses', 'joy');
assertEqual(numel(data), 9);
assert(ismember('sub-01_ses-joy_scans.tsv', ...
bids.internal.file_utils(data, 'filename')));

data = bids.query(BIDS, 'data', 'sub', '01', ...
'ses', 'joy', ...
'suffix', 'events');
assertEqual(numel(data), 1);
assert(~ismember('sub-01_ses-joy_scans.tsv', ...
bids.internal.file_utils(data, 'filename')));

data = bids.query(BIDS, 'data', 'sub', '01', ...
'ses', 'joy', ...
'task', 'Rotation');
assertEqual(numel(data), 7);
assert(~ismember('sub-01_ses-joy_scans.tsv', ...
bids.internal.file_utils(data, 'filename')));
end
4 changes: 2 additions & 2 deletions tests/tests_query/test_bids_query_ieeg.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function test_bids_query_ieeg_basic()
modalities = {'anat', 'ieeg'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);

suffixes = {'T1w', 'channels', 'electrodes', 'events', 'ieeg'};
suffixes = {'T1w', 'channels', 'electrodes', 'events', 'ieeg', 'scans'};
% Missing: 'coordsystem'
assertEqual(bids.query(BIDS, 'suffixes'), suffixes);

Expand All @@ -29,7 +29,7 @@ function test_bids_query_ieeg_basic()
modalities = {'anat', 'ieeg'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);

suffixes = {'T1w', 'channels', 'electrodes', 'events', 'ieeg', 'photo'};
suffixes = {'T1w', 'channels', 'electrodes', 'events', 'ieeg', 'photo', 'scans'};
% Missing: 'coordsystem'
assertEqual(bids.query(BIDS, 'suffixes'), suffixes);

Expand Down
2 changes: 1 addition & 1 deletion tests/tests_query/test_bids_query_meg.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function test_bids_query_meg_basic()
modalities = {'anat', 'meg'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);

suffixes = {'T1w', 'channels', 'headshape', 'meg', 'photo'};
suffixes = {'T1w', 'channels', 'headshape', 'meg', 'photo', 'scans'};
% missing: 'coordsystem'
assertEqual(bids.query(BIDS, 'suffixes'), suffixes);

Expand Down
2 changes: 1 addition & 1 deletion tests/tests_query/test_bids_query_microscopy.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function test_bids_query_microscopy_basic()
BIDS = bids.layout(fullfile(pth_bids_example, 'micr_SEM'));

data = bids.query(BIDS, 'data');
assertEqual(numel(data), 5);
assertEqual(numel(data), 6);

BIDS = bids.layout(fullfile(pth_bids_example, 'micr_SPIM'));

Expand Down

0 comments on commit f423ea6

Please sign in to comment.