Skip to content

Commit b01eb2e

Browse files
authored
Merge pull request #47 from Remi-Gau/remi-JSON_output
generate json output and a valid BIDS data set
2 parents 0f968f8 + b227d42 commit b01eb2e

36 files changed

+1124
-177
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010

1111
check_my_code_report.txt
1212
test_code_report.txt
13+
14+
output/**

.gitmodules

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[submodule "lib/bids-matlab"]
2+
path = lib/bids-matlab
3+
url = https://github.com/bids-standard/bids-matlab.git
4+
branch = master
5+
[submodule "lib/JSONio"]
6+
path = lib/JSONio
7+
url = https://github.com/gllmflndn/JSONio.git
8+
branch = master

.travis.yml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,32 @@ before_install:
1313
- travis_retry sudo apt-get -y -qq update
1414
- travis_retry sudo apt-get -y install octave
1515
- travis_retry sudo apt-get -y install liboctave-dev
16-
# - travis_retry sudo apt-get -y install nodejs
17-
# - travis_retry sudo apt-get -y install npm
16+
- travis_retry sudo apt-get -y install nodejs
17+
- travis_retry sudo apt-get -y install npm
1818
- cd .. && git clone https://github.com/florianschanda/miss_hit.git && export PATH=$PATH:`pwd`/miss_hit && cd CPP_BIDS
1919

2020

2121
install:
22-
# Install JSONio
23-
#- travis_retry git clone git://github.com/gllmflndn/JSONio.git --depth 1
24-
#- cd JSONio; mkoctfile --mex jsonread.c jsmn.c -DJSMN_PARENT_LINKS; cd ..
25-
#- octave $OCTFLAGS --eval "addpath (fullfile (pwd, 'JSONio')); savepath ();"
26-
# Install BIDS-MATLAB
22+
# make octave file for JSONio
23+
- cd lib/JSONio; mkoctfile --mex jsonread.c jsmn.c -DJSMN_PARENT_LINKS; cd ../..
2724
- octave $OCTFLAGS --eval "addpath (pwd); savepath ();"
2825
# Install BIDS-Validator
29-
#- sudo npm install -g bids-validator
26+
- sudo npm install -g bids-validator
3027

3128
before_script:
3229
# Change current directory
3330
- cd tests
3431

3532
jobs:
3633
include:
37-
- stage: "Tests and linter"
38-
name: "Unit Tests" # names the first job
34+
- stage: "Tests"
35+
name: "Unit and integration Tests"
3936
script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))"
40-
- script: cd .. && mh_style.py `pwd`
41-
name: "miss_hit linter" # names the second job
37+
- stage: "BIDS validator"
38+
name: "Create and check dataset"
39+
script: octave $OCTFLAGS --eval "testmanual_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders
40+
- stage: "Linter"
41+
name: "miss_hit"
42+
script: cd .. && mh_style `pwd`
43+
44+

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,17 @@ logFile.extraColumns = {'Speed', 'is_Fixation'};
127127
128128
[cfg, expParameters] = createFilename(cfg, expParameters);
129129
130-
% dummy call to initialize the logFile variable
131-
logFile = saveEventsFile('open', expParameters, logFile);
130+
% initialize the logFile variable
131+
[logFile] = saveEventsFile('init', expParameters, logFile);
132132
133133
% set the real length we really want
134134
logFile.extraColumns.Speed.length = 12;
135135
136-
% actual inititalization
136+
% open the file
137137
logFile = saveEventsFile('open', expParameters, logFile);
138138
```
139139

140+
140141
## Functions descriptions
141142

142143
### userInputs

checkCFG.m

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
function [cfg, expParameters] = checkCFG(cfg, expParameters)
22
% check that we have all the fields that we need in the experiment parameters
33

4+
checkCppBidsDependencies();
5+
6+
if nargin < 1 || isempty(cfg)
7+
cfg = struct();
8+
end
9+
if nargin < 2 || isempty(expParameters)
10+
expParameters = struct();
11+
end
12+
413
%% set the expParameters defaults
514

615
fieldsToSet.verbose = 0;
@@ -9,67 +18,92 @@
918
'..', ...
1019
'output');
1120

12-
fieldsToSet.subjectGrp = []; % in case no group was provided
21+
fieldsToSet = mriDefaults(fieldsToSet);
22+
23+
fieldsToSet.subjectGrp = ''; % in case no group was provided
1324
fieldsToSet.sessionNb = 1; % in case no session was provided
1425
fieldsToSet.askGrpSess = [true true];
1526

16-
% BIDS
27+
expParameters = setDefaultFields(expParameters, fieldsToSet);
1728

18-
% dataset description json
19-
% required
20-
fieldsToSet.bids.datasetDescription.json.Name = '';
21-
fieldsToSet.bids.datasetDescription.json.BIDSVersion = '';
22-
% recommended
23-
fieldsToSet.bids.datasetDescription.json.License = '';
24-
fieldsToSet.bids.datasetDescription.json.Authors = {''};
25-
fieldsToSet.bids.datasetDescription.json.Acknowledgements = '';
26-
fieldsToSet.bids.datasetDescription.json.HowToAcknowledge = '';
27-
fieldsToSet.bids.datasetDescription.json.Funding = {''};
28-
fieldsToSet.bids.datasetDescription.json.ReferencesAndLinks = {''};
29-
fieldsToSet.bids.datasetDescription.json.DatasetDOI = '';
30-
31-
% mri
32-
% for json
33-
fieldsToSet.MRI.repetitionTime = [];
34-
% for file naming
35-
fieldsToSet.MRI.ce = [];
36-
fieldsToSet.MRI.dir = []; % phase encoding direction of acquisition for fMRI
37-
fieldsToSet.MRI.rec = []; % reconstruction of fMRI images
38-
fieldsToSet.MRI.echo = []; % echo fMRI images
39-
fieldsToSet.MRI.acq = []; % acquisition of fMRI images
29+
%% BIDS
30+
clear fieldsToSet;
31+
fieldsToSet.bids = struct();
32+
expParameters = setDefaultFields(expParameters, fieldsToSet);
33+
34+
clear fieldsToSet;
35+
fieldsToSet.MRI = struct();
36+
fieldsToSet.datasetDescription = struct();
37+
expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet);
38+
39+
clear fieldsToSet;
40+
fieldsToSet = datasetDescriptionDefaults();
41+
42+
expParameters.bids.datasetDescription = ...
43+
setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet);
44+
45+
clear fieldsToSet;
46+
fieldsToSet = mriJsonDefaults();
47+
if isfield(expParameters, 'task')
48+
fieldsToSet.TaskName = expParameters.task;
49+
end
50+
51+
expParameters.bids.MRI = ...
52+
setDefaultFields(expParameters.bids.MRI, fieldsToSet);
4053

41-
expParameters = setDefaults(expParameters, fieldsToSet);
54+
% sort fields alphabetically
55+
expParameters = orderfields(expParameters);
4256

4357
%% set the cfg defaults
4458

4559
clear fieldsToSet;
4660
fieldsToSet.testingDevice = 'pc';
4761
fieldsToSet.eyeTracker = false;
4862

49-
cfg = setDefaults(cfg, fieldsToSet);
63+
cfg = setDefaultFields(cfg, fieldsToSet);
5064

51-
end
65+
% sort fields alphabetically
66+
cfg = orderfields(cfg);
5267

53-
function structure = setDefaults(structure, fieldsToSet)
54-
% loop through the defaults fiels to set and update if they don't exist
68+
end
5569

56-
names = fieldnames(fieldsToSet);
70+
function fieldsToSet = mriDefaults(fieldsToSet)
5771

58-
for i = 1:numel(names)
72+
% for file naming
73+
fieldsToSet.MRI.ce = [];
74+
fieldsToSet.MRI.dir = []; % phase encoding direction of acquisition for fMRI
75+
fieldsToSet.MRI.rec = []; % reconstruction of fMRI images
76+
fieldsToSet.MRI.echo = []; % echo fMRI images
77+
fieldsToSet.MRI.acq = []; % acquisition of fMRI images
5978

60-
thisField = fieldsToSet.(names{i});
79+
end
6180

62-
structure = setFieldToIfNotPresent( ...
63-
structure, ...
64-
names{i}, ...
65-
thisField);
81+
function fieldsToSet = datasetDescriptionDefaults()
82+
% required
83+
fieldsToSet.Name = '';
84+
fieldsToSet.BIDSVersion = '';
85+
% recommended
86+
fieldsToSet.License = '';
87+
fieldsToSet.Authors = {''};
88+
fieldsToSet.Acknowledgements = '';
89+
fieldsToSet.HowToAcknowledge = '';
90+
fieldsToSet.Funding = {''};
91+
fieldsToSet.ReferencesAndLinks = {''};
92+
fieldsToSet.DatasetDOI = '';
93+
end
6694

67-
end
95+
function fieldsToSet = mriJsonDefaults()
6896

69-
end
97+
% for json for funcfional data
98+
% required
99+
fieldsToSet.RepetitionTime = [];
100+
fieldsToSet.SliceTiming = [];
101+
fieldsToSet.TaskName = [];
102+
% fieldsToSet.PhaseEncodingDirection = [];
103+
% fieldsToSet.EffectiveEchoSpacing = [];
104+
% fieldsToSet.EchoTime = [];
105+
% recommended
106+
fieldsToSet.Instructions = [];
107+
fieldsToSet.TaskDescription = [];
70108

71-
function structure = setFieldToIfNotPresent(structure, fieldName, value)
72-
if ~isfield(structure, fieldName)
73-
structure.(fieldName) = value;
74-
end
75109
end

checkCppBidsDependencies.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function checkCppBidsDependencies
2+
3+
pth = fileparts(mfilename('fullpath'));
4+
addpath(fullfile(pth, 'lib', 'JSONio'));
5+
addpath(fullfile(pth, 'lib', 'bids-matlab'));
6+
addpath(fullfile(pth, 'lib', 'utils'));
7+
addpath(fullfile(pth, 'subfun'));
8+
9+
end

convertSourceToRaw.m

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
function convertSourceToRaw(expParameters)
2+
3+
sourceDir = fullfile(expParameters.outputDir, 'source');
4+
rawDir = fullfile(expParameters.outputDir, 'rawdata');
5+
6+
% add dummy readme and change file
7+
copyfile(fullfile('..', 'dummyData', 'README'), sourceDir);
8+
copyfile(fullfile('..', 'dummyData', 'CHANGES'), sourceDir);
9+
10+
copyfile(sourceDir, rawDir);
11+
12+
% list subjects
13+
subjects = cellstr(file_utils('List', rawDir, 'dir', '^sub-.*$'));
14+
15+
if isequal(subjects, {''})
16+
error('No subjects found in BIDS directory.');
17+
end
18+
19+
for su = 1:numel(subjects)
20+
21+
sess = cellstr(file_utils('List', fullfile(rawDir, subjects{su}), 'dir', '^ses-.*$'));
22+
23+
for se = 1:numel(sess)
24+
parseFunc(rawDir, subjects{su}, sess{se});
25+
end
26+
27+
end
28+
29+
end
30+
31+
function parseFunc(rawDir, subjName, sesName)
32+
33+
subjectPath = fullfile(rawDir, subjName, sesName, 'func');
34+
35+
if exist(subjectPath, 'dir')
36+
37+
% do events
38+
filenames = file_utils('List', subjectPath, ...
39+
sprintf('^%s.*_task-.*_events_date-.*$', subjName));
40+
41+
removeDateSuffix(filenames, subjectPath);
42+
43+
% do bold
44+
filenames = file_utils('List', subjectPath, ...
45+
sprintf('^%s.*_task-.*_bold_date-.*$', subjName));
46+
47+
removeDateSuffix(filenames, subjectPath);
48+
49+
end
50+
end
51+
52+
function removeDateSuffix(filenames, subjectPath)
53+
if isempty(filenames)
54+
filenames = {};
55+
else
56+
filenames = cellstr(filenames);
57+
end
58+
59+
for i = 1:numel(filenames)
60+
61+
[~, name, ext] = fileparts(filenames{i});
62+
63+
[parts, ~] = regexp(name, '(?:_date-)+', 'split', 'match');
64+
65+
movefile(fullfile(subjectPath, filenames{i}), ...
66+
fullfile(subjectPath, [parts{1} ext]));
67+
68+
end
69+
end

createBoldJson.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function createBoldJson(expParameters)
2+
3+
opts.Indent = ' ';
4+
5+
fileName = strrep(expParameters.fileName.events, '_events', '_bold');
6+
fileName = strrep(fileName, '.tsv', '.json');
7+
8+
fileName = fullfile( ...
9+
expParameters.subjectOutputDir, ...
10+
expParameters.modality, ...
11+
fileName);
12+
13+
jsonContent = expParameters.bids.MRI;
14+
15+
bids.util.jsonencode(fileName, jsonContent, opts);
16+
17+
end

createDataDictionary.m

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
function createDataDictionary(expParameters, logFile)
2+
3+
opts.Indent = ' ';
4+
5+
fileName = strrep(expParameters.fileName.events, '.tsv', '.json');
6+
7+
fileName = fullfile( ...
8+
expParameters.subjectOutputDir, ...
9+
expParameters.modality, ...
10+
fileName);
11+
12+
jsonContent = struct( ...
13+
'onset', struct( ...
14+
'Description', 'time elapsed since experiment start', ...
15+
'Unit', 's'), ...
16+
'trial_type', struct( ...
17+
'Description', 'types of trial', ...
18+
'Levels', ''), ...
19+
'duration', struct( ...
20+
'Description', 'duration of the event or the block', ...
21+
'Unit', 's') ...
22+
);
23+
24+
% transfer content of extra fields to json content
25+
namesExtraColumns = returnNamesExtraColumns(logFile);
26+
27+
for iExtraColumn = 1:numel(namesExtraColumns)
28+
29+
nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn});
30+
31+
for iCol = 1:nbCol
32+
33+
headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol);
34+
35+
jsonContent.(headerName) = ...
36+
logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}).bids;
37+
38+
end
39+
40+
end
41+
42+
bids.util.jsonencode(fileName, jsonContent, opts);
43+
44+
end

createDatasetDescription.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function createDatasetDescription(expParameters)
2+
3+
opts.Indent = ' ';
4+
5+
fileName = fullfile( ...
6+
expParameters.outputDir, 'source', ...
7+
'dataset_description.json');
8+
9+
jsonContent = expParameters.bids.datasetDescription;
10+
11+
bids.util.jsonencode(fileName, jsonContent, opts);
12+
13+
end

0 commit comments

Comments
 (0)