Skip to content

Commit

Permalink
Merge pull request #333 from Remi-Gau/meta_methods
Browse files Browse the repository at this point in the history
[ENH] add methods to load metadata through the bids.File class
  • Loading branch information
Remi-Gau authored Mar 5, 2022
2 parents 2ff80c5 + cf6f77f commit c0d274c
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 10 deletions.
3 changes: 3 additions & 0 deletions +bids/+internal/get_meta_list.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

% For all those files we find which one is potentially associated with
% the file of interest
% TODO: not more than one file per level is allowed
for i = 1:numel(metafile)

p2 = bids.internal.parse_filename(metafile{i});
Expand All @@ -76,6 +77,8 @@
% as its data file counterpart
ismeta = true;
if ~strcmp(p.suffix, p2.suffix)
% TODO is this necessary as we have already
% only listed files with the same suffix
ismeta = false;
end
for j = 1:numel(entities)
Expand Down
5 changes: 5 additions & 0 deletions +bids/+internal/parse_filename.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
tolerant = true;
end

if isempty(filename)
p = struct([]);
return
end

fields_order = {'filename', 'ext', 'suffix', 'entities', 'prefix'};

filename = bids.internal.file_utils(filename, 'filename');
Expand Down
29 changes: 26 additions & 3 deletions +bids/File.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,24 @@

json_filename = '' % bidsified name for json file

metadata_files = {} % list of metadata files related

metadata

entity_required = {} % Required entities

entity_order = {} % Expected order of entities

schema = [] % BIDS schema used

tolerant = true

verbose = false

end

properties (SetAccess = private)
changed = false
tolerant = true
verbose = false

end

methods
Expand Down Expand Up @@ -151,6 +156,8 @@
obj = obj.use_schema();
end

obj = obj.set_metadata();

obj = obj.update();
end

Expand Down Expand Up @@ -242,6 +249,14 @@
obj.changed = true;
end

function obj = set_metadata(obj)
if isempty(obj.metadata_files)
pattern = '^.*%s\\.json$';
obj.metadata_files = bids.internal.get_meta_list(obj.path, pattern);
end
obj.metadata = bids.internal.get_metadata(obj.metadata_files);
end

function obj = set_entity(obj, label, value)
obj.validate_word(label, 'Entity label');
obj.validate_word(value, 'Entity value');
Expand All @@ -250,6 +265,13 @@
obj.changed = true;
end

function obj = set_metadata_files(obj, pattern)
if nargin < 2
pattern = '^.*%s\\.json$';
end
obj.metadata_files = bids.internal.get_meta_list(obj.path, pattern);
end

%% other methods
function obj = update(obj)
%
Expand Down Expand Up @@ -405,6 +427,7 @@
end

if ~args.Results.dry_run
% TODO update obj.path
output_file = fullfile(fileparts(obj.path), obj.filename);
if ~exist(output_file, 'file') || args.Results.force
movefile(obj.path, output_file);
Expand Down
4 changes: 4 additions & 0 deletions +bids/Model.m
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
%
if isempty(varargin)
value = obj.Nodes;
idx = 1:numel(value);

else

Expand Down Expand Up @@ -257,6 +258,9 @@
end

function obj = get_edges_from_nodes(obj)
if numel(obj.Nodes) <= 1
return
end
for i = 1:(numel(obj.Nodes) - 1)
obj.Edges{i, 1} = struct('Source', obj.Nodes{i, 1}.Name, ...
'Destination', obj.Nodes{i + 1, 1}.Name);
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cff-version: 1.2.0

title: bids-matlab

version: 0.1.0
version: 0.1.0dev

license: GPL-3.0

Expand Down
Binary file added docs/bids-matlab.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'BIDS-MATLAB developers'

# The full version, including alpha/beta/rc tags
release = 'v0.1.0'
release = 'v0.1.0dev'


# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion miss_hit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ tab_width: 2

# metrics limit for the code quality (https://florianschanda.github.io/miss_hit/metrics.html)
metric "cnest": limit 5
metric "file_length": limit 710
metric "file_length": limit 800
metric "cyc": limit 17
metric "parameters": limit 8
47 changes: 44 additions & 3 deletions tests/test_bids_file.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,43 @@
%
% end

function test_get_metadata_suffixes_basic()
% ensures that "similar" suffixes are distinguished

data_dir = fullfile(fileparts(mfilename('fullpath')), 'data', 'surface_data');

