GithubHelp home page GithubHelp logo

mne-tools / mne-icalabel Goto Github PK

View Code? Open in Web Editor NEW
84.0 84.0 14.0 179.07 MB

Automatic labeling of ICA components in Python.

Home Page: https://mne.tools/mne-icalabel/dev/index.html

License: BSD 3-Clause "New" or "Revised" License

Makefile 1.43% Python 93.83% TeX 4.74%
eeg ica neuroscience python

mne-icalabel's People

Contributors

adam2392 avatar anandsaini024 avatar dependabot[bot] avatar github-actions[bot] avatar jacobf18 avatar mscheltienne avatar pre-commit-ci[bot] avatar tomdonoghue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mne-icalabel's Issues

reshape from epochs data shape

Describe the bug

I want to use iclabel on mne.epochs but get an error message regarding the shape (it somehow neglects the channel dimension):

Steps to reproduce

epochss[0].shape
epochss[0].get_data().shape
(719, 64, 751)

ic_labels = label_components(epochss[counter], icas[counter], method="iclabel")

Error msg:

:1: RuntimeWarning: The provided Epochs instance is not filtered between 1 and 100 Hz. ICLabel was designed to classify features extracted from an EEG dataset bandpass filtered between 1 and 100 Hz (see the 'filter()' method for Raw and Epochs instances).
ic_labels = label_components(epochss[counter], icas[counter], method="iclabel")
C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\utils.py:131: RuntimeWarning: divide by zero encountered in log
g = np.square(d) * (np.log(d) - 1) # % Green's function.
C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\utils.py:131: RuntimeWarning: invalid value encountered in multiply
g = np.square(d) * (np.log(d) - 1) # % Green's function.
Traceback (most recent call last):
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\IPython\core\interactiveshell.py", line 3361, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "", line 1, in <cell line: 1>
ic_labels = label_components(epochss[counter], icas[counter], method="iclabel")
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\label_components.py", line 56, in label_components
labels_pred_proba = methods[method](inst, ica)
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\label_components.py", line 45, in iclabel_label_components
features = get_iclabel_features(inst, ica)
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\features.py", line 69, in get_iclabel_features
psd = _eeg_rpsd(inst, ica, icaact)
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\features.py", line 233, in _eeg_rpsd
psd = _eeg_rpsd_compute_psdmed(inst, icaact, *constants)
File "C:\Users\Carina\Documents\expecon_EEG_analysis\venv\lib\site-packages\mne_icalabel\iclabel\features.py", line 305, in _eeg_rpsd_compute_psdmed
temp = temp.reshape(index.shape[0], len(inst), order="F")
ValueError: cannot reshape array of size 898750 into shape (250,719)

ONNX/Tensorflow Port

I just wanted to inform everybody that I was working on porting the PyTorch code to work with other deep-learning frameworks. I am doing this because PyTorch doesn't work well with other python packages for bundling into standalone programs. Also, PyTorch is large compared to other packages like ONNX when all we are doing is inference. The changes are minor and restricted to the network.py file.

We could make it an option for which framework to use if people have trouble installing PyTorch or want to run this package on a system that cannot run PyTorch.

[GUI] Additional PyQt5 dependency?

Describe the bug

Invoking the GUI after an installation of mne-icalabel[gui] via pip on a Windows 11 and Debian bookworm machine in a fresh Python 3.9 environment fails with an

ImportError: Failed to import any qt binding

Installing PyQt5 resolves the error.

Steps to reproduce

On both machines, I performed the following installations:

pip install ipython
pip install mne-icalabel
pip install sklearn
pip install mne-icalabel[gui]

and then followed the tutorial exactly. Here is the outcome

click to expand Windows CMD
C:\Users\adina\repos>pip install mne-icalabel[gui]
Requirement already satisfied: mne-icalabel[gui] in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (0.3.1)
Requirement already satisfied: pooch in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (1.6.0)
Requirement already satisfied: torch in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (1.12.1)
Requirement already satisfied: mne>=1.1 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (1.1.0)
Requirement already satisfied: numpy>=1.16.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (1.23.2)
Requirement already satisfied: scipy>=1.2.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (1.9.0)
Collecting qtpy
  Downloading QtPy-2.2.0-py3-none-any.whl (82 kB)
     |████████████████████████████████| 82 kB 2.9 MB/s
Collecting mne-qt-browser
  Downloading mne_qt_browser-0.3.1-py3-none-any.whl (70 kB)
     |████████████████████████████████| 70 kB 4.5 MB/s
Requirement already satisfied: matplotlib in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne-icalabel[gui]) (3.5.3)
Requirement already satisfied: decorator in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne>=1.1->mne-icalabel[gui]) (5.1.1)
Requirement already satisfied: jinja2 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne>=1.1->mne-icalabel[gui]) (3.1.2)
Requirement already satisfied: packaging in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne>=1.1->mne-icalabel[gui]) (21.3)
Requirement already satisfied: tqdm in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from mne>=1.1->mne-icalabel[gui]) (4.62.3)
Requirement already satisfied: appdirs>=1.3.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from pooch->mne-icalabel[gui]) (1.4.4)
Requirement already satisfied: requests>=2.19.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from pooch->mne-icalabel[gui]) (2.27.1)
Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from packaging->mne>=1.1->mne-icalabel[gui]) (3.0.9)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from requests>=2.19.0->pooch->mne-icalabel[gui]) (2021.10.8)
Requirement already satisfied: charset-normalizer~=2.0.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from requests>=2.19.0->pooch->mne-icalabel[gui]) (2.0.7)
Requirement already satisfied: idna<4,>=2.5 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from requests>=2.19.0->pooch->mne-icalabel[gui]) (3.3)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from requests>=2.19.0->pooch->mne-icalabel[gui]) (1.26.7)
Requirement already satisfied: MarkupSafe>=2.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from jinja2->mne>=1.1->mne-icalabel[gui]) (2.1.1)
Requirement already satisfied: kiwisolver>=1.0.1 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from matplotlib->mne-icalabel[gui]) (1.4.4)
Requirement already satisfied: cycler>=0.10 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from matplotlib->mne-icalabel[gui]) (0.11.0)
Requirement already satisfied: pillow>=6.2.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from matplotlib->mne-icalabel[gui]) (9.2.0)
Requirement already satisfied: python-dateutil>=2.7 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from matplotlib->mne-icalabel[gui]) (2.8.2)
Requirement already satisfied: fonttools>=4.22.0 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from matplotlib->mne-icalabel[gui]) (4.36.0)
Requirement already satisfied: six>=1.5 in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from python-dateutil>=2.7->matplotlib->mne-icalabel[gui]) (1.16.0)
Collecting colorspacious
  Downloading colorspacious-1.1.2-py2.py3-none-any.whl (37 kB)
Collecting scooby
  Downloading scooby-0.6.0-py3-none-any.whl (14 kB)
Collecting qdarkstyle
  Downloading QDarkStyle-3.1-py2.py3-none-any.whl (870 kB)
     |████████████████████████████████| 870 kB 6.8 MB/s
