Skip to content

Commit e2fcb04

Browse files
Merging code from Taylor's fork (lina-usc#198)
* Update readme * Integrating Taylor's changes for HPC * Adjusting the flags. * Fix test for changed flag names.
1 parent d563f98 commit e2fcb04

File tree

10 files changed

+34
-168
lines changed

10 files changed

+34
-168
lines changed

README.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,31 +37,37 @@ Please find the full documentation at
3737

3838
## ▶️ Running the pyLossless Pipeline
3939
Below is a minimal example that runs the pipeline one of MNE's sample files.
40-
```
40+
```python
4141
import pylossless as ll
4242
import mne
4343
fname = mne.datasets.sample.data_path() / 'MEG' / 'sample' / 'sample_audvis_raw.fif'
4444
raw = mne.io.read_raw_fif(fname, preload=True)
4545

4646
config = ll.config.Config()
4747
config.load_default()
48-
config.save("my_project_ll_config.yaml")
4948

50-
pipeline = ll.LosslessPipeline('my_project_ll_config.yaml')
49+
pipeline = ll.LosslessPipeline(config=config)
5150
pipeline.run_with_raw(raw)
5251
```
5352

5453
Once it is completed, You can see what channels and times were flagged:
55-
```
54+
```python
5655
print(pipeline.flagged_chs)
5756
print(pipeline.flagged_epochs)
5857
```
5958