file = fullfile(data_dir, 'sub-06_hemi-R_space-individual_den-native_thickness.shape.gii');
side_car = fullfile(data_dir, 'sub-06_hemi-R_space-individual_den-native_thickness.json');

bf = bids.File(file);

% TODO only only json file per folder level allowed
% assertEqual(numel(bf.metadata_files), 1)

expected_metadata = bids.util.jsondecode(side_car);

assertEqual(bf.metadata, expected_metadata);

file = fullfile(data_dir, 'sub-06_hemi-R_space-individual_den-native_midthickness.surf.gii');
side_car = fullfile(data_dir, 'sub-06_hemi-R_space-individual_den-native_midthickness.json');

bf = bids.File(file);

expected_metadata = bids.util.jsondecode(side_car);

assertEqual(bf.metadata, expected_metadata);

file = fullfile(data_dir, 'sub-06_space-individual_den-native_thickness.dscalar.nii');
side_car = fullfile(data_dir, 'sub-06_space-individual_den-native_thickness.json');

bf = bids.File(file);

expected_metadata = bids.util.jsondecode(side_car);

assertEqual(bf.metadata, expected_metadata);

end

function test_rename()

input_filename = 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii';
Expand All @@ -25,7 +62,7 @@ function test_rename()
set_up(input_file);
teardown(output_file);

file = bids.File(input_file, 'use_schema', false, 'verbose', true);
file = bids.File(input_file, 'use_schema', false, 'verbose', false);

assertEqual(file.path, input_file);

Expand Down Expand Up @@ -78,13 +115,17 @@ function test_rename_force()

system(sprintf('touch %s', input_file));
system(sprintf('touch %s', output_file));
file = bids.File(input_file, 'use_schema', false, 'verbose', true);
file = bids.File(input_file, 'use_schema', false, 'verbose', false);

assertEqual(file.path, input_file);

file.prefix = '';
file.entities.desc = 'preproc';
assertWarning(@() file.rename('dry_run', false), 'File:fileAlreadyExists');
file.verbose = true;
if bids.internal.is_github_ci && ~bids.internal.is_octave
% failure: warning 'Octave:mixed-string-concat' was raised, expected 'File:fileAlreadyExists'.
assertWarning(@() file.rename('dry_run', false), 'File:fileAlreadyExists');
end

file = file.rename('dry_run', false, 'verbose', false);
assertEqual(exist(input_file, 'file'), 2);
Expand Down
38 changes: 38 additions & 0 deletions tests/tests_private/test_get_metadata.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ function test_get_metadata_basic()

end

function test_get_metadata_basic_File()

% Same as above but uses the bids.File class

pth = fullfile(fileparts(mfilename('fullpath')), '..', 'data', 'synthetic');

func_sub_01.RepetitionTime = 10;
anat_sub_01.FlipAngle = 10;
anat_sub_01.Manufacturer = 'Siemens';

% try to get metadata
BIDS = bids.layout(pth);

data = bids.query(BIDS, 'data', 'sub', '01', 'suffix', 'bold');
bf = bids.File(data{1});
assert(bf.metadata.RepetitionTime == func_sub_01.RepetitionTime);

%% test anat metadata subject 01
metadata = bids.query(BIDS, 'data', 'sub', '01', 'suffix', 'T1w');
bf = bids.File(data{1});
assertEqual(bf.metadata.Manufacturer, anat_sub_01.Manufacturer);

end

function test_get_metadata_internal()

pth_bids_example = get_test_data_dir();
Expand All @@ -69,3 +93,17 @@ function test_get_metadata_participants()
assertEqual(metadata, expected_metadata);

end

function test_get_metadata_participants_File()

pth_bids_example = get_test_data_dir();

file = fullfile(pth_bids_example, 'pet002', 'participants.tsv');
side_car = fullfile(pth_bids_example, 'pet002', 'participants.json');

bf = bids.File(file);

expected_metadata = bids.util.jsondecode(side_car);
assertEqual(bf.metadata, expected_metadata);

end
3 changes: 3 additions & 0 deletions tests/tests_private/test_get_metadata_suffixes.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ function test_get_metadata_suffixes_basic()
side_car = fullfile(data_dir, 'sub-06_hemi-R_space-individual_den-native_thickness.json');

metalist = bids.internal.get_meta_list(file);
% TODO only only json file per folder level allowed
% assertEqual(numel(metalist), 1)

metadata = bids.internal.get_metadata(metalist);

expected_metadata = bids.util.jsondecode(side_car);
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.1.0
v0.1.0dev

0 comments on commit c0d274c

Please sign in to comment.