Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
1990002
Initial Commit
stradaa May 18, 2023
ef46427
Initial Commit
stradaa May 18, 2023
702637b
Delete test_BIDSDatastore.m
stradaa May 18, 2023
77914f2
June Update
stradaa Jun 6, 2023
3f9e749
Delete generateFolderStructureRecursive.m
stradaa Jun 6, 2023
1a5e209
Delete tsvread.m
stradaa Jun 6, 2023
4a54855
Update Files
stradaa Jul 13, 2023
d3e6805
Update README.md
stradaa Jul 13, 2023
506bf3e
Update README.md
stradaa Jul 13, 2023
952dcfb
Delete BIDSDatastore_Usage_Example.mlx
stradaa Jul 13, 2023
224710d
Update README.md
stradaa Jul 13, 2023
1e84c3e
MATLAB Online
stradaa Jul 13, 2023
59bd6da
Update README.md
stradaa Jul 13, 2023
24e7b89
Add files via upload
stradaa Jul 13, 2023
b4bbfd1
Delete create_moprop.m
stradaa Sep 25, 2023
c5b98a1
Delete find_folders.m
stradaa Sep 25, 2023
e4763bb
Delete generateFolderStructure.m
stradaa Sep 25, 2023
817c173
Add files via upload
stradaa Sep 25, 2023
cb3ba9e
Add files via upload
stradaa Sep 25, 2023
3fba4ea
BIDSDataSet.m can read participant.tsv
likeajumprope Nov 29, 2023
028ebaf
First official version of checkinput
likeajumprope Nov 29, 2023
f772656
first stable push
likeajumprope Dec 11, 2023
21f26f1
Create README.md
likeajumprope Dec 11, 2023
4f8a635
add open in matlab online tag
likeajumprope Dec 11, 2023
d281465
add file type selector, loop over file extensions
likeajumprope Dec 11, 2023
38b6b96
Merge pull request #3 from likeajumprope/2-add-filetype-selector
likeajumprope Dec 11, 2023
00523a5
add reading function
likeajumprope Dec 12, 2023
c4bb6c4
add documentation
likeajumprope Dec 12, 2023
a4e3593
Update README.md
likeajumprope Dec 13, 2023
98829ef
Update README.md
likeajumprope Dec 13, 2023
0a39ba4
Update README.md
likeajumprope Dec 13, 2023
028b30c
Update README.md
likeajumprope Dec 13, 2023
307c999
Update README.md
likeajumprope Dec 13, 2023
331e239
Update README.md
likeajumprope Dec 13, 2023
4225fd3
Update README.md
likeajumprope Dec 13, 2023
8b55476
Update README.md
likeajumprope Dec 13, 2023
a71030c
Update README.md
likeajumprope Dec 13, 2023
944d4d1
update OpenNeuroDemo with third example
likeajumprope Dec 13, 2023
cda07da
Update authorship
likeajumprope Dec 14, 2023
9a99672
rewriting to loop over subjects
likeajumprope Jan 30, 2024
41d7acb
update gitignore
likeajumprope Apr 11, 2024
0865bd6
add mri folder specifications
likeajumprope Apr 11, 2024
2d783a2
remove MatlabDataStore as abstract class
likeajumprope Jul 7, 2024
316f1e6
remove addParticipantwiseDatasStore method and get_value
likeajumprope Jul 7, 2024
a222645
add get_keys dictionary and infer_data method
likeajumprope Jul 7, 2024
0660f2e
update
likeajumprope Aug 30, 2024
1245c21
Merge pull request #14 from likeajumprope/dev
likeajumprope Aug 30, 2024
be654a2
update after the sprint
likeajumprope Sep 14, 2024
45160ee
Merge branch 'seed' into main
tiborauer Sep 17, 2024
cb0f4e3
Push state of toolbox after stprint
likeajumprope Apr 16, 2025
e3561e4
Merge pull request #15 from likeajumprope/dev
likeajumprope Apr 16, 2025
756f9e7
push state of toolbox after sprint
likeajumprope Apr 16, 2025
9d3ae28
Merge pull request #16 from likeajumprope/dev
likeajumprope Apr 16, 2025
d51b015
Update Readme and .mlx
likeajumprope Apr 16, 2025
0492130
Merge pull request #17 from likeajumprope/dev
likeajumprope Apr 16, 2025
4af3e93
update .gitignore to contain .asv files
likeajumprope Apr 16, 2025
dbc0cb7
Merge pull request #18 from likeajumprope/dev
likeajumprope Apr 16, 2025
b74571b
Matlab online tag
likeajumprope Apr 16, 2025
3cfb8f3
first example ds001415
likeajumprope Apr 27, 2025
30a8a83
delete unnecessary files
likeajumprope Apr 27, 2025
15e8bb2
add // after openneuro.org//
likeajumprope Apr 27, 2025
91f956e
clean files Particpantwise
likeajumprope Apr 27, 2025
a055cd9
Merge pull request #19 from likeajumprope/dev
likeajumprope Apr 27, 2025
df98b73
Update README.md
likeajumprope Apr 27, 2025
e7f4991
Update README.md
likeajumprope Apr 27, 2025
a3fd505
Update documentation
likeajumprope Apr 30, 2025
b6e9950
Merge pull request #20 from likeajumprope/dev
likeajumprope Apr 30, 2025
6d7645f
adjusted .mlx file
likeajumprope May 3, 2025
481dc64
add MVP version
likeajumprope Jun 3, 2025
eda01f5
Merge pull request #21 from likeajumprope/dev
likeajumprope Jun 3, 2025
11e857a
Update Readme
likeajumprope Jun 3, 2025
4843f4a
Merge branch 'main' into dev
likeajumprope Jun 3, 2025
d3e6a21
Merge pull request #22 from likeajumprope/dev
likeajumprope Jun 3, 2025
7630f7a
Adjusted Readme
likeajumprope Jun 4, 2025
df02f65
Merge branch 'main' into openneuro-import
likeajumprope Jun 4, 2025
89bc196
Merge pull request #1 from likeajumprope/openneuro-import
likeajumprope Jun 4, 2025
d52f50e
Delete BIDS.m
likeajumprope Jun 4, 2025
b2be1fd
Delete BIDSDataStore.m
likeajumprope Jun 4, 2025
d06b0b5
Delete BIDS_Usage_Example.mlx
likeajumprope Jun 4, 2025
bc0190b
Delete OpenNeuroDemo.mlx
likeajumprope Jun 4, 2025
d3c2993
Add latest MVP version of the toobox.
likeajumprope Oct 31, 2025
26a85ab
Adding two lines to diplay information about the dataset
Oct 31, 2025
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
201 changes: 201 additions & 0 deletions +openneuro/+datastore/Participantwise.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
classdef Participantwise < matlab.io.Datastore
%PARTICIPANTWISE Summary of this class goes here
% Detailed explanation goes here