60-
Once you are ready, you can save your file:
61-
```
59+
Once you are ready, you can save your file in its lossless state:
60+
```python
6261
pipeline.save(pipeline.get_derivative_path(bids_path), overwrite=True)
6362
```
6463

64+
To get a **cleaned** version, you can use a `RejectionPolicy` object to apply
65+
these annotations to your raw object. This is a lossy operation:
66+
```python
67+
rejection_policy = ll.RejectionPolicy()
68+
cleaned_raw = rejection_policy.apply(pipeline)
69+
```
70+
6571
## 👩‍💻 Dashboard Review
6672
[![Open in Colab](https://camo.githubusercontent.com/84f0493939e0c4de4e6dbe113251b4bfb5353e57134ffd9fcab6b8714514d4d1/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667)](https://colab.research.google.com/github/lina-usc/pylossless/blob/main/notebooks/qc_example.ipynb)
6773

@@ -90,6 +96,7 @@ If you are a Canadian researcher working on an HPC system such as [Narval](https
9096
module load python/3.10
9197

9298
# Build the virtualenv in your homedir
99+
cd ~
93100
virtualenv --no-download eeg-env
94101
source eeg-env/bin/activate
95102

@@ -99,17 +106,12 @@ pip install --no-index xarray
99106
pip install --no-index pyyaml
100107
pip install --no-index sklearn
101108
pip install mne_bids
109+
pip install edfio
110+
pip install openneuro-py
102111

103-
# Clone down mne-iclabel and switch to the right version and install it locally
104-
git clone https://github.com/mne-tools/mne-icalabel.git
105-
cd mne-icalabel
106-
git checkout maint/0.4
107-
pip install .
112+
pip install mne-icalabel
108113

109-
# Clone down pipeline and install without reading dependencies
110-
git clone [email protected]:lina-usc/pylossless.git
111-
cd pylossless
112-
pip install --no-deps .
114+
pip install --no-deps pylossless
113115

114116
# Verify that the package has installed correct with an import
115117
python -c 'import pylossless'

pylossless/assets/ll_default_config_adults.yaml

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,6 @@ project:
2424
EEGCoordinateSystem: Other
2525
EEGCoordinateUnits: metres
2626

27-
general_info:
28-
authors: [Unspecified]
29-
institution_Name: Unspecified
30-
institution_address: Unspecified
31-
dataset_doi: []
32-
funding: Unspecified
33-
how_to_acknowledge: tba
34-
license: ""
35-
name: Unspecified
36-
references_and_links: []
37-
38-
t_info:
39-
EEG_placement_scheme: EGI 129
40-
cap_manufacturer: EGI
41-
cap_manufacturers_model_name: Hydrocel 129 Channel
42-
hardware_filters: n/a
43-
manufacturer: Electrical Geodesics
44-
manufacturers_model_name: NetAmps300
45-
power_line_frequency: 60
46-
software_filters: n/a
47-
software_versions: NetStation V4.5
48-
4927
######################## Task break detection ########################
5028
# See arguments definition from mne.preprocessing.annotate_breaks
5129
find_breaks:
@@ -69,19 +47,6 @@ filtering:
6947
notch_filter_args:
7048
freqs: [60]
7149

72-
############################## SLURM #################################
73-
# Options for running the pipeline on a cluster
74-
# through SLURM
75-
slurm_options:
76-
account: def-emayada
77-
job_name: pylossless
78-
memory: 16g
79-
mpi: false
80-
num_tasks: 1
81-
program_options: []
82-
threads_per_task: []
83-
time_limit: 2h
84-
8550
########################## Nearest neighbor ##########################
8651
nearest_neighbors:
8752
n_nbr_ch: 3

pylossless/assets/ll_default_config_infants.yaml

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,6 @@ project:
2424
EEGCoordinateSystem: Other
2525
EEGCoordinateUnits: metres
2626

27-
general_info:
28-
authors: [Unspecified]
29-
institution_Name: Unspecified
30-
institution_address: Unspecified
31-
dataset_doi: []
32-
funding: Unspecified
33-
how_to_acknowledge: tba
34-
license: ""
35-
name: Unspecified
36-
references_and_links: []
37-
38-
t_info:
39-
EEG_placement_scheme: EGI 129
40-
cap_manufacturer: EGI
41-
cap_manufacturers_model_name: Hydrocel 129 Channel
42-
hardware_filters: n/a
43-
manufacturer: Electrical Geodesics
44-
manufacturers_model_name: NetAmps300
45-
power_line_frequency: 60
46-
software_filters: n/a
47-
software_versions: NetStation V4.5
48-
4927
######################## Task break detection ########################
5028
# See arguments definition from mne.preprocessing.annotate_breaks
5129
find_breaks:
@@ -69,19 +47,6 @@ filtering:
6947
notch_filter_args:
7048
freqs: []
7149

72-
############################## SLURM #################################
73-
# Options for running the pipeline on a cluster
74-
# through SLURM
75-
slurm_options:
76-
account: def-emayada
77-
job_name: pylossless
78-
memory: 16g
79-
mpi: false
80-
num_tasks: 1
81-
program_options: []
82-
threads_per_task: []
83-
time_limit: 2h
84-
8550
########################## Nearest neighbor ##########################
8651
nearest_neighbors:
8752
n_nbr_ch: 3

pylossless/assets/test_data/sub-s01/eeg/sub-s01_task-faceO_ll_config.yaml

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,38 +92,8 @@ project:
9292
coordsys:
9393
EEGCoordinateSystem: Other
9494
EEGCoordinateUnits: metres
95-
general_info:
96-
authors:
97-
- Q1K Neuroimaging group
98-
dataset_doi: []
99-
funding: Azrieli Foundationt
100-
how_to_acknowledge: tba
101-
institution_Name: McGill University
102-
institution_address: 3775 Rue University, Montreal, QC
103-
license: ''
104-
name: Q1K Mismatched Negativity
105-
references_and_links: []
10695
readme: '# Q1K ACAR Dataset'
10796
set_montage_kwargs: {}
108-
t_info:
109-
EEG_placement_scheme: EGI 129
110-
cap_manufacturer: EGI
111-
cap_manufacturers_model_name: Hydrocel 129 Channel
112-
hardware_filters: n/a
113-
manufacturer: Electrical Geodesics
114-
manufacturers_model_name: NetAmps300
115-
power_line_frequency: 60
116-
software_filters: n/a
117-
software_versions: NetStation V4.5
11897
ref_loc_file: derivatives/EEG-IP-L/code/misc/standard_1020_ll_ref19.elc
11998
save_f_res: 1
120-
sd_t_pad: 1
121-
slurm_options:
122-
account: def-emayada
123-
job_name: pylossless
124-
memory: 16g
125-
mpi: false
126-
num_tasks: 1
127-
program_options: []
128-
threads_per_task: []
129-
time_limit: 2h
99+
sd_t_pad: 1

pylossless/assets/test_data/sub-s02/eeg/sub-s02_task-faceO_ll_config.yaml

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -92,38 +92,8 @@ project:
9292
coordsys:
9393
EEGCoordinateSystem: Other
9494
EEGCoordinateUnits: metres
95-
general_info:
96-
authors:
97-
- Q1K Neuroimaging group
98-
dataset_doi: []
99-
funding: Azrieli Foundationt
100-
how_to_acknowledge: tba
101-
institution_Name: McGill University
102-
institution_address: 3775 Rue University, Montreal, QC
103-
license: ''
104-
name: Q1K Mismatched Negativity
105-
references_and_links: []
10695
readme: '# Q1K ACAR Dataset'
10796
set_montage_kwargs: {}
108-
t_info:
109-
EEG_placement_scheme: EGI 129
110-
cap_manufacturer: EGI
111-
cap_manufacturers_model_name: Hydrocel 129 Channel
112-
hardware_filters: n/a
113-
manufacturer: Electrical Geodesics
114-
manufacturers_model_name: NetAmps300
115-
power_line_frequency: 60
116-
software_filters: n/a
117-
software_versions: NetStation V4.5
11897
ref_loc_file: derivatives/EEG-IP-L/code/misc/standard_1020_ll_ref19.elc
11998
save_f_res: 1
12099
sd_t_pad: 1
121-
slurm_options:
122-
account: def-emayada
123-
job_name: pylossless
124-
memory: 16g
125-
mpi: false
126-
num_tasks: 1
127-
program_options: []
128-
threads_per_task: []
129-
time_limit: 2h

pylossless/flagging.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,29 @@
1818
from .utils._utils import _icalabel_to_data_frame
1919

2020
IC_LABELS = mne_icalabel.config.ICA_LABELS_TO_MNE
21-
CH_LABELS: dict[str, str] = {
22-
"Noisy": "ch_sd",
23-
"Bridged": "bridge",
24-
"Uncorrelated": "low_r",
25-
"Rank": "rank"
26-
}
27-
EPOCH_LABELS: dict[str, str] = {
28-
"Noisy": "noisy",
29-
"Noisy ICs": "noisy_ICs",
30-
"Uncorrelated": "uncorrelated",
31-
}
21+
CH_LABELS: list = ["noisy", "bridged", "uncorrelated", "rank"]
22+
EPOCH_LABELS: list = ["noisy", "noisy_ICs", "uncorrelated"]
3223

3324

3425
class _Flagged(dict):
3526

36-
def __init__(self, key_map, kind_str, ll, *args, **kwargs):
27+
def __init__(self, keys, kind_str, ll, *args, **kwargs):
3728
"""Initialize class."""
3829
super().__init__(*args, **kwargs)
3930
self.ll = ll
40-
self._key_map = key_map
31+
self._keys = keys
4132
self._kind_str = kind_str
4233

4334
@property
4435
def valid_keys(self):
4536
"""Return the valid keys."""
46-
return tuple(self._key_map.values())
37+
return tuple(self._keys)
4738

4839
def __repr__(self):
4940
"""Return a string representation."""
5041
ret_str = f"Flagged {self._kind_str}s: |\n"
51-
for key, val in self._key_map.items():
52-
ret_str += f" {key}: {self.get(val, None)}\n"
42+
for key in self._keys:
43+
ret_str += f" {key.title().replace('_', ' ')}: {self.get(key, None)}\n"
5344
return ret_str
5445

5546
def __eq__(self, other):
@@ -102,8 +93,7 @@ def add_flag_cat(self, kind, bad_ch_names, *args):
10293
Parameters
10394
----------
10495
kind : str
105-
Should be one of ``'ch_sd'``, ``'low_r'``,
106-
``'bridge'``, ``'rank'``.
96+
Should be one of the values in ``CH_LABELS``.
10797
bad_ch_names : list | tuple
10898
Channel names. Will be the values corresponding to the ``kind``
10999
dictionary key.
@@ -220,7 +210,7 @@ def add_flag_cat(self, kind, bad_epoch_inds, epochs):
220210
Parameters
221211
----------
222212
kind : str
223-
Should be one of ``'noisy'``, ``'uncorrelated'``, ``'noisy_ICs'``.
213+
Should be one of the values in ``EPOCH_LABELS``.
224214
bad_epochs_inds : list | tuple
225215
Indices for the epochs in an :class:`mne.Epochs` object. Will be
226216
the values for the ``kind`` dictionary key.

pylossless/pipeline.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ def _repr_html_(self):
509509
"Noisy": ch_flags.get("noisy", None),
510510
"Bridged": ch_flags.get("bridged", None),
511511
"Uncorrelated": ch_flags.get("uncorrelated", None),
512+
"Rank": ch_flags.get("rank", None),
512513
}
513514
html += _create_html_details("Flagged Channels", flagged_channels_data)
514515

pylossless/tests/test_pipeline.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ def test_load_flags(pipeline_fixture, tmp_path):
121121
pipeline = ll.LosslessPipeline().load_ll_derivative(bids_path)
122122

123123
assert pipeline_fixture.flags['ch'] == pipeline.flags['ch']
124-
pipeline.flags['ch']["bridge"] = ["xx"]
124+
pipeline.flags['ch']["bridged"] = ["xx"]
125125
assert pipeline_fixture.flags['ch'] != pipeline.flags['ch']
126126

127127
assert pipeline_fixture.flags['epoch'] == pipeline.flags['epoch']
128-
pipeline.flags['epoch']["bridge"] = ["noisy"]
128+
pipeline.flags['epoch']["bridged"] = ["noisy"]
129129
assert pipeline_fixture.flags['epoch'] == pipeline.flags['epoch']

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ mne_bids>=0.14
44
pandas
55
xarray
66
scipy>=1.7.1
7-
mne_icalabel>=0.5.0
7+
mne_icalabel>=0.6.0
88
pyyaml
99
scikit-learn
10+
torch
11+
edfio

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@
4343
extras_require=extras_require,
4444
include_package_data=True,
4545
entry_points={"console_scripts": qc_entry_point},
46+
dependency_links=['https://download.pytorch.org/whl/cpu'],
4647
)

0 commit comments

Comments
 (0)