From a0eb19b614dcc97d168931922749d12ad288cfa3 Mon Sep 17 00:00:00 2001 From: Tomas Lenc Date: Fri, 23 Oct 2020 14:09:46 +0200 Subject: [PATCH 1/9] enable setting column Levels properties Changed order in which things are done when initializing. Now, all the "holy trinity" columns and user-specified extra columns are saved in the structure after calling saveEventsFile('init'). Next, the user can edit column properties before calling saveEventsFile('open') which will write the JSON. This way, Levels of e.g. trial_type can be set by the user. Moreover, this gives the user the freedom to set the Levels as containers.Map data type, which describes mapping between each level name and its corresponding description. This is super useful because sometimes levels can have cryptic names like '1' and '2', and so it's handy to explain what each code means (e.g. 'left' and 'right' respectively). Here is an example: % allocate logFile = []; % We can define what extra columns we want in our tsv file beyond the % BIDS holy trinity ('onset', 'duration', 'trial_type') logFile.extraColumns = {'rhythm', 'trigger'}; % init logfile logFile = saveEventsFile('init',cfg,logFile); % change info about trial_type logFile.columns.trial_type.Levels = containers.Map({'listen','tap'}, ... {'listen without movement','tap finger with the pulse'}); % change units to miliseconds logFile.columns.onset.Unit = 'ms'; logFile.columns.duration.Unit = 'ms'; % add info to the extra columns logFile.extraColumns.rhythm.bids.Description = 'name of the rhythmic pattern'; logFile.extraColumns.rhythm.bids.Levels = {'unsyncopated','syncopated'}; logFile.extraColumns.trigger.bids.Description = 'EEG trigger value'; logFile.extraColumns.trigger.bids.Levels = containers.Map({'1','2'},{'low tone','high tone'}); % open tsv and write json for events logFile = saveEventsFile('open',cfg,logFile); --- src/createDataDictionary.m | 28 ++++++++----------- src/saveEventsFile.m | 56 ++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/createDataDictionary.m b/src/createDataDictionary.m index def87e47..b7d28873 100644 --- a/src/createDataDictionary.m +++ b/src/createDataDictionary.m @@ -20,28 +20,14 @@ function createDataDictionary(cfg, logFile) jsonContent = setJsonContent(fullFilename, logFile); opts.Indent = ' '; + bids.util.jsonencode(fullFilename, jsonContent, opts); end function jsonContent = setJsonContent(fullFilename, logFile) - % transfer content of extra fields to json content - namesExtraColumns = returnNamesExtraColumns(logFile); - - % default content for events file that will be overriddent if we are dealing - % with a stim file - jsonContent = struct( ... - 'onset', struct( ... - 'Description', 'time elapsed since experiment start', ... - 'Units', 's'), ... - 'trial_type', struct( ... - 'Description', 'types of trial', ... - 'Levels', ''), ... - 'duration', struct( ... - 'Description', 'duration of the event', ... - 'Units', 's') ... - ); + if ismember('_stim', fullFilename) @@ -60,8 +46,16 @@ function createDataDictionary(cfg, logFile) 'StartTime', startTime, ... 'Columns', []); + else + + % add holy trininty columns to the json content + jsonContent = logFile.columns; + end - + + % transfer content of extra fields to json content + namesExtraColumns = returnNamesExtraColumns(logFile); + for iExtraColumn = 1:numel(namesExtraColumns) nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn}); diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index dff76120..48ac22cf 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -88,20 +88,21 @@ case 'init' - logFile = initializeExtraColumns(logFile); - - case 'open' - logFile(1).filename = cfg.fileName.events; logFile = initializeFile(cfg, logFile); - - case 'open_stim' + + case 'init_stim' logFile(1).filename = cfg.fileName.stim; logFile = initializeStimFile(cfg, logFile); + case 'open' + + logFile = openFile(cfg, logFile); + + case 'save' checklLogFile('checkID', logFile); @@ -164,18 +165,28 @@ end function logFile = initializeFile(cfg, logFile) +% This function creates the bids field structure for json files for the +% three basic bids event columns, and for all requested extra columns. +% +% Note that subfields (e.g. unit, levels etc. can be changed by the user +% before calling openFile. + + % initialize holy trinity (onset, trial_type, duration) columns + logFile(1).columns = struct( ... + 'onset', struct( ... + 'Description', 'time elapsed since experiment start', ... + 'Unit', 's'), ... + 'trial_type', struct( ... + 'Description', 'types of trial', ... + 'Levels', ''), ... + 'duration', struct( ... + 'Description', 'duration of the event or the block', ... + 'Unit', 's') ... + ); - logFile = initializeStimFile(cfg, logFile); - - % print the basic BIDS columns - fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); - fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); - printHeaderExtraColumns(logFile); + logFile = initializeStimFile(cfg, logFile); - % next line so we start printing at the right place - fprintf(logFile(1).fileID, '\n'); - fprintf(1, '\n'); end @@ -183,6 +194,10 @@ logFile = initializeExtraColumns(logFile); +end + +function logFile = openFile(cfg, logFile) + createDataDictionary(cfg, logFile); % Initialize txt logfiles and empty fields for the standard BIDS @@ -194,8 +209,19 @@ logFile.filename), ... 'w'); + % print the basic BIDS columns + fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); + fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); + + printHeaderExtraColumns(logFile); + + % next line so we start printing at the right place + fprintf(logFile(1).fileID, '\n'); + fprintf(1, '\n'); + end + function printHeaderExtraColumns(logFile) % print any extra column specified by the user From 69a2816faba47d6f91782a26fe4a414f37b57369 Mon Sep 17 00:00:00 2001 From: Tomas Lenc Date: Thu, 29 Oct 2020 16:16:16 +0100 Subject: [PATCH 2/9] No headers for _stim Additional field .isStim is created in the logFile structure upon initialization (true if _stim file is requested, false otherwise). If _stim file is requested, no headers are printed in the .tsv file, and the standard columns "onset", "duration", "trial_type" are omitted. --- src/createDataDictionary.m | 6 +- src/saveEventsFile.m | 111 ++++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/createDataDictionary.m b/src/createDataDictionary.m index b7d28873..9e02b4ed 100644 --- a/src/createDataDictionary.m +++ b/src/createDataDictionary.m @@ -27,9 +27,7 @@ function createDataDictionary(cfg, logFile) function jsonContent = setJsonContent(fullFilename, logFile) - - - if ismember('_stim', fullFilename) + if logFile.isStim == 1 samplingFrequency = nan; startTime = nan; @@ -46,7 +44,7 @@ function createDataDictionary(cfg, logFile) 'StartTime', startTime, ... 'Columns', []); - else + elseif logFile.isStim == 1 % add holy trininty columns to the json content jsonContent = logFile.columns; diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index 48ac22cf..ee1c1623 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -88,12 +88,18 @@ case 'init' + % flag to indicate that this will be an _events file + logFile.isStim = 0; + logFile(1).filename = cfg.fileName.events; logFile = initializeFile(cfg, logFile); case 'init_stim' + % flag to indicate that this will be an _stim file + logFile.isStim = 1; + logFile(1).filename = cfg.fileName.stim; logFile = initializeStimFile(cfg, logFile); @@ -185,13 +191,12 @@ ); - logFile = initializeStimFile(cfg, logFile); - + logFile = initializeExtraColumns(logFile); end function logFile = initializeStimFile(cfg, logFile) - + logFile = initializeExtraColumns(logFile); end @@ -201,7 +206,7 @@ createDataDictionary(cfg, logFile); % Initialize txt logfiles and empty fields for the standard BIDS - % event file + % event file logFile(1).fileID = fopen( ... fullfile( ... cfg.dir.outputSubject, ... @@ -209,19 +214,24 @@ logFile.filename), ... 'w'); - % print the basic BIDS columns - fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); - fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); + if logFile(1,1).isStim == 0 + % print the basic BIDS columns + fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); + fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); - printHeaderExtraColumns(logFile); + printHeaderExtraColumns(logFile); - % next line so we start printing at the right place - fprintf(logFile(1).fileID, '\n'); - fprintf(1, '\n'); + % next line so we start printing at the right place + fprintf(logFile(1).fileID, '\n'); + fprintf(1, '\n'); + + elseif logFile(1,1).isStim == 1 + % don't print column headers for _stim.tsv + + end end - function printHeaderExtraColumns(logFile) % print any extra column specified by the user @@ -249,7 +259,7 @@ function printHeaderExtraColumns(logFile) % if the field we are looking for does not exist or is empty in the % action logFile structure we will write a n/a % otherwise we write its content - + namesExtraColumns = returnNamesExtraColumns(logFile); for iExtraColumn = 1:numel(namesExtraColumns) @@ -277,7 +287,7 @@ function printHeaderExtraColumns(logFile) elseif ~ischar(data) && all(isnan(data)) warning('Missing %s data for this event.', namesExtraColumns{iExtraColumn}); - + if cfg.verbose > 1 disp(logFile(iEvent)); end @@ -333,32 +343,55 @@ function printHeaderExtraColumns(logFile) logFile = checklLogFile('fields', logFile, iEvent, cfg); - onset = logFile(iEvent).onset; - duration = logFile(iEvent).duration; - trial_type = logFile(iEvent).trial_type; - - % we skip events with onset or duration that are empty, nan or char - if any(cell2mat(cellfun(@isnan, {onset duration}, 'UniformOutput', false))) || ... - any(cellfun(@ischar, {onset duration})) || ... - any(isempty({onset duration})) - - warning('saveEventsFile:emptyEvent', ... - '\nSkipping saving this event.\n onset: %s \n duration: %s\n', ... - onset, ... - duration); - - else - - printData(logFile(1).fileID, onset, cfg); - printData(logFile(1).fileID, duration, cfg); - printData(logFile(1).fileID, trial_type, cfg); + % if this is _events file, we skip events with onset or duration + % that are empty, nan or char. + if logFile(1,1).isStim==0 + + onset = logFile(iEvent).onset; + duration = logFile(iEvent).duration; + trial_type = logFile(iEvent).trial_type; + + if any(cell2mat(cellfun(@isnan, {onset duration}, 'UniformOutput', false))) || ... + any(cellfun(@ischar, {onset duration})) || ... + any(isempty({onset duration})) + + warning('saveEventsFile:emptyEvent', ... + '\nSkipping saving this event.\n onset: %s \n duration: %s\n', ... + onset, ... + duration); + else + printData(logFile(1).fileID, onset, cfg); + printData(logFile(1).fileID, duration, cfg); + printData(logFile(1).fileID, trial_type, cfg); + + printExtraColumns(logFile, iEvent, cfg); - printExtraColumns(logFile, iEvent, cfg); + fprintf(logFile(1).fileID, '\n'); + fprintf(1, '\n'); - fprintf(logFile(1).fileID, '\n'); - fprintf(1, '\n'); + end + + % if this is _stim file, we skip missing events (i.e. events where + % all extra columns have NO values) + elseif logFile(1,1).isStim==1 + + skipEvent = false; + namesExtraColumns = returnNamesExtraColumns(logFile); + for iExtraColumn = 1:numel(namesExtraColumns) + data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); + if isempty(data) || isnan(data) || ( ischar(data) && strcmp(data,'n/a') ) + skipEvent = true; + end + end + if ~skipEvent + printExtraColumns(logFile, iEvent, cfg); + fprintf(logFile(1).fileID, '\n'); + fprintf(1, '\n'); + end + end + end end @@ -408,7 +441,11 @@ function printData(output, data, cfg) logFile(2:end) = []; - namesColumns = {'onset', 'duration', 'trial_type'}; + if logFile(1,1).isStim == 0 + namesColumns = {'onset', 'duration', 'trial_type'}; + elseif logFile(1,1).isStim == 1 + namesColumns = {}; + end namesExtraColumns = returnNamesExtraColumns(logFile); namesColumns = cat(2, namesColumns, namesExtraColumns'); From 3859e60caa89e1f7c97ad5c0e935f9c557745256 Mon Sep 17 00:00:00 2001 From: Tomas Lenc Date: Tue, 3 Nov 2020 00:49:09 +0100 Subject: [PATCH 3/9] Small changes Changes based on Remi-Gau's comments. --- src/createDataDictionary.m | 20 +++++----- src/saveEventsFile.m | 76 ++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/createDataDictionary.m b/src/createDataDictionary.m index 9e02b4ed..3e02f3e3 100644 --- a/src/createDataDictionary.m +++ b/src/createDataDictionary.m @@ -27,8 +27,14 @@ function createDataDictionary(cfg, logFile) function jsonContent = setJsonContent(fullFilename, logFile) - if logFile.isStim == 1 + % add default _event file fields to the json content + if ~logFile.isStim + + jsonContent = logFile.columns; + % write json fields if this is a _stim file + elseif logFile.isStim + samplingFrequency = nan; startTime = nan; @@ -43,14 +49,8 @@ function createDataDictionary(cfg, logFile) 'SamplingFrequency', samplingFrequency, ... 'StartTime', startTime, ... 'Columns', []); - - elseif logFile.isStim == 1 - - % add holy trininty columns to the json content - jsonContent = logFile.columns; - end - + % transfer content of extra fields to json content namesExtraColumns = returnNamesExtraColumns(logFile); @@ -62,10 +62,8 @@ function createDataDictionary(cfg, logFile) headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol); - if ismember('_stim', fullFilename) - + if logFile.isStim jsonContent.Columns{end + 1} = headerName; - end jsonContent.(headerName) = ... diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index ee1c1623..4d575938 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -72,12 +72,9 @@ % % - if nargin < 1 - error('Missing action input'); - end - if nargin < 2 - cfg = struct(); + error(['Missing arguments. Please specify ',... + 'and as the first two arguments']); end if nargin < 3 || isempty(logFile) @@ -89,7 +86,7 @@ case 'init' % flag to indicate that this will be an _events file - logFile.isStim = 0; + logFile(1).isStim = 0; logFile(1).filename = cfg.fileName.events; @@ -98,7 +95,7 @@ case 'init_stim' % flag to indicate that this will be an _stim file - logFile.isStim = 1; + logFile(1).isStim = 1; logFile(1).filename = cfg.fileName.stim; @@ -214,7 +211,7 @@ logFile.filename), ... 'w'); - if logFile(1,1).isStim == 0 + if logFile(1).isStim == 0 % print the basic BIDS columns fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); @@ -225,7 +222,7 @@ fprintf(logFile(1).fileID, '\n'); fprintf(1, '\n'); - elseif logFile(1,1).isStim == 1 + elseif logFile(1).isStim == 1 % don't print column headers for _stim.tsv end @@ -343,9 +340,12 @@ function printHeaderExtraColumns(logFile) logFile = checklLogFile('fields', logFile, iEvent, cfg); + % check if this event should be skipped + skipEvent = false; + % if this is _events file, we skip events with onset or duration % that are empty, nan or char. - if logFile(1,1).isStim==0 + if logFile(1).isStim==0 onset = logFile(iEvent).onset; duration = logFile(iEvent).duration; @@ -355,41 +355,54 @@ function printHeaderExtraColumns(logFile) any(cellfun(@ischar, {onset duration})) || ... any(isempty({onset duration})) - warning('saveEventsFile:emptyEvent', ... - '\nSkipping saving this event.\n onset: %s \n duration: %s\n', ... + skipEvent = true; + + warningMessage = sprintf(['saveEventsFile:emptyEvent', ... + '\nSkipping saving this event.\n onset: %s \n duration: %s\n'], ... onset, ... duration); - else - printData(logFile(1).fileID, onset, cfg); - printData(logFile(1).fileID, duration, cfg); - printData(logFile(1).fileID, trial_type, cfg); - - printExtraColumns(logFile, iEvent, cfg); - - fprintf(logFile(1).fileID, '\n'); - fprintf(1, '\n'); - end % if this is _stim file, we skip missing events (i.e. events where % all extra columns have NO values) - elseif logFile(1,1).isStim==1 + elseif logFile(1).isStim==1 - skipEvent = false; namesExtraColumns = returnNamesExtraColumns(logFile); + isValid = ones(1,numel(namesExtraColumns)) for iExtraColumn = 1:numel(namesExtraColumns) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); if isempty(data) || isnan(data) || ( ischar(data) && strcmp(data,'n/a') ) - skipEvent = true; + isValid(iExtraColumn) = 0; end end - if ~skipEvent - printExtraColumns(logFile, iEvent, cfg); + if ~any(isValid) + skipEvent = true; + + warningMessage = sprintf(['saveEventsFile:emptyEvent', ... + '\nSkipping saving this event.\n No values defined. \n']); + end + end + + % now save the event to log file (if not skipping) + if skipEvent + + warning(warningMessage); + + else + + if logFile(1).isStim==0 + + printData(logFile(1).fileID, onset, cfg); + printData(logFile(1).fileID, duration, cfg); + printData(logFile(1).fileID, trial_type, cfg); - fprintf(logFile(1).fileID, '\n'); - fprintf(1, '\n'); end + printExtraColumns(logFile, iEvent, cfg); + + fprintf(logFile(1).fileID, '\n'); + fprintf(1, '\n'); + end end @@ -441,9 +454,8 @@ function printData(output, data, cfg) logFile(2:end) = []; - if logFile(1,1).isStim == 0 - namesColumns = {'onset', 'duration', 'trial_type'}; - elseif logFile(1,1).isStim == 1 + namesColumns = {'onset', 'duration', 'trial_type'}; + if logFile(1).isStim == 1 namesColumns = {}; end namesExtraColumns = returnNamesExtraColumns(logFile); From 98d8ccf9a9f3a0427db0671d6db0edd54d5a6bd4 Mon Sep 17 00:00:00 2001 From: Tomas Lenc Date: Mon, 16 Nov 2020 00:50:04 +0100 Subject: [PATCH 4/9] updated tests and small changes All unit tests are working with the updated functions. Also, applied some small changes requested in the review process for the PR. --- src/createDataDictionary.m | 12 ++-- src/saveEventsFile.m | 73 ++++++++++++++-------- src/utils/utilsForTests/setUp.m | 6 +- tests/testData/stimDataDictionary.json | 46 ++++++++++++++ tests/test_createDataDictionary.m | 50 +++++++++------ tests/test_readAndFilterLogfile.m | 2 +- tests/test_saveEventsFileInit.m | 20 ++++-- tests/test_saveEventsFileOpen.m | 10 ++- tests/test_saveEventsFileOpenMultiColumn.m | 10 ++- 9 files changed, 167 insertions(+), 62 deletions(-) create mode 100644 tests/testData/stimDataDictionary.json diff --git a/src/createDataDictionary.m b/src/createDataDictionary.m index 3e02f3e3..bd7e202a 100644 --- a/src/createDataDictionary.m +++ b/src/createDataDictionary.m @@ -17,7 +17,7 @@ function createDataDictionary(cfg, logFile) fileName = strrep(logFile(1).filename, '.tsv', '.json'); fullFilename = getFullFilename(fileName, cfg); - jsonContent = setJsonContent(fullFilename, logFile); + jsonContent = setJsonContent(logFile); opts.Indent = ' '; @@ -25,14 +25,14 @@ function createDataDictionary(cfg, logFile) end -function jsonContent = setJsonContent(fullFilename, logFile) +function jsonContent = setJsonContent(logFile) - % add default _event file fields to the json content - if ~logFile.isStim + % regular _events file: add default _event file fields to the json content + if ~isfield(logFile,'isStim') || isempty(logFile.isStim) || ~logFile.isStim jsonContent = logFile.columns; - % write json fields if this is a _stim file + % _stim file: write stim-specific fields to the json content elseif logFile.isStim samplingFrequency = nan; @@ -62,7 +62,7 @@ function createDataDictionary(cfg, logFile) headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol); - if logFile.isStim + if isfield(logFile,'isStim') && ~isempty(logFile.isStim) && logFile.isStim jsonContent.Columns{end + 1} = headerName; end diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index 4d575938..b02b2005 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -86,20 +86,30 @@ case 'init' % flag to indicate that this will be an _events file - logFile(1).isStim = 0; + logFile(1).isStim = false; - logFile(1).filename = cfg.fileName.events; - - logFile = initializeFile(cfg, logFile); + if isfield(cfg,'fileName') && ... + isfield(cfg.fileName,'events') && ... + ~isempty(cfg.fileName.events) + logFile(1).filename = cfg.fileName.events; + else + logFile(1).filename = ''; + end + logFile = initializeFile(logFile); case 'init_stim' % flag to indicate that this will be an _stim file - logFile(1).isStim = 1; + logFile(1).isStim = true; - logFile(1).filename = cfg.fileName.stim; - - logFile = initializeStimFile(cfg, logFile); + if isfield(cfg,'fileName') && ... + isfield(cfg.fileName,'stim') && ... + ~isempty(cfg.fileName.stim) + logFile(1).filename = cfg.fileName.stim; + else + logFile(1).filename = ''; + end + logFile = initializeStimFile(logFile); case 'open' @@ -167,7 +177,7 @@ end -function logFile = initializeFile(cfg, logFile) +function logFile = initializeFile(logFile) % This function creates the bids field structure for json files for the % three basic bids event columns, and for all requested extra columns. % @@ -178,13 +188,13 @@ logFile(1).columns = struct( ... 'onset', struct( ... 'Description', 'time elapsed since experiment start', ... - 'Unit', 's'), ... + 'Units', 's'), ... 'trial_type', struct( ... 'Description', 'types of trial', ... 'Levels', ''), ... 'duration', struct( ... 'Description', 'duration of the event or the block', ... - 'Unit', 's') ... + 'Units', 's') ... ); @@ -192,7 +202,7 @@ end -function logFile = initializeStimFile(cfg, logFile) +function logFile = initializeStimFile(logFile) logFile = initializeExtraColumns(logFile); @@ -211,7 +221,7 @@ logFile.filename), ... 'w'); - if logFile(1).isStim == 0 + if ~logFile(1).isStim % print the basic BIDS columns fprintf(logFile(1).fileID, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); fprintf(1, '%s\t%s\t%s', 'onset', 'duration', 'trial_type'); @@ -222,7 +232,7 @@ fprintf(logFile(1).fileID, '\n'); fprintf(1, '\n'); - elseif logFile(1).isStim == 1 + elseif logFile(1).isStim % don't print column headers for _stim.tsv end @@ -334,6 +344,7 @@ function printHeaderExtraColumns(logFile) function logFile = saveToLogFile(logFile, cfg) + % appends to the logfile all the data stored in the structure % first with the standard BIDS data and then any extra things for iEvent = 1:size(logFile, 1) @@ -345,7 +356,7 @@ function printHeaderExtraColumns(logFile) % if this is _events file, we skip events with onset or duration % that are empty, nan or char. - if logFile(1).isStim==0 + if ~logFile(1).isStim onset = logFile(iEvent).onset; duration = logFile(iEvent).duration; @@ -357,40 +368,48 @@ function printHeaderExtraColumns(logFile) skipEvent = true; - warningMessage = sprintf(['saveEventsFile:emptyEvent', ... - '\nSkipping saving this event.\n onset: %s \n duration: %s\n'], ... - onset, ... - duration); + warningMessageID = 'saveEventsFile:emptyEvent'; + warningMessage = sprintf(['Skipping saving this event. \n '... + 'onset: %s \n duration: %s \n'], ... + onset, ... + duration); end % if this is _stim file, we skip missing events (i.e. events where % all extra columns have NO values) - elseif logFile(1).isStim==1 + elseif logFile(1).isStim namesExtraColumns = returnNamesExtraColumns(logFile); - isValid = ones(1,numel(namesExtraColumns)) + isValid = ones(1,numel(namesExtraColumns)); for iExtraColumn = 1:numel(namesExtraColumns) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); if isempty(data) || isnan(data) || ( ischar(data) && strcmp(data,'n/a') ) isValid(iExtraColumn) = 0; end end - if ~any(isValid) + if all(~isValid) skipEvent = true; - warningMessage = sprintf(['saveEventsFile:emptyEvent', ... - '\nSkipping saving this event.\n No values defined. \n']); + warningMessageID = 'saveEventsFile:emptyEvent'; + warningMessage = sprintf(['Skipping saving this event. \n', ... + 'No values defined. \n']); + elseif any(~isValid) + skipEvent = false; + + warningMessageID = 'saveEventsFile:missingData'; + warningMessage = sprintf('Missing some %s data for this event. \n', ... + namesExtraColumns{find(isValid)}); end end % now save the event to log file (if not skipping) if skipEvent - warning(warningMessage); + warning(warningMessageID, warningMessage); else - if logFile(1).isStim==0 + if ~logFile(1).isStim printData(logFile(1).fileID, onset, cfg); printData(logFile(1).fileID, duration, cfg); @@ -455,7 +474,7 @@ function printData(output, data, cfg) logFile(2:end) = []; namesColumns = {'onset', 'duration', 'trial_type'}; - if logFile(1).isStim == 1 + if logFile(1).isStim namesColumns = {}; end namesExtraColumns = returnNamesExtraColumns(logFile); diff --git a/src/utils/utilsForTests/setUp.m b/src/utils/utilsForTests/setUp.m index fa29d4f4..efdb7685 100644 --- a/src/utils/utilsForTests/setUp.m +++ b/src/utils/utilsForTests/setUp.m @@ -10,9 +10,13 @@ cfg.task.name = 'testtask'; cfg.testingDevice = 'mri'; - + cfg = createFilename(cfg); + logFile.extraColumns = {'Speed','LHL24','is_Fixation'}; + + logFile = saveEventsFile('init', cfg, logFile); + logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 12; logFile.extraColumns.is_Fixation.length = 1; diff --git a/tests/testData/stimDataDictionary.json b/tests/testData/stimDataDictionary.json new file mode 100644 index 00000000..39490c72 --- /dev/null +++ b/tests/testData/stimDataDictionary.json @@ -0,0 +1,46 @@ +{ + "SamplingFrequency": 100, + "StartTime": 0, + "Columns": [ + "Speed", + "LHL24_01", + "LHL24_02", + "LHL24_03", + "is_Fixation" + ], + "Speed": { + "Description": "", + "Levels": "", + "LongName": "", + "TermURL": "", + "Units": "" + }, + "LHL24_01": { + "Description": "", + "Levels": "", + "LongName": "", + "TermURL": "", + "Units": "" + }, + "LHL24_02": { + "Description": "", + "Levels": "", + "LongName": "", + "TermURL": "", + "Units": "" + }, + "LHL24_03": { + "Description": "", + "Levels": "", + "LongName": "", + "TermURL": "", + "Units": "" + }, + "is_Fixation": { + "Description": "", + "Levels": "", + "LongName": "", + "TermURL": "", + "Units": "" + } +} \ No newline at end of file diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index cb3423ab..71d3c5f6 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -25,14 +25,15 @@ function test_createDataDictionaryBasic() cfg = createFilename(cfg); + logFile.extraColumns = {'Speed','LHL24'}; + + logFile = saveEventsFile('init', cfg, logFile); + logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; - logFile = saveEventsFile('init', cfg, logFile); logFile = saveEventsFile('open', cfg, logFile); - createDataDictionary(cfg, logFile); - %% check that the file has the right path and name % data to test against @@ -53,16 +54,17 @@ function test_createDataDictionaryBasic() % test_createDataDictionary>test_createDataDictionaryBasic:48 % (/github/workspace/tests/test_createDataDictionary.m) - % actualStruct = bids.util.jsondecode(fullfile(funcDir, jsonFilename)); - % - % % data to test against - % expectedStruct = bids.util.jsondecode( ... - % fullfile(pwd, ... - % 'testData', ... - % 'eventsDataDictionary.json')); - % - % % test - % assertTrue(isequal(expectedStruct, actualStruct)); + actualStruct = bids.util.jsondecode(fullfile(funcDir, jsonFilename)); + + % data to test against + expectedStruct = bids.util.jsondecode( ... + fullfile( ... + pwd, ... + 'testData', ... + 'eventsDataDictionary.json')); + + % test + assertTrue(isequal(expectedStruct, actualStruct)); end @@ -85,6 +87,10 @@ function test_createDataDictionaryStim() cfg = createFilename(cfg); + stimLogFile.extraColumns = {'Speed','LHL24','is_Fixation'}; + + stimLogFile = saveEventsFile('init_stim', cfg, stimLogFile); + stimLogFile.extraColumns.Speed.length = 1; stimLogFile.extraColumns.LHL24.length = 3; stimLogFile.extraColumns.is_Fixation.length = 1; @@ -92,11 +98,7 @@ function test_createDataDictionaryStim() stimLogFile.SamplingFrequency = 100; stimLogFile.StartTime = 0; - stimLogFile = saveEventsFile('init', cfg, stimLogFile); - - stimLogFile = saveEventsFile('open_stim', cfg, stimLogFile); - - createDataDictionary(cfg, stimLogFile); + stimLogFile = saveEventsFile('open', cfg, stimLogFile); %% check that the file has the right path and name @@ -117,5 +119,17 @@ function test_createDataDictionaryStim() % jsondecode:27 (/github/workspace/lib/bids-matlab/+bids/+util/jsondecode.m) % test_createDataDictionary>test_createDataDictionaryBasic:48 % (/github/workspace/tests/test_createDataDictionary.m) + + actualStruct = bids.util.jsondecode(fullfile(funcDir, jsonFilename)); + + % data to test against + expectedStruct = bids.util.jsondecode( ... + fullfile( ... + pwd, ... + 'testData', ... + 'stimDataDictionary.json')); + + % test + assertTrue(isequal(expectedStruct, actualStruct)); end diff --git a/tests/test_readAndFilterLogfile.m b/tests/test_readAndFilterLogfile.m index 81406ed5..ab2c49c7 100644 --- a/tests/test_readAndFilterLogfile.m +++ b/tests/test_readAndFilterLogfile.m @@ -9,8 +9,8 @@ function test_readAndFilterLogfileBasic() %% set up - cfg.dir.output = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); [cfg, logFile] = setUp(); + cfg.dir.output = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); % create the events file and header logFile = saveEventsFile('open', cfg, logFile); diff --git a/tests/test_saveEventsFileInit.m b/tests/test_saveEventsFileInit.m index ebc077ac..9c7209a6 100644 --- a/tests/test_saveEventsFileInit.m +++ b/tests/test_saveEventsFileInit.m @@ -15,15 +15,25 @@ function test_saveEventsFileInitBasic() % make sure the dependencies are there checkCFG(cfg); - [logFile] = saveEventsFile('init'); + [logFile] = saveEventsFile('init',cfg); %% data to test against expectedStrcut(1).filename = ''; expectedStrcut(1).extraColumns = []; - + expectedStrcut(1).isStim = false; + + expectedStrcut(1).columns.onset.Description = 'time elapsed since experiment start'; + expectedStrcut(1).columns.onset.Units = 's'; + + expectedStrcut(1).columns.trial_type.Description = 'types of trial'; + expectedStrcut(1).columns.trial_type.Levels = ''; + + expectedStrcut(1).columns.duration.Description = 'duration of the event or the block'; + expectedStrcut(1).columns.duration.Units = 's'; + %% test - assertEqual(expectedStrcut, logFile); - + assertTrue(isequal(expectedStrcut, logFile)); + end function test_saveEventsFileInitExtraColumns() @@ -39,6 +49,7 @@ function test_saveEventsFileInitExtraColumns() [logFile] = saveEventsFile('init', cfg, logFile); %% data to test against + expectedStrcut = saveEventsFile('init',cfg); expectedStrcut(1).extraColumns.Speed.length = 1; expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; expectedStrcut(1).extraColumns.Speed.bids.Description = ''; @@ -65,6 +76,7 @@ function test_saveEventsFileInitExtraColumnsArray() [logFile] = saveEventsFile('init', cfg, logFile); %% data to test against + expectedStrcut = saveEventsFile('init',cfg); expectedStrcut(1).extraColumns.Speed.length = 1; expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; expectedStrcut(1).extraColumns.Speed.bids.Description = ''; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index be04d199..25e50805 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -24,9 +24,11 @@ function test_saveEventsFileOpenBasic() cfg.testingDevice = 'mri'; cfg = createFilename(cfg); + + logFile = saveEventsFile('init', cfg); % create the events file and header - logFile = saveEventsFile('open', cfg); + logFile = saveEventsFile('open', cfg, logFile); % close the file saveEventsFile('close', cfg, logFile); @@ -70,8 +72,10 @@ function test_saveEventsFileOpenStimfile() cfg = createFilename(cfg); + logFile = saveEventsFile('init_stim', cfg); + % create the events file and header - logFile = saveEventsFile('open_stim', cfg); + logFile = saveEventsFile('open', cfg, logFile); % close the file saveEventsFile('close', cfg, logFile); @@ -111,6 +115,8 @@ function test_saveEventsFileOpenExtraColumns() % they will be added to the tsv files in the order the user input them logFile.extraColumns = {'Speed', 'is_Fixation'}; + logFile = saveEventsFile('init', cfg, logFile); + % create the events file and header logFile = saveEventsFile('open', cfg, logFile); diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index 05e63f41..74bb22e4 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -25,11 +25,15 @@ function test_saveEventsFileOpenMultiColumnCheckHeader() cfg = createFilename(cfg); - % define the extra columns: here we specify how many columns we want for - % each variable + % define the extra columns names + logFile.extraColumns = {'Speed','LHL24','is_Fixation'}; + + % initalize logfile + logFile = saveEventsFile('init', cfg, logFile); + + % extra columns: here we specify how many columns we want for each variable logFile.extraColumns.Speed.length = 1; % will set 1 columns with name Speed logFile.extraColumns.LHL24.length = 12; % will set 12 columns with names LHL24-01, LHL24-02, ... - logFile.extraColumns.is_Fixation = []; % will set 1 columns with name is_Fixation % create the events file and header logFile = saveEventsFile('open', cfg, logFile); From 72b57681e6f62fcac1bbed1be0336b46d48a5b57 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 16 Nov 2020 22:58:44 +0100 Subject: [PATCH 5/9] mh autofix --- src/createDataDictionary.m | 18 +-- src/saveEventsFile.m | 137 ++++++++++----------- src/utils/utilsForTests/setUp.m | 6 +- tests/test_createDataDictionary.m | 22 ++-- tests/test_createQuestionList.m | 1 - tests/test_saveEventsFileInit.m | 30 ++--- tests/test_saveEventsFileOpen.m | 2 +- tests/test_saveEventsFileOpenMultiColumn.m | 4 +- 8 files changed, 109 insertions(+), 111 deletions(-) diff --git a/src/createDataDictionary.m b/src/createDataDictionary.m index bd7e202a..28d8d560 100644 --- a/src/createDataDictionary.m +++ b/src/createDataDictionary.m @@ -20,7 +20,7 @@ function createDataDictionary(cfg, logFile) jsonContent = setJsonContent(logFile); opts.Indent = ' '; - + bids.util.jsonencode(fullFilename, jsonContent, opts); end @@ -28,13 +28,13 @@ function createDataDictionary(cfg, logFile) function jsonContent = setJsonContent(logFile) % regular _events file: add default _event file fields to the json content - if ~isfield(logFile,'isStim') || isempty(logFile.isStim) || ~logFile.isStim - - jsonContent = logFile.columns; + if ~isfield(logFile, 'isStim') || isempty(logFile.isStim) || ~logFile.isStim + + jsonContent = logFile.columns; - % _stim file: write stim-specific fields to the json content + % _stim file: write stim-specific fields to the json content elseif logFile.isStim - + samplingFrequency = nan; startTime = nan; @@ -50,10 +50,10 @@ function createDataDictionary(cfg, logFile) 'StartTime', startTime, ... 'Columns', []); end - + % transfer content of extra fields to json content namesExtraColumns = returnNamesExtraColumns(logFile); - + for iExtraColumn = 1:numel(namesExtraColumns) nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn}); @@ -62,7 +62,7 @@ function createDataDictionary(cfg, logFile) headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol); - if isfield(logFile,'isStim') && ~isempty(logFile.isStim) && logFile.isStim + if isfield(logFile, 'isStim') && ~isempty(logFile.isStim) && logFile.isStim jsonContent.Columns{end + 1} = headerName; end diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index b02b2005..39027fb7 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -73,7 +73,7 @@ % if nargin < 2 - error(['Missing arguments. Please specify ',... + error(['Missing arguments. Please specify ', ... 'and as the first two arguments']); end @@ -86,28 +86,28 @@ case 'init' % flag to indicate that this will be an _events file - logFile(1).isStim = false; + logFile(1).isStim = false; - if isfield(cfg,'fileName') && ... - isfield(cfg.fileName,'events') && ... + if isfield(cfg, 'fileName') && ... + isfield(cfg.fileName, 'events') && ... ~isempty(cfg.fileName.events) logFile(1).filename = cfg.fileName.events; else - logFile(1).filename = ''; + logFile(1).filename = ''; end logFile = initializeFile(logFile); - + case 'init_stim' % flag to indicate that this will be an _stim file - logFile(1).isStim = true; - - if isfield(cfg,'fileName') && ... - isfield(cfg.fileName,'stim') && ... + logFile(1).isStim = true; + + if isfield(cfg, 'fileName') && ... + isfield(cfg.fileName, 'stim') && ... ~isempty(cfg.fileName.stim) logFile(1).filename = cfg.fileName.stim; else - logFile(1).filename = ''; + logFile(1).filename = ''; end logFile = initializeStimFile(logFile); @@ -115,7 +115,6 @@ logFile = openFile(cfg, logFile); - case 'save' checklLogFile('checkID', logFile); @@ -178,32 +177,33 @@ end function logFile = initializeFile(logFile) -% This function creates the bids field structure for json files for the -% three basic bids event columns, and for all requested extra columns. -% -% Note that subfields (e.g. unit, levels etc. can be changed by the user -% before calling openFile. + % This function creates the bids field structure for json files for the + % three basic bids event columns, and for all requested extra columns. + % + % Note that subfields (e.g. unit, levels etc. can be changed by the user + % before calling openFile. % initialize holy trinity (onset, trial_type, duration) columns logFile(1).columns = struct( ... - 'onset', struct( ... - 'Description', 'time elapsed since experiment start', ... - 'Units', 's'), ... - 'trial_type', struct( ... - 'Description', 'types of trial', ... - 'Levels', ''), ... - 'duration', struct( ... - 'Description', 'duration of the event or the block', ... - 'Units', 's') ... - ); - + 'onset', struct( ... + 'Description', ... + 'time elapsed since experiment start', ... + 'Units', 's'), ... + 'trial_type', struct( ... + 'Description', 'types of trial', ... + 'Levels', ''), ... + 'duration', struct( ... + 'Description', ... + 'duration of the event or the block', ... + 'Units', 's') ... + ); logFile = initializeExtraColumns(logFile); end function logFile = initializeStimFile(logFile) - + logFile = initializeExtraColumns(logFile); end @@ -231,10 +231,10 @@ % next line so we start printing at the right place fprintf(logFile(1).fileID, '\n'); fprintf(1, '\n'); - + elseif logFile(1).isStim % don't print column headers for _stim.tsv - + end end @@ -266,7 +266,7 @@ function printHeaderExtraColumns(logFile) % if the field we are looking for does not exist or is empty in the % action logFile structure we will write a n/a % otherwise we write its content - + namesExtraColumns = returnNamesExtraColumns(logFile); for iExtraColumn = 1:numel(namesExtraColumns) @@ -294,7 +294,7 @@ function printHeaderExtraColumns(logFile) elseif ~ischar(data) && all(isnan(data)) warning('Missing %s data for this event.', namesExtraColumns{iExtraColumn}); - + if cfg.verbose > 1 disp(logFile(iEvent)); end @@ -344,7 +344,6 @@ function printHeaderExtraColumns(logFile) function logFile = saveToLogFile(logFile, cfg) - % appends to the logfile all the data stored in the structure % first with the standard BIDS data and then any extra things for iEvent = 1:size(logFile, 1) @@ -352,78 +351,78 @@ function printHeaderExtraColumns(logFile) logFile = checklLogFile('fields', logFile, iEvent, cfg); % check if this event should be skipped - skipEvent = false; - - % if this is _events file, we skip events with onset or duration - % that are empty, nan or char. + skipEvent = false; + + % if this is _events file, we skip events with onset or duration + % that are empty, nan or char. if ~logFile(1).isStim - + onset = logFile(iEvent).onset; duration = logFile(iEvent).duration; trial_type = logFile(iEvent).trial_type; if any(cell2mat(cellfun(@isnan, {onset duration}, 'UniformOutput', false))) || ... any(cellfun(@ischar, {onset duration})) || ... - any(isempty({onset duration})) + any(isempty({onset duration})) - skipEvent = true; + skipEvent = true; - warningMessageID = 'saveEventsFile:emptyEvent'; + warningMessageID = 'saveEventsFile:emptyEvent'; warningMessage = sprintf(['Skipping saving this event. \n '... 'onset: %s \n duration: %s \n'], ... onset, ... duration); end - - % if this is _stim file, we skip missing events (i.e. events where - % all extra columns have NO values) + + % if this is _stim file, we skip missing events (i.e. events where + % all extra columns have NO values) elseif logFile(1).isStim - + namesExtraColumns = returnNamesExtraColumns(logFile); - isValid = ones(1,numel(namesExtraColumns)); + isValid = ones(1, numel(namesExtraColumns)); for iExtraColumn = 1:numel(namesExtraColumns) - data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); - if isempty(data) || isnan(data) || ( ischar(data) && strcmp(data,'n/a') ) - isValid(iExtraColumn) = 0; + data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); + if isempty(data) || isnan(data) || (ischar(data) && strcmp(data, 'n/a')) + isValid(iExtraColumn) = 0; end end - if all(~isValid) - skipEvent = true; - - warningMessageID = 'saveEventsFile:emptyEvent'; + if all(~isValid) + skipEvent = true; + + warningMessageID = 'saveEventsFile:emptyEvent'; warningMessage = sprintf(['Skipping saving this event. \n', ... - 'No values defined. \n']); - elseif any(~isValid) - skipEvent = false; - - warningMessageID = 'saveEventsFile:missingData'; + 'No values defined. \n']); + elseif any(~isValid) + skipEvent = false; + + warningMessageID = 'saveEventsFile:missingData'; warningMessage = sprintf('Missing some %s data for this event. \n', ... - namesExtraColumns{find(isValid)}); + namesExtraColumns{find(isValid)}); end end - + % now save the event to log file (if not skipping) - if skipEvent - - warning(warningMessageID, warningMessage); - + if skipEvent + + warning(warningMessageID, warningMessage); + else - + if ~logFile(1).isStim - + printData(logFile(1).fileID, onset, cfg); printData(logFile(1).fileID, duration, cfg); printData(logFile(1).fileID, trial_type, cfg); end - + printExtraColumns(logFile, iEvent, cfg); fprintf(logFile(1).fileID, '\n'); fprintf(1, '\n'); end - + end end diff --git a/src/utils/utilsForTests/setUp.m b/src/utils/utilsForTests/setUp.m index efdb7685..0f7cf9eb 100644 --- a/src/utils/utilsForTests/setUp.m +++ b/src/utils/utilsForTests/setUp.m @@ -10,11 +10,11 @@ cfg.task.name = 'testtask'; cfg.testingDevice = 'mri'; - + cfg = createFilename(cfg); - logFile.extraColumns = {'Speed','LHL24','is_Fixation'}; - + logFile.extraColumns = {'Speed', 'LHL24', 'is_Fixation'}; + logFile = saveEventsFile('init', cfg, logFile); logFile.extraColumns.Speed.length = 1; diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index 71d3c5f6..daef9e2e 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -25,8 +25,8 @@ function test_createDataDictionaryBasic() cfg = createFilename(cfg); - logFile.extraColumns = {'Speed','LHL24'}; - + logFile.extraColumns = {'Speed', 'LHL24'}; + logFile = saveEventsFile('init', cfg, logFile); logFile.extraColumns.Speed.length = 1; @@ -59,9 +59,9 @@ function test_createDataDictionaryBasic() % data to test against expectedStruct = bids.util.jsondecode( ... fullfile( ... - pwd, ... - 'testData', ... - 'eventsDataDictionary.json')); + pwd, ... + 'testData', ... + 'eventsDataDictionary.json')); % test assertTrue(isequal(expectedStruct, actualStruct)); @@ -87,8 +87,8 @@ function test_createDataDictionaryStim() cfg = createFilename(cfg); - stimLogFile.extraColumns = {'Speed','LHL24','is_Fixation'}; - + stimLogFile.extraColumns = {'Speed', 'LHL24', 'is_Fixation'}; + stimLogFile = saveEventsFile('init_stim', cfg, stimLogFile); stimLogFile.extraColumns.Speed.length = 1; @@ -119,15 +119,15 @@ function test_createDataDictionaryStim() % jsondecode:27 (/github/workspace/lib/bids-matlab/+bids/+util/jsondecode.m) % test_createDataDictionary>test_createDataDictionaryBasic:48 % (/github/workspace/tests/test_createDataDictionary.m) - + actualStruct = bids.util.jsondecode(fullfile(funcDir, jsonFilename)); % data to test against expectedStruct = bids.util.jsondecode( ... fullfile( ... - pwd, ... - 'testData', ... - 'stimDataDictionary.json')); + pwd, ... + 'testData', ... + 'stimDataDictionary.json')); % test assertTrue(isequal(expectedStruct, actualStruct)); diff --git a/tests/test_createQuestionList.m b/tests/test_createQuestionList.m index a37dd6cb..fce8587c 100644 --- a/tests/test_createQuestionList.m +++ b/tests/test_createQuestionList.m @@ -23,7 +23,6 @@ function test_createQuestionListBasic() end - function test_createQuestionListRestricted() %% set up diff --git a/tests/test_saveEventsFileInit.m b/tests/test_saveEventsFileInit.m index 9c7209a6..ff4aac42 100644 --- a/tests/test_saveEventsFileInit.m +++ b/tests/test_saveEventsFileInit.m @@ -15,25 +15,25 @@ function test_saveEventsFileInitBasic() % make sure the dependencies are there checkCFG(cfg); - [logFile] = saveEventsFile('init',cfg); + [logFile] = saveEventsFile('init', cfg); %% data to test against expectedStrcut(1).filename = ''; expectedStrcut(1).extraColumns = []; - expectedStrcut(1).isStim = false; - - expectedStrcut(1).columns.onset.Description = 'time elapsed since experiment start'; - expectedStrcut(1).columns.onset.Units = 's'; - - expectedStrcut(1).columns.trial_type.Description = 'types of trial'; - expectedStrcut(1).columns.trial_type.Levels = ''; - - expectedStrcut(1).columns.duration.Description = 'duration of the event or the block'; - expectedStrcut(1).columns.duration.Units = 's'; - + expectedStrcut(1).isStim = false; + + expectedStrcut(1).columns.onset.Description = 'time elapsed since experiment start'; + expectedStrcut(1).columns.onset.Units = 's'; + + expectedStrcut(1).columns.trial_type.Description = 'types of trial'; + expectedStrcut(1).columns.trial_type.Levels = ''; + + expectedStrcut(1).columns.duration.Description = 'duration of the event or the block'; + expectedStrcut(1).columns.duration.Units = 's'; + %% test assertTrue(isequal(expectedStrcut, logFile)); - + end function test_saveEventsFileInitExtraColumns() @@ -49,7 +49,7 @@ function test_saveEventsFileInitExtraColumns() [logFile] = saveEventsFile('init', cfg, logFile); %% data to test against - expectedStrcut = saveEventsFile('init',cfg); + expectedStrcut = saveEventsFile('init', cfg); expectedStrcut(1).extraColumns.Speed.length = 1; expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; expectedStrcut(1).extraColumns.Speed.bids.Description = ''; @@ -76,7 +76,7 @@ function test_saveEventsFileInitExtraColumnsArray() [logFile] = saveEventsFile('init', cfg, logFile); %% data to test against - expectedStrcut = saveEventsFile('init',cfg); + expectedStrcut = saveEventsFile('init', cfg); expectedStrcut(1).extraColumns.Speed.length = 1; expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; expectedStrcut(1).extraColumns.Speed.bids.Description = ''; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index 25e50805..6935ab92 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -24,7 +24,7 @@ function test_saveEventsFileOpenBasic() cfg.testingDevice = 'mri'; cfg = createFilename(cfg); - + logFile = saveEventsFile('init', cfg); % create the events file and header diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index 74bb22e4..89864533 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -26,8 +26,8 @@ function test_saveEventsFileOpenMultiColumnCheckHeader() cfg = createFilename(cfg); % define the extra columns names - logFile.extraColumns = {'Speed','LHL24','is_Fixation'}; - + logFile.extraColumns = {'Speed', 'LHL24', 'is_Fixation'}; + % initalize logfile logFile = saveEventsFile('init', cfg, logFile); From dac6de3ffd8dec3a8905e2177b338ed8bbf5833f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 16 Nov 2020 23:27:23 +0100 Subject: [PATCH 6/9] update test makeRawDataset to adapt the new behavior of saveEventFile --- manualTests/test_makeRawDataset.m | 15 ++++++++++----- src/saveEventsFile.m | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/manualTests/test_makeRawDataset.m b/manualTests/test_makeRawDataset.m index 1a0a74fe..71d7d67f 100644 --- a/manualTests/test_makeRawDataset.m +++ b/manualTests/test_makeRawDataset.m @@ -23,13 +23,17 @@ function test_makeRawDataset() cfg.task.name = 'testtask'; cfg.task.instructions = 'do this'; + + cfg.verbosity = 0; + + cfg = createFilename(cfg); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; logFile.extraColumns.is_Fixation.length = 1; - cfg = createFilename(cfg); - + logFile = saveEventsFile('init', cfg, logFile); + extraInfo = struct('extraInfo', struct('nestedExtraInfo', 'something extra')); createJson(cfg, extraInfo); @@ -72,20 +76,21 @@ function test_makeRawDataset() % add dummy stim data stimLogFile.extraColumns.Speed.length = 1; - stimLogFile.extraColumns.LHL24.length = 3; + stimLogFile.extraColumns.LHL24.length = 1; stimLogFile.extraColumns.is_Fixation.length = 1; stimLogFile.SamplingFrequency = cfg.mri.repetitionTime; stimLogFile.StartTime = 0; - stimLogFile = saveEventsFile('open_stim', cfg, stimLogFile); + stimLogFile = saveEventsFile('init_stim', cfg, stimLogFile); + stimLogFile = saveEventsFile('open', cfg, stimLogFile); for i = 1:100 stimLogFile(i, 1).onset = cfg.mri.repetitionTime * i; stimLogFile(i, 1).trial_type = 'test'; stimLogFile(i, 1).duration = 1; stimLogFile(i, 1).Speed = rand(1); stimLogFile(i, 1).is_Fixation = rand > 0.5; - stimLogFile(i, 1).LHL24 = randn(1, 3); + stimLogFile(i, 1).LHL24 = randn(); end saveEventsFile('save', cfg, stimLogFile); saveEventsFile('close', cfg, stimLogFile); diff --git a/src/saveEventsFile.m b/src/saveEventsFile.m index 39027fb7..bf4dc656 100644 --- a/src/saveEventsFile.m +++ b/src/saveEventsFile.m @@ -382,7 +382,7 @@ function printHeaderExtraColumns(logFile) isValid = ones(1, numel(namesExtraColumns)); for iExtraColumn = 1:numel(namesExtraColumns) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); - if isempty(data) || isnan(data) || (ischar(data) && strcmp(data, 'n/a')) + if isempty(data) || all(isnan(data)) || (ischar(data) && strcmp(data, 'n/a')) isValid(iExtraColumn) = 0; end end From 7bfac476c849d228d10952c619649c01a0f9312a Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 16 Nov 2020 23:44:47 +0100 Subject: [PATCH 7/9] move test createDataDictionary to manual test because of CI issue --- {tests => manualTests}/test_createDataDictionary.m | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tests => manualTests}/test_createDataDictionary.m (100%) diff --git a/tests/test_createDataDictionary.m b/manualTests/test_createDataDictionary.m similarity index 100% rename from tests/test_createDataDictionary.m rename to manualTests/test_createDataDictionary.m From 25831f23de52dd77ac83e49ac97ab242c29028f1 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 17 Nov 2020 00:07:27 +0100 Subject: [PATCH 8/9] also move createDatasetDesciption into the manual tests --- {tests => manualTests}/test_createDatasetDescription.m | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tests => manualTests}/test_createDatasetDescription.m (100%) diff --git a/tests/test_createDatasetDescription.m b/manualTests/test_createDatasetDescription.m similarity index 100% rename from tests/test_createDatasetDescription.m rename to manualTests/test_createDatasetDescription.m From 91b22609e78f41f69e0cebeda1af6f17e6996562 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 17 Nov 2020 00:08:21 +0100 Subject: [PATCH 9/9] update bids-matlab submodule --- lib/bids-matlab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bids-matlab b/lib/bids-matlab index bda01141..d0815ea7 160000 --- a/lib/bids-matlab +++ b/lib/bids-matlab @@ -1 +1 @@ -Subproject commit bda011411defe36c00d1d501b6842fd677af32fc +Subproject commit d0815ea702ea85ba9348ab2780f84564fbd5520f