Collecting darkdetect
  Downloading darkdetect-0.7.1-py2.py3-none-any.whl (8.2 kB)
Collecting pyqtgraph>=0.12.3
  Downloading pyqtgraph-0.12.4-py3-none-any.whl (995 kB)
     |████████████████████████████████| 995 kB 3.2 MB/s
Requirement already satisfied: typing-extensions in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from torch->mne-icalabel[gui]) (4.3.0)
Requirement already satisfied: colorama in c:\users\adina\appdata\local\programs\python\python39\lib\site-packages (from tqdm->mne>=1.1->mne-icalabel[gui]) (0.4.4)
Installing collected packages: qtpy, scooby, qdarkstyle, pyqtgraph, darkdetect, colorspacious, mne-qt-browser
Successfully installed colorspacious-1.1.2 darkdetect-0.7.1 mne-qt-browser-0.3.1 pyqtgraph-0.12.4 qdarkstyle-3.1 qtpy-2.2.0 scooby-0.6.0
WARNING: You are using pip version 21.2.4; however, version 22.2.2 is available.
You should consider upgrading via the 'C:\Users\adina\AppData\Local\Programs\Python\Python39\python.exe -m pip install --upgrade pip' command.

C:\Users\adina\repos>ipython
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import os
   ...:
   ...: import mne
   ...: from mne.preprocessing import ICA
   ...:
   ...: from mne_icalabel.gui import label_ica_components

In [2]: sample_data_folder = mne.datasets.sample.data_path()
   ...: sample_data_raw_file = os.path.join(
   ...:     sample_data_folder, "MEG", "sample", "sample_audvis_filt-0-40_raw.fif"
   ...: )
   ...: raw = mne.io.read_raw_fif(sample_data_raw_file)
   ...:
   ...: # Here we'll crop to 60 seconds and drop gradiometer channels for speed
   ...: raw.crop(tmax=60.0).pick_types(meg="mag", eeg=True, stim=True, eog=True)
   ...: raw.load_data()
Opening raw data file C:\Users\adina\mne_data\MNE-sample-data\MEG\sample\sample_audvis_filt-0-40_raw.fif...
    Read a total of 4 projection items:
        PCA-v1 (1 x 102)  idle
        PCA-v2 (1 x 102)  idle
        PCA-v3 (1 x 102)  idle
        Average EEG reference (1 x 60)  idle
    Range : 6450 ... 48149 =     42.956 ...   320.665 secs
Ready.
Reading 0 ... 9009  =      0.000 ...    59.999 secs...
Out[2]: <Raw | sample_audvis_filt-0-40_raw.fif, 171 x 9010 (60.0 s), ~14.8 MB, data loaded>

In [3]: # high-pass filter the data and then perform ICA
   ...: filt_raw = raw.copy().filter(l_freq=1.0, h_freq=None)
   ...: ica = ICA(n_components=15, max_iter="auto", random_state=97)
   ...: ica.fit(filt_raw)
Filtering raw data in 1 contiguous segment
Setting up high-pass filter at 1 Hz

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal highpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower passband edge: 1.00
- Lower transition bandwidth: 1.00 Hz (-6 dB cutoff frequency: 0.50 Hz)
- Filter length: 497 samples (3.310 sec)