properties (Constant, Hidden)
% Dictionary mapping type names to read settings
Type = containers.Map( ...
{'Anatomical NIfTI', 'EEG EDF', 'Functional NIfTI', 'DWI', 'Fieldmap', 'JSON Files', 'TSV Files'}, ...
{struct('ReadFcn', @niftiread, 'FileExtensions', {{'.nii.gz', '.nii'}}, 'FolderPath', 'anat'), ...
struct('ReadFcn', @edfread, 'FileExtensions', {{'.edf'}}, 'FolderPath', 'eeg'), ...
struct('ReadFcn', @niftiread, 'FileExtensions', {{'.nii.gz', '.nii'}}, 'FolderPath', 'func'), ...
struct('ReadFcn', @niftiread, 'FileExtensions', {{'.nii.gz', '.nii'}}, 'FolderPath', 'dwi'), ...
struct('ReadFcn', @niftiread, 'FileExtensions', {{'.nii.gz', '.nii'}}, 'FolderPath', 'fmap'), ...
struct('ReadFcn', @(f) jsondecode(fileread(f)), 'FileExtensions', {{'.json'}}, 'FolderPath', 'anat'), ...
struct('ReadFcn', @readtable, 'FileExtensions', {{'.tsv', '.txt'}}, 'FolderPath', 'anat') ...
} ...
)
end

properties (Dependent)
AvailableTypes % List of supported type keys
end

properties
fileDatastoreObj % Public fileDatastore object for MVP mode
end

properties (Access = private)
CurrentFileIndex double;
FileSet matlab.io.datastore.DsFileSet;
isMVPMode logical = false; % Track which mode we're in
end

methods
function keys = get.AvailableTypes(obj)
% List available types from the Type dictionary
keys = obj.Type.keys;
end

function obj = Participantwise(dataset,spec)
% Constructor supporting both MVP mode and original mode
%
% MVP Mode (dictionary-based spec):
% obj = Participantwise("Anatomical NIfTI")
%
% Original Mode (structure-based spec):
% obj = Participantwise(dataset, filesetSpec)

if isStringScalar(spec) || (ischar(spec) && isvector(spec))
% MVP MODE: dictionary-based spec
%typeName = varargin{1};

% Validate type name against the Type dictionary using keys() method
if ~isKey(obj.Type, spec)
error('Invalid type specified. Available types are: %s', strjoin(obj.AvailableTypes, ', '));
end

obj.isMVPMode = true;
obj = createMVPDatastore(obj, dataset, spec);

