Skip to content

Commit

Permalink
automatic management of BIDSAlign dependency list
Browse files Browse the repository at this point in the history
  • Loading branch information
fedepup committed Jul 15, 2024
1 parent 6391584 commit 101f0f1
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 47 deletions.
51 changes: 40 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,21 @@ You have to create a folder where you will store all the datasets present in the

Please remember that the name of the folder where the dataset is stored must corresponds to the value in column *dataset_code*.

The library already comes with all the information needed for processing 20 public datasets. Some of them are large and commonly used in deep learning such as the Healthy Brain Network [HBN EO/EC](https://openneuro.org/datasets/ds004186/versions/2.0.0), the Two Decades–Brainclinics Research Archive for Insights in Neurophysiology [TDBRAIN](https://brainclinics.com/resources/) and the Max Planck Institute LEMON dataset [MPI-LEMON](https://fcon_1000.projects.nitrc.org/indi/retro/MPI_LEMON.html).
The library already comes with all the information needed for processing 20 public datasets.
Some of them are large and commonly used in deep learning such as the Healthy Brain Network
[HBN EO/EC](https://openneuro.org/datasets/ds004186/versions/2.0.0),
the Two Decades–Brainclinics Research Archive for Insights in Neurophysiology
[TDBRAIN](https://brainclinics.com/resources/)
and the Max Planck Institute LEMON dataset
[MPI-LEMON](https://fcon_1000.projects.nitrc.org/indi/retro/MPI_LEMON.html).

### BIDS Format
This library can preprocess datasets structured with both BIDS and non-BIDS format, thus is expected in input a dataset structured as shown in [BIDS-EEG](https://bids-specification.readthedocs.io/en/stable/modality-specific-files/electroencephalography.html).
However you can use the function *create_dataset_architecture.m* to change in-place the folder structure of the dataset.
As specified by the BIDS format, the *participants.tsv* file is recommended and should be stored inside the dataset folder.
This library can preprocess datasets structured with both BIDS and non-BIDS format,
thus is expected in input a dataset structured as shown in
[BIDS-EEG](https://bids-specification.readthedocs.io/en/stable/modality-specific-files/electroencephalography.html).
However you can use the function *create_dataset_architecture.m* to change in-place
the folder structure of the dataset. As specified by the BIDS format,
the *participants.tsv* file is recommended and should be stored inside the dataset folder.

Here an example of how the folder structure and the workflow can be organized.

Expand All @@ -52,15 +61,20 @@ Many times the channel location is absent or even wrong when downloading public
## Usage Modalities
You can use the library in three ways:
1. Preprocess a specified file.
You have to specify the dataset name, from which the file is taken, the filename and the corresponding filepath. The modality is activated with the variable *single_file*.
You have to specify the dataset name, from which the file is taken,
the filename and the corresponding filepath. The modality is activated with
the variable *single_file*.

```
single_file = true;
dataset_name = ['UC_SD'];
raw_filename = ['sub-hc10_ses-hc_task-rest_eeg.bdf'];
raw_filepath = ['/Users/.../Datasets/ds002778/sub-hc10/ses-hc/eeg/'];
```
2. Preprocess an entire dataset.
You have to specify the dataset. In this case you can process the entire dataset, a portion, only some subjects or some sessions, or even preprocess specific groups and/or specific task.
You have to specify the dataset. In this case you can process the entire dataset,
a portion, only some subjects or some sessions, or even preprocess specific groups
and/or specific task.
```
single_file = false;
dataset_name = ['UC_SD'];
Expand All @@ -81,21 +95,29 @@ The following preprocessing steps are currently available in BIDSAlign:
5. Filtering.
6. Independent Component Analysis (ICA) and Automatic IC rejection with MARA or ICLabel.
7. Notch-Filtering.
8. Artifact Subspace Reconstruction (ASR) can be used independently in two ways: for removing bad channels and/or for removing/reconstructing bad time windows.
8. Artifact Subspace Reconstruction (ASR) can be used independently in two ways:
for removing bad channels and/or for removing/reconstructing bad time windows.
9. Interpolation of previously removed bad channels.
10. Rereference.

Please note that EEG data are assumed to be saved in $\mu V$.

## Saving and Visualisation
BIDSAlign allows you to do a proper visualisation of the data and perform statistical analysis.
In order to use the visualisation functions, please save the .set or the .mat folders by specifing save_info.set_label as *group* _ *pipeline*; for example group could be 'A' indicating Alzheimer's and pipeline could be 'ICA' indicating that you have performed Independent Component Analysis, thus *A_ICA*.
In order to use the visualisation functions, please save the .set or the .mat folders
by specifing save_info.set_label as *group* _ *pipeline*; for example group could be
'A' indicating Alzheimer's and pipeline could be 'ICA' indicating that you have
performed Independent Component Analysis, thus *A_ICA*.


The library comes with three functions:
1. groups_visualization: you can compare more groups for a single pipeline, or viceversa; you can also specify the single filename to be visualised.
2. ERP_visualization: you can plot the average and grand-average ERP for a group of patients, for multiple events. If there is only one event, scalp topographies of channels activation in time are also shown.
3. template_comparison: you can see the differences between the topographies obtained from two channel location and the effects of the conversion file.
1. groups_visualization: you can compare more groups for a single pipeline,
or viceversa; you can also specify the single filename to be visualised.
2. ERP_visualization: you can plot the average and grand-average ERP for a group of
patients, for multiple events. If there is only one event, scalp topographies of
channels activation in time are also shown.
3. template_comparison: you can see the differences between the topographies obtained
from two channel location and the effects of the conversion file.

## Compatibility
The library was written in MATLAB 2023b, EEGLAB 2023.0 and requires the following plug-in:
Expand All @@ -110,6 +132,13 @@ The library was written in MATLAB 2023b, EEGLAB 2023.0 and requires the followin
- "firfilt" v2.7.1
- "eegstats" v1.2

BIDSAlign can automatically install all these plugins if not already included in your
EEGLAB installation.
(The dependecy list is checked when **bidsaling** or **bidsalign nogui** is called.)
You can also run a fresh installation of EEGLAB and all the required plugins by running
the ``install_eeglab_from_scratch( 'target_path' )`` function. It is suggested
to use as target_path the 'MATLAB' directory or one of its subdirectories.

Moreover interally it uses two libraries:
- For the non-parametric permutation t-test [hfASDmodules: Reorganization of functionally connected subnetworks in autism](https://zenodo.org/records/44657).
- For the iaf calculation: [restingIAF](https://zenodo.org/records/2575868)
Expand Down
94 changes: 58 additions & 36 deletions __lib/search_eeglab_path.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,21 @@
return
catch
if verbose
disp(['eeglab not present in your current search path.' ...
' Trying to add it automatically'])
disp(['eeglab not present in your current search path. ' ...
newline 'Trying to add it automatically'])
end
end
else
if isequal(exist('eeglab','file'),2)
if verbose
disp(['It seems that an eeglab.m file can be accessed'...
'from your current search path. Returning'])
end
return
else
if verbose
disp(['eeglab not present in your current search path.' ...
'Trying to add it automatically'])
newline 'Trying to add it automatically'])
end
end
end
Expand Down Expand Up @@ -101,8 +105,8 @@
if not(isempty(ith_path))
if verbose
disp('Found eeglab path in MATLAB toolbox folder')
disp(folder_names{i})
disp('adding it to the current path list')
disp(['Folder name: ' folder_names{i}])
disp('Adding folder to the current path list')
end
addpath(folder_names{i})
addedpath = true;
Expand All @@ -124,7 +128,10 @@
else
if isequal(exist('eeglab','file'),2)
if verbose
disp('Found path to EEGLab')
disp( ...
['added path to an eeglab folder with an eeglab.m file' ...
'form your list of available toolboxes']...
)
end
return
else
Expand All @@ -136,45 +143,60 @@
end


%try searching in your current path and subpaths
d = dir('**');
% try searching in your current path and subpaths
% or, if possible, in all subdirectories inside the MATLAB folder.
% In other words, if you are in a subdirectory of MATLAB, dir
% search will be extended
current_path = pwd;
mat_idx = strfind(current_path, 'MATLAB');
if mat_idx
d = dir([current_path(1:mat_idx+5) filesep '**' filesep 'eeglab*']);
else
d = dir('**');
end
dfolders = d([d(:).isdir]);
dfolders = dfolders(~ismember({dfolders(:).name},{'.','..'}));
folder_names = {dfolders.name};
folder_paths = {dfolders.folder};
for i=1:length(folder_names)
ith_path = strfind(folder_names{i},'eeglab');
if not(isempty(ith_path))
if verbose
disp('Found a folder with eeglab in its name in the MATLAB path list')
disp(folder_names{i})
disp('Adding it to the current path list')
end
addpath(folder_names{i})
addedpath = true;
if forcestart
try
if nogui_launch
[~] = evalc('eeglab nogui;');
else
[~] = evalc('eeglab; close;');
end
if verbose
disp('Found path to EEGLab')
end
return
catch
totPath = totPath + 1;
pathAddedList{totPath} = folder_names{i};
if exist([folder_paths{i} filesep folder_names{i} filesep 'eeglab.m'], 'file')
if verbose
disp('Found a folder eeglab in its name and an eeglab.m file in it.')
disp(folder_names{i})
disp('Adding it to the path list for the current MATLAB session')
end
else
if isequal(exist('eeglab','file'),2)
if verbose
disp('Found path to EEGLab')
addpath(folder_names{i})
addedpath = true;
if forcestart
try
if nogui_launch
[~] = evalc('eeglab nogui;');
else
[~] = evalc('eeglab; close;');
end
if verbose
disp('Found path to EEGLab. Search completed')
end
return
catch
totPath = totPath + 1;
pathAddedList{totPath} = folder_names{i};
end
return
else
totPath = totPath + 1;
pathAddedList{totPath} = folder_names{i};
if isequal(exist('eeglab','file'), 2)
if verbose
disp( ...
['An eeglab.m file placed inside an eeglab folder ' ...
'is now in your current search path.'] ...
)
end
return
else
totPath = totPath + 1;
pathAddedList{totPath} = folder_names{i};
end
end
end
end
Expand Down
77 changes: 77 additions & 0 deletions bidsalign.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,92 @@ function bidsalign( guistatus )
disp('Added Path to BIDSAlign function')
end

try
disp('Searching for an existing eeglab path or one to add')
search_eeglab_path(true, false, false)
eeglab nogui
disp('Checking all the dependencies')
plugin_dependency = { ...
'clean_rawdata', ...
'ICLabel', ...
'Biosig', ...
'Fileio', ...
'MARA', ...
'eegstats', ...
'bva-io', ...
'dipfit', ...
'firfilt' ...
'FastICA', ...
};
is_plugin_installed = false(1, length(plugin_dependency));
for i=1:length(plugin_dependency)
if plugin_status(plugin_dependency{i})
is_plugin_installed(i) = true;
end
end
plugin_to_install = plugin_dependency(not(is_plugin_installed));
if ~isempty(plugin_to_install)
disp(['The following EEGLAB plugins are needed by BIDSAlign'...
' but are not installed.' newline])
for i=1:length(plugin_to_install)
disp([num2str(i) '- ' plugin_to_install{i}])
end
disp([newline 'Installing them one by one (this may take some time)'])
for i=1:length(plugin_to_install)
if strcmp(plugin_to_install{i}, 'FastICA')
eeglab_plugin_path = fullfile(fileparts(which('eeglab.m')), 'plugins');
websave([eeglab_plugin_path filesep 'fastica.zip'], ...
'http://research.ics.aalto.fi/ica/fastica/code/FastICA_2.5.zip');
unzip([eeglab_plugin_path filesep 'fastica.zip'], ...
[eeglab_plugin_path filesep])
delete([eeglab_plugin_path filesep 'fastica.zip'])
else
[~] = evalc('plugin_askinstall(plugin_to_install{i}, [], true);');
end
close all
disp(['Installed ' plugin_to_install{i} ' plugin'] )
end
disp([newline 'All the plugins installed successfully. Restarting eeglab'])
eeglab nogui
end
disp([ ...
newline ...
'EEGLAB with all the plugins are included in the current MATLAB search path' ...
newline
])

catch
disp( ...
"Unable to found any eeglab installation." + newline + ...
"Please download it or add its path manually by running the command" + ...
"addpath('/path/to/eeglab')." + newline + ...
"Make sure to also install all the required plugins:" +...
"1- Biosig (v3.8.3+)" + newline +...
"2- FastICA (link: http://research.ics.aalto.fi/ica/fastica/)" + newline + ...
"3- Fileio (v20240111+)" + newline + ...
"4- ICLabel (v1.4+)" + newline + ...
"5- MARA (v1.2+)" + newline + ...
"6- bva-io (v1.73+)" + newline + ...
"7- clean_rawdata (v2.91+)" + newline + ...
"8- dipfit (v5.3+)" + newline + ...
"9- firfilt (v2.7.1+)" + newline + ...
"10- eegstats (v1.2+)" + newline ...
)
disp(newline + "You can also launch a fresh installation with the function" + ...
"'install_eeglab_from_scratch(target_path)'")
end

switch nargin
case 0
BIDSAlign_GUI
case 1
if strcmpi(guistatus, 'nogui')
disp(newline)
disp('---------------------------------------------------------')
disp(' BIDSAlign functions can be excecuted without problems.')
disp(' To open the GUI, simply run bidsalign.')
disp('---------------------------------------------------------')
disp(newline)
end
end

Expand Down
Loading

0 comments on commit 101f0f1

Please sign in to comment.