[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   2 out of   2 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   3 out of   3 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   4 out of   4 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done 161 out of 161 | elapsed:    0.0s finished
Fitting ICA to data using 161 channels (please be patient, this may take a while)
Selecting by number: 15 components
Fitting ICA took 0.8s.
Out[3]: <ICA | raw data decomposition, method: fastica (fit in 22 iterations on 9010 samples), 15 ICA components explaining 94.3 % of variance (161 PCA components available), channel types: mag, eeg, no sources marked for exclusion>

In [4]: gui = label_ica_components(raw, ica)
   ...:
   ...: # The `ica` object is modified to contain the component labels
   ...: # after closing the GUI and can now be saved
   ...: # gui.close()  # typically you close when done
   ...:
   ...: # Now, we can take a look at the components, which were modified in-place
   ...: # for the ICA instance.
   ...: print(ica.labels_)
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 gui = label_ica_components(raw, ica)
      3 # The `ica` object is modified to contain the component labels
      4 # after closing the GUI and can now be saved
      5 # gui.close()  # typically you close when done
      6
      7 # Now, we can take a look at the components, which were modified in-place
      8 # for the ICA instance.
      9 print(ica.labels_)

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\mne_icalabel\gui\__init__.py:26, in label_ica_components(inst, ica, show, block)
      5 """Launch the IC labelling GUI.
      6
      7 Parameters
   (...)
     22     The graphical user interface (GUI) window.
     23 """
     24 from mne.viz.backends._utils import _init_mne_qtapp, _qt_app_exec
---> 26 from ._label_components import ICAComponentLabeler
     28 # get application
     29 app = _init_mne_qtapp()

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\mne_icalabel\gui\_label_components.py:4, in <module>
      1 from typing import Dict, List, Union
      3 from matplotlib import pyplot as plt
----> 4 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
      5 from mne import BaseEpochs
      6 from mne.io import BaseRaw

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\matplotlib\backends\backend_qt5agg.py:7, in <module>
      4 from .. import backends
      6 backends._QT_FORCE_QT5_BINDING = True
----> 7 from .backend_qtagg import (    # noqa: F401, E402 # pylint: disable=W0611
      8     _BackendQTAgg, FigureCanvasQTAgg, FigureManagerQT, NavigationToolbar2QT,
      9     backend_version,  FigureCanvasAgg,  FigureCanvasQT
     10 )
     13 @_BackendQTAgg.export
     14 class _BackendQT5Agg(_BackendQTAgg):
     15     pass

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\matplotlib\backends\backend_qtagg.py:9, in <module>
      5 import ctypes
      7 from matplotlib.transforms import Bbox
----> 9 from .qt_compat import QT_API, _enum, _setDevicePixelRatio
     10 from .. import cbook
     11 from .backend_agg import FigureCanvasAgg

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\matplotlib\backends\qt_compat.py:142, in <module>
    140         break
    141     else:
--> 142         raise ImportError("Failed to import any qt binding")
    143 else:  # We should not get there.
    144     raise AssertionError(f"Unexpected QT_API: {QT_API}")

ImportError: Failed to import any qt binding
click to expand Linux zsh ``` (joss) adina@muninn in ~/repos/mne-icalabel on git:main! ❱ ipython Python 3.9.12 (main, Mar 24 2022, 13:02:21) Type 'copyright', 'credits' or 'license' for more information IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import os
...:
...: import mne
...: from mne.preprocessing import ICA
...:
...: from mne_icalabel.gui import label_ica_components

In [2]: sample_data_folder = mne.datasets.sample.data_path()
...: sample_data_raw_file = os.path.join(
...: sample_data_folder, "MEG", "sample", "sample_audvis_filt-0-40_raw.fif"
...: )
...: raw = mne.io.read_raw_fif(sample_data_raw_file)
...:
...: # Here we'll crop to 60 seconds and drop gradiometer channels for speed
...: raw.crop(tmax=60.0).pick_types(meg="mag", eeg=True, stim=True, eog=True)
...: raw.load_data()
Opening raw data file /home/adina/mne_data/MNE-sample-data/MEG/sample/sample_audvis_filt-0-40_raw.fif...
Read a total of 4 projection items:
PCA-v1 (1 x 102) idle
PCA-v2 (1 x 102) idle
PCA-v3 (1 x 102) idle
Average EEG reference (1 x 60) idle
Range : 6450 ... 48149 = 42.956 ... 320.665 secs
Ready.
Reading 0 ... 9009 = 0.000 ... 59.999 secs...
Out[2]: <Raw | sample_audvis_filt-0-40_raw.fif, 171 x 9010 (60.0 s), ~14.8 MB, data loaded>

In [3]: # high-pass filter the data and then perform ICA
...: filt_raw = raw.copy().filter(l_freq=1.0, h_freq=None)
...: ica = ICA(n_components=15, max_iter="auto", random_state=97)
...: ica.fit(filt_raw)
Filtering raw data in 1 contiguous segment
Setting up high-pass filter at 1 Hz

FIR filter parameters

Designing a one-pass, zero-phase, non-causal highpass filter:

  • Windowed time-domain design (firwin) method
  • Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
  • Lower passband edge: 1.00
  • Lower transition bandwidth: 1.00 Hz (-6 dB cutoff frequency: 0.50 Hz)
  • Filter length: 497 samples (3.310 sec)

[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 2 out of 2 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 3 out of 3 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 4 out of 4 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 161 out of 161 | elapsed: 0.1s finished
Fitting ICA to data using 161 channels (please be patient, this may take a while)
Selecting by number: 15 components
Fitting ICA took 0.5s.
Out[3]: <ICA | raw data decomposition, method: fastica (fit in 22 iterations on 9010 samples), 15 ICA components explaining 94.3 % of variance (161 PCA components available), channel types: mag, eeg, no sources marked for exclusion>

In [4]: gui = label_ica_components(raw, ica)
...:
...: # The ica object is modified to contain the component labels
...: # after closing the GUI and can now be saved
...: # gui.close() # typically you close when done
...:
...: # Now, we can take a look at the components, which were modified in-place
...: # for the ICA instance.
...: print(ica.labels_)

ImportError Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 gui = label_ica_components(raw, ica)
3 # The ica object is modified to contain the component labels
4 # after closing the GUI and can now be saved
5 # gui.close() # typically you close when done
6
7 # Now, we can take a look at the components, which were modified in-place
8 # for the ICA instance.
9 print(ica.labels_)

File ~/repos/mne-icalabel/mne_icalabel/gui/init.py:26, in label_ica_components(inst, ica, show, block)
5 """Launch the IC labelling GUI.
6
7 Parameters
(...)
22 The graphical user interface (GUI) window.
23 """
24 from mne.viz.backends._utils import _init_mne_qtapp, _qt_app_exec
---> 26 from ._label_components import ICAComponentLabeler
28 # get application
29 app = _init_mne_qtapp()

File ~/repos/mne-icalabel/mne_icalabel/gui/_label_components.py:4, in
1 from typing import Dict, List, Union
3 from matplotlib import pyplot as plt
----> 4 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
5 from mne import BaseEpochs
6 from mne.io import BaseRaw

File ~/env/joss/lib/python3.9/site-packages/matplotlib/backends/backend_qt5agg.py:7, in
4 from .. import backends
6 backends._QT_FORCE_QT5_BINDING = True
----> 7 from .backend_qtagg import ( # noqa: F401, E402 # pylint: disable=W0611
8 _BackendQTAgg, FigureCanvasQTAgg, FigureManagerQT, NavigationToolbar2QT,
9 backend_version, FigureCanvasAgg, FigureCanvasQT
10 )
13 @_BackendQTAgg.export
14 class _BackendQT5Agg(_BackendQTAgg):
15 pass

File ~/env/joss/lib/python3.9/site-packages/matplotlib/backends/backend_qtagg.py:9, in
5 import ctypes
7 from matplotlib.transforms import Bbox
----> 9 from .qt_compat import QT_API, _enum, _setDevicePixelRatio
10 from .. import cbook
11 from .backend_agg import FigureCanvasAgg

File ~/env/joss/lib/python3.9/site-packages/matplotlib/backends/qt_compat.py:142, in
140 break
141 else:
--> 142 raise ImportError("Failed to import any qt binding")
143 else: # We should not get there.
144 raise AssertionError(f"Unexpected QT_API: {QT_API}")

ImportError: Failed to import any qt binding

</details>


Installing PyQt5, which currently isn't listed as a dependency for the ```[gui]``` components, solved the issue on both machines. 

Comments on the docsite

Collecting a few small / quick comments on the documentation website.
This comment / review is part of the JOSS paper review:
openjournals/joss-reviews#4484

General:

  • In the About part of the repo page (top right), it would be useful to put the documentation site in the link field
  • There seems to be small issue with the version selector (multiple "v0.1"s)
    • Screen Shot 2022-07-31 at 2 23 57 PM
  • The License button in the header is a broken link
  • I think the landing page of the docsite should say a bit more about this project, including a bit more description (such as is in the README / summary of the JOSS paper), and a note that this is a re-implementation of the ICLabel project.

Example:

  • There are some parts that are not rendering correctly (as in, what should be text markdown getting rendered as a code block)
    • This includes the section "# Example: EOG and ECG artifact repair", for both 0.2 release, and the dev version
  • If installing mne-icalabel, with it's required dependencies, and trying to run the example, one hits a dependency error for fitting the ICA (sklearn)
    • I think it might be worth mentioning in the example that it has an extra dependency: scikit-learn
  • For the cell that plots the ICA sources, this is what I get locally:
    • Screen Shot 2022-07-31 at 2 47 53 PM
    • However, one the docsite, it looks like:
    • Screen Shot 2022-07-31 at 2 49 22 PM
    • There appears to be a rendering issue on the docsite, which is an issue for the comments about looking at the time series.
  • After this section of the tutorial, the description and notes discuss "00" as eye activity, and "01" as heartbeat. I agree with "00", but I think something changed at some point such at 01 is not clearly heartbeat, but rather 05 looks more like heartbeat. This is a bit unclear on the docsite, since the time series plot doesn't render, but the time series plot above that gets generated locally seems to suggest this. (Note that the automatic labelling after this also does not label 01 as heartbeat).
  • The Selecting ICA components automatically again has some rendering issues, and I think should be more clearly split up into separate blocks to see each step here
  • There are quite a lot of warnings printed out from the label_components function (local version copied here), and this seems to imply there are some issues with what is being computed? If not, why are the warnings arising?
    • Screen Shot 2022-07-31 at 2 57 07 PM
  • After the labels have been computed, rather than printing them out as a list that is a disconnected from the actual ICs, I think it would be much more informative to then print out
    • something like for ind, label in enumerate(labels): print(label); ica.plot_properties(raw, picks=[ind]);
    • ^It might be a bit much to print all of them, but for a subset showing "this is an IC that the labelling called X" would be nice.

[GUI] Missing or non-expandable ICA properties

Describe the bug

The GUI seems to lack some ICA property plots shown in the tutorial, or they exists, but can't be expanded.

Steps to reproduce

I followed the tutorial, using a Python 3.9 environment on a Windows 11 and a Debian bookworm system.

Expected results

I expected to see the GUI include all plots shown in the figure in the tutorial, including the epochs image, ERP/ERF, power spectrum, and epoch variance (as shown in images
doc/auto_examples/images/sphx_glr_label_components_00{1..4}.png in the examples).

Actual results

On both machines, this is how the GUI looks by default, lacking the images from doc/auto_examples/images/sphx_glr_label_components_003.png (no external screen connected, display resolution of 2560x1440 (16:9) (Debian) and 1920x1080 (Windows)):

Debian:
Screenshot from 2022-08-19 09-03-07

Windows:
mne-icalabel-gui-windows

This is how the GUI looks in full screen:
Debian:
Screenshot from 2022-08-19 09-07-24

Windows:
mne-icalabel-gui-windows-fullscreen

The plots might be present underneath the topography, but the GUI components can't be changed in size individually so I can't reveal them if they are there.

ICLabel topographic feature fails if ICA and Raw have a channel mismatch

ICLabel topographic feature is failing if the ICA was fit on a partial raw (e.g. excluding bad channels). I'll have a look.

Code snippet:

from mne import pick_types
from mne.datasets import sample
from mne.io import read_raw_fif
from mne.preprocessing import ICA

from mne_icalabel import label_components


directory = sample.data_path() / "MEG" / "sample"
fname = directory / "sample_audvis_raw.fif"
raw = read_raw_fif(fname, preload=False)
raw.pick_types(eeg=True, exclude=[]).crop(0, 5)
raw.load_data()
raw.filter(1., 100.)
raw.set_eeg_reference("average")

picks = pick_types(raw.info, eeg=True, exclude="bads")
ica = ICA(
    n_components=5,
    method="picard",
    max_iter="auto",
    fit_params=dict(ortho=False, extended=True),
)
ica.fit(raw, picks=picks)

component_dict = label_components(raw, ica, method="iclabel")

.pt not included in v0.3

Describe the bug

FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\ferat\\AppData\\Local\\Continuum\\miniconda3\\envs\\ni39\\lib\\site-packages\\mne_icalabel\\iclabel\\assets\\iclabelNet.pt'

Steps to reproduce

Install version '0.3' via pip
then run:
label_components(raw, ica, method='iclabel')

Additional information

Autocorrection may have change assets by asserts in pyproject.toml (this line) so the .pt files are not included.

Labels for Epoch objects

Describe the bug

Upon fitting with ICA on an epochs instance, i pass in the object (along with a fitted ica instance on the same epoch object) using

ic_labels = label_components(epochs, ica, method='iclabel')

The error generated is

/var/folders/ph/9w0w89cd5pq1d7z1_kn2mt8m0000gp/T/ipykernel_18124/129543192.py in process_eeg(cap_size, ppt_num, session)
     77     ica.fit(epochs)
     78     # ICA Labels
---> 79     ic_labels = label_components(epochs, ica, method='iclabel')
     80     labels = ic_labels["labels"]
     81     exclude_idx = [idx for idx, label in enumerate(labels) 

/usr/local/anaconda3/lib/python3.9/site-packages/mne_icalabel/label_components.py in label_components(inst, ica, method)
     54     _check_option("method", method, methods)
     55     _validate_inst_and_ica(inst, ica)
---> 56     labels_pred_proba = methods[method](inst, ica)
     57     labels_pred = np.argmax(labels_pred_proba, axis=1)
     58     labels = [ICLABEL_NUMERICAL_TO_STRING[label] for label in labels_pred]

/usr/local/anaconda3/lib/python3.9/site-packages/mne_icalabel/iclabel/label_components.py in iclabel_label_components(inst, ica)
     43     .. footbibliography::
     44     """
---> 45     features = get_iclabel_features(inst, ica)
     46     labels_pred_proba = run_iclabel(*features)
     47     return labels_pred_proba

/usr/local/anaconda3/lib/python3.9/site-packages/mne_icalabel/iclabel/features.py in get_iclabel_features(inst, ica)
     80 
     81     # compute psd feature (float32)
---> 82     psd = _eeg_rpsd(inst, ica, icaact)
     83 
     84     # compute autocorr feature (float32)

/usr/local/anaconda3/lib/python3.9/site-packages/mne_icalabel/iclabel/features.py in _eeg_rpsd(inst, ica, icaact)
    243     assert isinstance(inst, (BaseRaw, BaseEpochs))  # sanity-check
    244     constants = _eeg_rpsd_constants(inst, ica)
--> 245     psd = _eeg_rpsd_compute_psdmed(inst, icaact, *constants)
    246     psd = _eeg_rpsd_format(psd)
    247     return psd

/usr/local/anaconda3/lib/python3.9/site-packages/mne_icalabel/iclabel/features.py in _eeg_rpsd_compute_psdmed(inst, icaact, ncomp, nfreqs, n_points, nyquist, index, window, subset)
    314         elif isinstance(inst, BaseEpochs):
    315             temp = np.hstack([icaact[it, index[:, k], :] for k in range(index.shape[-1])])
--> 316             temp = temp.reshape(index.shape[0], len(inst), order="F")
    317         else:
    318             raise RuntimeError  # should never happen

ValueError: cannot reshape array of size 818048 into shape (128,913)

If I instead use the following raw instance to classify the epochs it works, is this intended? Essentially I'm performing ICA after epoching, so I'm not sure how using the fitted ica on epoch data and then using the raw to compare this with is correct.

ic_labels = label_components(raw, ica, method='iclabel')

Perhaps I have some funky rank deficiency going on somewhere from interpolation or something?

"arrays used as indices must be of integer (or boolean) type"

Describe the bug

When I was running "label_components", an error occurred:
"arrays used as indices must be of integer (or boolean) type"

Steps to reproduce

IDE: jupyter notebook
python 3.9.12
mne 1.3.1
mne-iclabel 0.4

raw_filt = raw_filt.filter(l_freq=1, h_freq=None)
ica = mne.preprocessing.ICA(n_components=8, method='picard', max_iter=10000) 
ica.fit(raw_filt)

ic_labels = label_components(raw_filt, ica, method="iclabel")

Actual results

Snipaste_2023-03-16_22-22-55

importlib-resources is required for Python <3.9

I checked the Python docs and apparently, importlib.resources.files didn't show up until Python 3.9.

So we need a conditional runtime dependency for importlib-resources for older Python versions in setup.cfg.

The code for using this fallback is already present here.

[DOC] License link in documentation 404's

Hello 👋 :)
I read through the documentation and notived that the "License" header in the documentation points to https://raw.githubusercontent.com/mne-tools/mne-icalabel/blob/main/LICENSE, which does not resolve. The correct link would be https://raw.githubusercontent.com/mne-tools/mne-icalabel/main/LICENSE.

Here's a patch:

diff --git a/doc/index.rst b/doc/index.rst
index 2a33c25..257ed39 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -32,7 +32,7 @@ Contents
    :hidden:
    :caption: Development
 
-   License <https://raw.githubusercontent.com/mne-tools/mne-icalabel/blob/main/LICENSE>
+   License <https://raw.githubusercontent.com/mne-tools/mne-icalabel/main/LICENSE>
    Contributing <https://github.com/mne-tools/mne-icalabel/blob/main/CONTRIBUTING.md>
 
 License

Found while doing openjournals/joss-reviews#4484

PS: I noticed that your repositories "About" overview section on the right links to the development version instead of the stable version of the documentation - is this intentional? Not in any way a problem, adding here as an FYI in case its an unintentional pre-first-release residual, because the empty "Whats new" page in the development version caught my eye and I'm used to redirection to the stable docs by mne-python. Ignore if this choice intentional or preferred.

Runtime requirements missing from setup.py

Please add the dependencies via install_requires in setup.py (or put that stuff into pyproject.toml), including the minimal required version numbers. It appears that currently the dependencies are only specified in requirements.txt, so installing this package e.g. from PyPI won't pull in any requirements.

Clean-up _mne_to_eeglab_locs doc and comments

Hello @jacobf18, when you have the time (super low priority!), could you check and clean up the doc and comments that were left in

def _mne_to_eeglab_locs(raw: BaseRaw, picks: List[str]) -> Tuple[NDArray[float], NDArray[float]]:
"""Obtain EEGLab-like spherical coordinate from EEG channel positions.
TODO: @JACOB:
- Where is (0,0,0) defined in MNE vs EEGLab?
- some text description of how the sphere coordinates differ between MNE
and EEGLab.
Parameters
----------
raw : mne.io.BaseRaw
Instance of raw object with a `mne.montage.DigMontage` set with
``n_channels`` channel positions.
picks : list of str
List of channel names to include.
Returns
-------
Rd : np.array of shape (1, n_channels)
Angle in spherical coordinates of each EEG channel.
Th : np.array of shape (1, n_channels)
Degree in spherical coordinates of each EEG channel.
"""
def _sph2topo(_theta, _phi):
"""Convert spherical coordinates to topo."""
az = _phi
horiz = _theta
angle = -1 * horiz
radius = (np.pi / 2 - az) / np.pi
return angle, radius
def _cart2sph(_x, _y, _z):
"""Convert cartesian coordinates to spherical."""
azimuth = np.arctan2(_y, _x)
elevation = np.arctan2(_z, np.sqrt(_x**2 + _y**2))
r = np.sqrt(_x**2 + _y**2 + _z**2)
# theta,phi,r
return azimuth, elevation, r
# get the channel position dictionary
montage = raw.copy().pick_channels(picks, ordered=True).get_montage()
positions = montage.get_positions()
ch_pos = positions["ch_pos"]
# get locations as a 2D array
locs = np.vstack(list(ch_pos.values()))
# Obtain carthesian coordinates
x = locs[:, 1]
# be mindful of the nose orientation in eeglab and mne
# TODO: @Jacob, please expand on this.
y = -1 * locs[:, 0]
# see https://github.com/mne-tools/mne-python/blob/24377ad3200b6099ed47576e9cf8b27578d571ef/mne/io/eeglab/eeglab.py#L105 # noqa
z = locs[:, 2]
# Obtain Spherical Coordinates
sph = np.array([_cart2sph(x[i], y[i], z[i]) for i in range(len(x))])
theta = sph[:, 0]
phi = sph[:, 1]
# Obtain Polar coordinates (as in eeglab)
topo = np.array([_sph2topo(theta[i], phi[i]) for i in range(len(theta))])
rd = topo[:, 1]
th = topo[:, 0]
return rd.reshape([1, -1]), np.degrees(th).reshape([1, -1])

ValueError: need at least one array to concatenate

After I run the following codes, I met this error.

from mne_icalabel import label_components
ic_labels = label_components(epochs, ica, method="iclabel")
print(pd.DataFrame(ic_labels))

My data type is MEG data. So is it possible that the icalabel is not suite for MEG data?

Thanks for your time~

[BUG] Muscle artifact detection does not replicate MNE example

Here's some minimally reproducible example code:

import os.path as op
import mne
from mne_icalabel import label_components

data_path = mne.datasets.sample.data_path()
raw_fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(raw_fname)
raw.crop(tmin=100, tmax=130)  # take 30 seconds for speed

# pick only EEG channels, muscle artifact is basically not picked up by MEG
# if you have a simultaneous recording, you may want to do ICA on MEG and EEG
# separately
raw.pick_types(eeg=True)

# ICA works best with a highpass filter applied
raw.load_data()
raw.filter(l_freq=1., h_freq=100)
raw.set_eeg_reference('average')

# %%
# Run ICA
ica = mne.preprocessing.ICA(
    n_components=15, method='picard', max_iter='auto', random_state=97)
ica.fit(raw)

ic_labels = label_components(raw, ica, method="iclabel")
print(ic_labels['labels'])  # 6 on should be muscle

The components that should be muscle by my inspection at least are 6-14 shown here https://mne.tools/dev/auto_examples/preprocessing/muscle_ica.html

I get

['eye blink',
 'brain',
 'brain',
 'brain',
 'muscle artifact',
 'line noise',
 'brain',
 'muscle artifact',
 'eye blink',
 'other',
 'muscle artifact',
 'eye blink',
 'muscle artifact',
 'line noise',
 'brain']

which I guess is okay if blink and line noise supercede muscle. Maybe an enhancement would be adding all labels greater than some threshold so that there could be multiple.

Is MNE 0.24 supported?

setup.cfg says mne 0.24 is the minimum required version. However, I don't think this has (ever?) been tested? Should this be bumped to 1.0?

Improve test coverage

Looks like the main parts to improve are annotations submodule. We should also ignore the commands submodule probably. I think getting those two fixed should bring our test coverage to 90+

Screen Shot 2022-08-05 at 11 01 22 AM

Refactor ICA Component Labeling GUI Based on MNE-Python API

We would like to refactor the ICA GUI to use the ICA API provided in MNE-Python. This will rely on the PR to solve the issues raised in: mne-tools/mne-python#9846 (comment)

I'll think about it, for now, I was more inclined towards (1) because it was constrained. Supporting only datasets in BIDS format makes this first version simpler. 

I don't think it's a good idea to have a pop-up GUI to ask the user for a BIDS path, it can be more error-prone and I don't see a reason to save the IC labels in a .tsv sidecar in a BIDS folder if the original data and ICA decomposition are not in the same BIDS folder.

I like option (3) as well, modifying the ICA instance in place makes a lot of sense, and does not entirely make the .tsv redundant as it will also contain the information about who authored the labels (and other information).

Originally posted by @mscheltienne in #66 (comment)

Package name

Hello, is there a particular reason this package is called ICALabel instead of ICLabel? The latter is somewhat more intuitive to me, but maybe that's just a personal preference thing…

Don't recommend a user install via pip

I've never seen pip install --user causing anything but hard to debug trouble and confusion. I'd strongly advocate for removing this suggestion from the install docs. If a user has to rely on a centrally managed Python environment, they should talk to their administrator to install missing packages.

The problem stems from the fact that Python will by default prefer user-installed packages, so even if a centrally installed version shows up someday, Python won't use it as long as there's an (by that time then outdated) user install.

Tidy Manifest

For the MANIFEST.in, we can fix it in a follow-up. It needs more clean-up than just this .txt, and also do we include the data for the test files or not?

Let me know if the previous comment answers your question for the CAR issue.

Originally posted by @mscheltienne in #18 (comment)

We should tighten up the MANIFEST file to remove any data files, and include only the necessary python and text files for a distribution.

Notes on JOSS paper

Some brief comments / suggestions on the current draft of the JOSS paper:

  • lines 16-18: I find this sentence a little vague, and a couple sentences could clarify the details
    • how it makes this available: "this work makes the popular Matlab-based ICLabel model available in MNE-Python
    • something more on what "modern Pytorch format", as this is a bit unclear
  • line 41: say "we will build" but since this project now exists, the tense shouldn't be future
  • the relationship between Pytorch / Tensorflow, and what this project does related to them is unclear. For the M/EEG researcher who's looking into this project, I think it may be unclear how / why you jump between these different projects without detailing how they relate to each other and a more detailed description of the status of the old tool, and the update here.

Note: this issue is part of the JOSS review:
openjournals/joss-reviews#4484

Enhance Labeling GUI with MNE-QT Backend

Just to leave a comment for the next issue on v2.0 of the GUI:

The next version of the GUI would require a modular QT MNE backend.

  1. This would require a PR as Martin suggests to BrowserBase to be able to sub out the actual data for the plotting. The API would probably be something like browser.replace_data(inst).
  2. Then a PR to mne-qt-browser to add the capability inside the MNE QT browser
  3. Finally, we would update the timeseries widget accordingly in mne-icalabel

Originally posted by @adam2392 in #66 (comment)

[JOSS] Nitpicks on the paper

As part of the JOSS review I stumbled over some paragraphs or wordings in the paper. All of them are nitpicks that you can feel free to ignore, and the editors comments would take complete precedence - so please feel free to close this issue any time, and @emdupre can come in and invalidate any of my comments as she sees fit as well without explanation.

However, this package was previously only available in MATLAB, limiting its usage among Python neuroscience researchers.

The term "Python neuroscience researchers" is certainly understandable, but somehow still feels like a slightly weird composite term to me (it boils down to "Python researchers"). Given that the reduced accessibility of closed-source MatLab software is known in the open source world, I think the sentence would convey the same meaning and intention without the second half of the sentence - or, alternatively, you could make a slight change like 'neuroscientists preferring Python-based tools' to avoid the "Python researchers".

MNE-Python is a general-purpose electrophysiology analysis package in Python that has a large core group of developers. Integration into MNE makes it likely that MNE-ICALabel will be maintained and continue to be improved. MNE-Python also has stability due to the funding it receives directly for development from institutions such as National Institutes of Health, the Chan Zuckerberg open-source initiative, the European Research Council and Agence Nationale de la Recherche in France.

I think this is a strong paragraph highlighting a major advantage of this package and further warranting the porting of ICLabel into this cool open source tool. I believe that from a structural perspective it would better fit one paragraph up, right into the end of the paragraph starting with "ICLabel was a proposed statistical model that uses neural networks and a crowdsourced training dataset to automatically label ICA components [@iclabel2019]. However, this package [...]" that highlights the other advantages this package has over the EEGLab alternative/origin.

In future versions, we plan on building on top of the ICLabel model to improve its robustness when operating on different types of recording hardware, sensor type, and sensor count. Moreover, we plan on building new types of models that improve their overall accuracy and performance with respect to auto-labeling neural and non-neural signals. The availability of a simple API for ICLabel will facilitate a strong benchmark to build future models and bring in new developers and contributors.

I kept wondering whether this paragraph might better fit into a new section "Development goals" or "Future directions" rather than "Statement of Need", but I am unsure. In general, it feels like this paragraph interrupts the line of thought in the previous and preceeding paragraph (i.e., my comment above), and it feels like the last sentence ("The developer team is excited to improve the state of the art in data handling for ICA preprocessing and looking forward to welcoming new contributors and users from the broader MNE, neuroscience and electrophysiology community.") would fit more nicely at the end of this paragraph.

Again, feel free to disagree with any of those comments and close this issue at any time.

[DOC] Clarify the types of data to be used

I am unfamiliar with the original ICLabel tool, and in reading the docs and subsequently applying mne-icalabel it to my own MEG data I got confused for which types of data it is intended to be used. The paper and introduction in the documention mention "Scalp electroencephalography (EEG) and magnetoencephalography (MEG)" explicitly, and summarize generally "mne-icalabel is a Python package for labeling independent components that stem from an Independent Component Analysis (ICA)." This made me think that I could use the tool on ICAs fitted on non-EEG data such as MEG or ieeg or ECoG as well. The warning emitted by label_components() (also mentioned in #86) however somewhat implies I would need to have EEG data:

<ipython-input-7-1dec4ffcd5a6>:1: RuntimeWarning: The provided Raw instance does not seem to be referenced to a common average reference (CAR). ICLabel was designed to classify features extracted from an EEG dataset referenced to a CAR (see the 'set_eeg_reference()' method for Raw and Epochs instances).

and ndeed I can not get the examples to run on my own data without EEG channels.
The original ICLabel paper's abstract mentions EEG data only. A comment in the tutorial seems to suggest it is even more restricted:

# Note: for this example, we are using ICLabel which has only
# been validated and works for EEG systems with less than 32 electrodes.

In response to #86 , PR #87 also introduced the following changes in the tutorial to get rid of a few warnings:

ica = ICA(n_components=15, max_iter="auto", random_state=97)
# Before fitting ICA, we will apply a common average referencing.
filt_raw = filt_raw.set_eeg_reference("average")

# Note: we will use the 'infomax' method for fitting the ICA because
# that is what is supported in the ICLabel model. In practice, one can
# use any method they choose.
ica = ICA(
    n_components=15,
    max_iter="auto",
    method="infomax",
    random_state=97,
    fit_params=dict(extended=True),
)

I think it would be useful if you could clarify the requirements mne-icalabel has for ICA data, and state more prominently which data is suitable and which data isn't suitable to help people unfamiliar with the original EEGLab ICLabel tool gauge quickly if it is useful for them. Likewise a clarification about the requirements of common average referencing and non-fastica ICA, probably even in the docstring of the function, makes sense if it is a strong requirement or recommendation, which isn't immediately obvious to me from code and documentation. The code emitting the warning reads as if bad things happen if a non-infomax method is used:

# confirm that the ICA uses an infomax extended
method_ = ica.method not in ("infomax", "picard")
extended_ = "extended" not in ica.fit_params or ica.fit_params["extended"] is False
ortho_ = "ortho" not in ica.fit_params or ica.fit_params["ortho"] is True
ortho_ = ortho_ if ica.method == "picard" else False
if any((method_, extended_, ortho_)):
warn(
f"The provided ICA instance was fitted with a '{ica.method}' algorithm. "
"ICLabel was designed with extended infomax ICA decompositions. To use the "
"extended infomax algorithm, use the 'mne.preprocessing.ICA' instance with the "
"arguments 'ICA(method='infomax', fit_params=dict(extended=True))' (scikit-learn) or "
"'ICA(method='picard', fit_params=dict(ortho=False, extended=True))' (python-picard)."
)

But the comment in the tutorial says "In practice, one can use any method they choose." If non-infomax methods are not a problem, why the warning? If non-infomax methods are not benchmarked/tested/validated, I think its worth an easily findable note on that in the docstring so that anyone can learn about this without reading the walk-throughs in detail.

Point to the MNE installation instructions for getting MNE to run

We've put a lot of work into creating the MNE installation instructions because there are sooo many potential issues users can run into. Instead of simply suggesting users run conda install mne or pip install mne here, I'd just say: see the official MNE installation instructions and then come back here again.

Edit: And once we have a conda-forge package of MNE-ICALabel, we can include it in the installer and things will become even easier for users!

Installation of mne_icalabel

@rnawaz reposting in a separate issue.

Hello all, I am trying to install/import iclabel-mne but not successful. For a starting purpose I will try to execute the above example by @adam2392 but I am not sure what I am doing wrong. I tried to install mne-iclabel via pip install method mentioned in here via following

(NOTE: i am working in colab that's why exclamation mark before pip command)
!pip install --user -U https://api.github.com/repos/jacobf18/iclabel-python/zipball/main

and get the message that mne-icalabel-0.1.dev0 is successfully installed, see below

Collecting https://api.github.com/repos/jacobf18/iclabel-python/zipball/main
  Downloading https://api.github.com/repos/jacobf18/iclabel-python/zipball/main
     - 122.7 MB 1.2 MB/s
Collecting mne>=0.24
  Downloading mne-0.24.1-py3-none-any.whl (7.4 MB)`
     |████████████████████████████████| 7.4 MB 6.0 MB/s 
Requirement already satisfied: numpy>=1.16.0 in /usr/local/lib/python3.7/dist-packages (from mne-icalabel==0.1.dev0) (1.21.5)
Requirement already satisfied: scipy>=1.2.0 in /usr/local/lib/python3.7/dist-packages (from mne-icalabel==0.1.dev0) (1.4.1)
Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from mne-icalabel==0.1.dev0) (57.4.0)
Building wheels for collected packages: mne-icalabel
  Building wheel for mne-icalabel (setup.py) ... done
  Created wheel for mne-icalabel: filename=mne_icalabel-0.1.dev0-py2.py3-none-any.whl size=17612 sha256=6e077310f31de483cd83b50dcf6f88df93ba8f12a45b8cee05938a163e46a054
  Stored in directory: /tmp/pip-ephem-wheel-cache-be7s5va2/wheels/d4/00/98/7e59c6dea60d544087ce3d8d4067578061db5645b5538a1890`
Successfully built mne-icalabel
Installing collected packages: mne, mne-icalabel
  WARNING: The script mne is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed mne-0.24.1 mne-icalabel-0.1.dev0

but when I try to import the modules it says "ModuleNotFoundError: No module named 'mne_icalabel'". see below

# import
from mne_icalabel.ica_label import ica_eeg_features
from mne_icalabel.ica_net import run_iclabel

ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-2-a755f923046f> in <module>()
      # import
----> from mne_icalabel.ica_label import ica_eeg_features
      from mne_icalabel.ica_net import run_iclabel
ModuleNotFoundError: No module named 'mne_icalabel'
---------------------------------------------------------------------------
NOTE: If your import is failing due to a missing package, you can
manually install dependencies using either !pip or !apt.
To view examples of installing some common dependencies, click the
"Open Examples" button below.
---------------------------------------------------------------------------

Could you please let me know if my installation is not correct? Should there be another way to install mne-iclable? if yes, could you please update its procedure in the main repo for future users.

any help would be much appreciated.
thanks
Rab

_Originally posted by @rnawaz in #5.

Discussion about the API for mne_icalabel and mne

I would like to discuss a bit what the API would look like, both on the mne_icalabel side and on the mne side. Here is my point of view:

mne_icalabel

As described in the readme, this package is not only a port of the popular ICLabel network for EEG but could host other models for EEG, MEG, and iEEG. Thus, I would structure the package as:

mne_icalabel
└─ iclabel
    └─ assets
    └─ tests
    └─ network.py
    └─ features.py
└─ model2
└─ model3
└─ ...
└─ icalabel.py

The main entry point from a user perspective would be in mne_icalabel/icalabel.py through a function that takes as input a raw or epochs instance, an ICA decomposition, and a method (str). The method argument would have a couple of accepted values: the name of the models, e.g. 'iclabel'; and would be responsible for selecting the model used.
Based on the model used, the number of class in which the components are classified may vary. But in any case, the output should be the label (which class) and the probability that each component is in each class (scores).

Additionally to this main entry point, I would keep public a function to retrieve the features of a model, and a function to run a set of features through the model. e.g. for ICLabel, it would be mne_icalabel/iclabel/features.py:get_features and mne_icalabel/iclabel/network.py:run_iclabel. Everything else would become private.

mne

In version 1.1, there are already 4 methods to find bad components in mne.preprocessing.ICA: find_bads_ecg, find_bads_eog, find_bads_muscle and find_bads_ref. Following this pattern, I would go for a find_bads method that would wrap around the entry point in mne_icalabel/icalabel.py, with the 2 parameters inst and method. As for the 4 other methods, the label can be stored in ica.labels_.

I think it would be worth also storing the probability that each component is in each class (scores) in a similar attribute to ica.labels_, for both this new find_bads method and for all others as well.
I brought the idea here a while ago: mne-tools/mne-python#9846 but I didn't follow up on it yet. It does require a new ICA FIFF field for a 2D matrix of floats.


Finally, from an MNE perspective, the API could be simplified a bit further. At term, the find_bads method could be the only one remaining with the 4 others moved to mne_icalabel as models and called through find_bads with the correct method keyword specified.

Discussion of correctness of IClabel-python vs EEGLab

@mscheltienne reposting here as an issue to begin discussion again.

Quick update: our intern should have started on the 1st of March. But he did not yet get his work permit (mandatory in Switzerland), thus his start has been delayed and we hope he will be on board next week.


I finally took the time to test it! It looks very promising but seems to favor a lot 'Other'.
Am I correct in assuming that the classes outputted are in the order:

classes = ['Brain', 'Muscle', 'Eye', 'Heart', 'Line Noise', 'Channel Noise', 'Other']

I ran it on this file quickly:

from matplotlib import pyplot as plt
import mne
import numpy as np

from mne_icalabel.ica_label import ica_eeg_features
from mne_icalabel.ica_net import run_iclabel

#%% Load
raw = mne.io.read_raw_fif('ica-test-raw.fif', preload=True)

#%% ICA
ica = mne.preprocessing.ICA(method='picard', max_iter='auto')
ica.fit(raw, picks='eeg')

#%% Features
features = ica_eeg_features(raw, ica)
topo = features[0].astype(np.float32)
psds = features[1].astype(np.float32)
autocorr = features[2].astype(np.float32)
labels = run_iclabel(topo, psds, autocorr)

classes = ['Brain', 'Muscle', 'Eye', 'Heart', 'Line Noise', 'Channel Noise', 
           'Other']

#%% Plot
f, axes = plt.subplots(1, 7, sharex=True, sharey=True, figsize=(20, 5))
for k, ax in enumerate(axes):
    ax.bar(np.arange(0, labels.shape[0]), labels[:, k])
    ax.set_title(classes[k])

for i, label in enumerate(labels):
    k = np.argmax(label)
    axes[k].bar(i, label[k], color='crimson')
    
f.tight_layout()

#%% ICA plots
ica.plot_components()
ica.plot_sources(raw)

Screenshot 2022-03-04 at 16 40 40

Eye and heartbeat are correct. The last time we talked, you told me it failed at classifying even simple blinks, did you find what caused this?

Originally posted by @mscheltienne in #4 (comment)

mne_icalabel ImportError

Describe the bug

I installed mne-icalabel via conda and tried to use mne-icalable.
However, when I import the mne_icalabel, I got Import Error.
"ImportError: cannot import name '_INTERPOLATION_DEFAULT' from 'mne.defaults' (MYFOLDER\Anaconda3\envs\mne\lib\site-packages\mne\defaults.py)"

Steps to reproduce

I used anaconda, mne version 1.1.1 and mne_icalabel version 0.4

Actual results

from mne_icalabel import label_components


ImportError Traceback (most recent call last)
Input In [2], in <cell line: 1>()
----> 1 from mne_icalabel import label_components

File ~\Anaconda3\envs\mne\lib\site-packages\mne_icalabel_init_.py:5, in
3 from . import annotation # noqa: F401
4 from . import datasets # noqa: F401
----> 5 from . import features # noqa: F401
6 from ._version import version # noqa: F401
7 from .label_components import label_components

File ~\Anaconda3\envs\mne\lib\site-packages\mne_icalabel\features_init_.py:3, in
1 """Features for the ICLabel"""
----> 3 from .topomap import get_topomaps

File ~\Anaconda3\envs\mne\lib\site-packages\mne_icalabel\features\topomap.py:5, in
3 import numpy as np
4 from mne.channels.layout import _find_topomap_coords
----> 5 from mne.defaults import _BORDER_DEFAULT, _EXTRAPOLATE_DEFAULT, _INTERPOLATION_DEFAULT
6 from mne.io import Info
7 from mne.io.pick import _get_channel_types, _pick_data_channels, _picks_to_idx, pick_info

ImportError: cannot import name '_INTERPOLATION_DEFAULT' from 'mne.defaults' (MYFOLDER\Anaconda3\envs\mne\lib\site-packages\mne\defaults.py)

Using it on Windows?

Hello, has anyone here tried to use this package on Windows? I'm having a bit of trouble getting PyTorch to work on this platform via conda-forge, as there's currently not conda-forge package of PyTorch available: mne-tools/mne-installers#123 (comment)

Just wanted to ask if anybody's got experience with this sort of issue?

ICLabel doesn't work with combined MEG/EEG data

          I meant that if we have a dataset with combined channels, ICLabel should be applied only to the EEG channel-related components. And at the moment, it is indeed not working.
from mne.datasets import sample
from mne.io import read_raw_fif
from mne.preprocessing import ICA
from mne_icalabel import label_components


directory = sample.data_path() / "MEG" / "sample"
raw = read_raw_fif(directory / "sample_audvis_raw.fif", preload=False)
raw.pick_types(meg=True, eeg=True)
raw.load_data()
raw.filter(1., 100.)
ica = ICA(n_components=5, method="picard")
ica.fit(raw)

labels = label_components(raw, ica, method="iclabel")

Raises:

  Cell In[1], line 15
    labels = label_components(raw, ica, method="iclabel")

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\label_components.py:50 in label_components
    labels_pred_proba = ICALABEL_METHODS[method](inst, ica)  # type: ignore

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\label_components.py:57 in iclabel_label_components
    features = get_iclabel_features(inst, ica)

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\features.py:85 in get_iclabel_features
    topo = _eeg_topoplot(inst, icawinv, ica.ch_names)

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\features.py:186 in _eeg_topoplot
    temp_topo = _topoplotFast(icawinv[:, it], rd, th)

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\features.py:236 in _topoplotFast
    Xi, Yi, Zi = _gdatav4(x, y, values.reshape((-1, 1)), XQ, YQ)

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\utils.py:132 in _gdatav4
    x, y, v = _mergepoints2D(x, y, v)

  File ~\Documents\git\mscheltienne\mne-icalabel\mne_icalabel\iclabel\utils.py:194 in _mergepoints2D
    v = np.reshape(v, sz, order="F")

  File <__array_function__ internals>:200 in reshape

  File ~\Documents\pyvenv\mscheltienne\mne-icalabel\lib\site-packages\numpy\core\fromnumeric.py:298 in reshape
    return _wrapfunc(a, 'reshape', newshape, order=order)

  File ~\Documents\pyvenv\mscheltienne\mne-icalabel\lib\site-packages\numpy\core\fromnumeric.py:57 in _wrapfunc
    return bound(*args, **kwds)

ValueError: cannot reshape array of size 364 into shape (59,)

But I'm not sure how MNE handles an ICA decomposition on multiple channel types.. I need to look into that first.

Originally posted by @mscheltienne in #124 (comment)

Setting up dataset repository for testing

Similar to MNE-Python datasets API, just leverage pooch again to pull datasets from a repo.

Datasets unique to iclabel-python would be:

  • the MATLAB convnet weight files
  • additional feature files for the original ICLabel pipeline
  • other EEGLab files that would be useful to integrate

In the future, I can imagine there needing to be more datasets unique to the mne-iclabel, which would warrant this other dataset repository.

Remove extras_require?

All dependencies currently listed as extras_require.full apparently are only used for building docs and running tests, so I think they should be dropped from setup.cfg.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.