else %if nargin == 2
% ORIGINAL MODE: structure-based spec
%dataset = varargin{1};
filesetSpec = spec; %varargin{2};

% Validate arguments (original validation)
if ~isa(dataset, 'openneuro.Dataset')
error('First argument must be an openneuro.Dataset object');
end
if ~isstruct(filesetSpec)
error('Second argument must be a struct');
end

obj.isMVPMode = false;
obj = createOriginalDatastore(obj, dataset, filesetSpec);

% else
% error('Constructor requires either 1 argument (MVP mode) or 2 arguments (original mode). Got %d arguments.', nargin);
end
end

function reset(obj)
% Reset to the start of the data.
if obj.isMVPMode && ~isempty(obj.fileDatastoreObj)
reset(obj.fileDatastoreObj);
else
reset(obj.FileSet);
end
obj.CurrentFileIndex = 1;
end

function tf = hasdata(obj)
% Return true if more data is available.
if obj.isMVPMode && ~isempty(obj.fileDatastoreObj)
tf = hasdata(obj.fileDatastoreObj);
else
tf = hasfile(obj.FileSet);
end
end

function [data, info] = read(obj)
% MVP read method - no arguments, dispatches appropriately
if obj.isMVPMode && ~isempty(obj.fileDatastoreObj)
% MVP mode: dispatch to fileDatastore.read()
[data, info] = read(obj.fileDatastoreObj);
else
% Original mode: use FileSet reading
if ~hasdata(obj)
error(sprintf(['No more data to read.\nUse the reset ',...
'method to reset the datastore to the start of ' ,...
'the data. \nBefore calling the read method, ',...
'check if data is available to read ',...
'by using the hasdata method.']))
end

fileInfoTbl = nextfile(obj.FileSet);
data = MyFileReader(fileInfoTbl);
info.Size = size(data);
info.FileName = fileInfoTbl.FileName;
info.Offset = fileInfoTbl.Offset;

% Update CurrentFileIndex for tracking progress
if fileInfoTbl.Offset + fileInfoTbl.SplitSize >= ...
fileInfoTbl.FileSize
obj.CurrentFileIndex = obj.CurrentFileIndex + 1;
end
end
end
end

methods (Access = private)
function obj = createMVPDatastore(obj, dataset, typeName)
% Create MVP mode datastore using Type dictionary

% Get the specification for this type
spec = obj.Type(typeName);

% Construct fileDatastore object using the Type specification
%defaultPath = fullfile(pwd, "ds001415/");
%searchPath = fullfile(defaultPath, 'sub-01', spec.FolderPath);
searchPath = fullfile(dataset.URI,dataset.ParticipantIDs(1), spec.FolderPath);

try
obj.fileDatastoreObj = fileDatastore( ...
searchPath, ...
'ReadFcn', spec.ReadFcn, ...
'IncludeSubfolders', true, ...
'FileExtensions', spec.FileExtensions ...
);
catch e
warning('Failed to create MVP datastore:\n%s', getReport(e));
% Create empty datastore as fallback
obj.fileDatastoreObj = fileDatastore(pwd, 'ReadFcn', @readtable);
obj.fileDatastoreObj.Files = {};
end
end

function obj = createOriginalDatastore(obj, dataset, filesetSpec)
% Create original mode datastore (unchanged logic)

obj.FileSet = matlab.io.datastore.DsFileSet(computeLocations(dataset,filesetSpec),'FileExtensions',filesetSpec.extensionList);
obj.CurrentFileIndex = 1;
reset(obj);
end
end

methods (Access=protected)

end
end

%% LOCAL FUNCTIONS
function data = MyFileReader(fileInfoTbl)
% create a reader object using the FileName
reader = matlab.io.datastore.DsFileReader(fileInfoTbl.FileName);

% seek to the offset
seek(reader,fileInfoTbl.Offset,'Origin','start-of-file');

% read fileInfoTbl.SplitSize amount of data
data = read(reader,fileInfoTbl.SplitSize);
end


function locations = computeLocations(dataset,filesetSpec)

fs = filesetSpec;
if all(cellfun(@isempty,{fs.sessions,fs.tasks,fs.runs},'UniformOutput',true)) % Maybe sessions is enough? Trigger an error if tasks/runs w/o sessions?
% "Core modality" special case
assert(isscalar(fs.extendedModality));
assert(isa(dataset,'openneuro.Dataset'));
locations = dataset.RootURI + "/" + string(dataset.ID) + "/" + dataset.ParticipantIDs + "/" + fs.extendedModality;

else % General case (TODO; may encompass core modality special case, i.e., removing need for IF/ELSE)
%TODO
end

%
% dir(b.encoding.dir + "/" + subjects{1} + "/" + sessions{1} + "/" +folders{1} + "/*" );

end
Loading