ica.plot_sources not working

Hi,

I’m having issues trying to use the ica.plot_sources in MNE. Here is the code I’m trying to run:

def run_ica(subject, condition, srmr_nr, sampling_rate):
    # Set paths
    subject_id = f'sub-{str(subject).zfill(3)}'
    save_path = "../tmp_data/baseline_ica_py/" + subject_id + "/esg/prepro/"  # Saving to baseline_ica_py
    input_path = "/data/pt_02569/tmp_data/prepared_py/" + subject_id + "/esg/prepro/"  # Taking prepared data
    figure_path = "/data/p_02569/baseline_ICA_images/" + subject_id + "/"
    cfg_path = "/data/pt_02569/"  # Contains important info about experiment
    os.makedirs(save_path, exist_ok=True)
    os.makedirs(figure_path, exist_ok=True)

    # Get the condition information based on the condition read in
    cond_info = get_conditioninfo(condition, srmr_nr)
    cond_name = cond_info.cond_name
    trigger_name = cond_info.trigger_name
    nerve = cond_info.nerve

    # load cleaned ESG data
    fname = f'noStimart_sr{sampling_rate}_{cond_name}_withqrs.fif'
    raw = mne.io.read_raw_fif(input_path + fname, preload=True)

    # make a copy to filter
    raw_filtered = raw.copy().drop_channels(['ECG'])

    # filtering
    cfg = loadmat(cfg_path + 'cfg.mat')
    notch_freq = cfg['notch_freq'][0]
    esg_bp_freq = cfg['esg_bp_freq'][0]

    raw_filtered.filter(l_freq=esg_bp_freq[0], h_freq=esg_bp_freq[1], n_jobs=len(raw.ch_names), method='iir',
                        iir_params={'order': 2, 'ftype': 'butter'}, phase='zero')

    raw_filtered.notch_filter(freqs=notch_freq, n_jobs=len(raw.ch_names), method='fir', phase='zero')

    # ICA
    ica = mne.preprocessing.ICA(n_components=len(raw_filtered.ch_names), max_iter='auto', random_state=97)
    # ica = mne.preprocessing.ICA(n_components=len(raw_filtered.ch_names), max_iter='auto', random_state=97)
    ica.fit(raw_filtered)

    raw.load_data()
    ica.plot_sources(raw)  # Just for visualising

    # Automatically choose ICA components
    ica.exclude = []
    # find which ICs match the EOG pattern
    ecg_indices, ecg_scores = ica.find_bads_ecg(raw, ch_name='ECG')
    ica.exclude = ecg_indices
    ica.plot_scores(ecg_scores)  # Just for visualising

    # Apply the ica we got from the filtered data onto the unfiltered raw
    ica.apply(raw)


And essentially this works totally fine, provided I comment the ica.plot_sources line…

The error I get if I leave it in looks like:
ValueError: At least one channel name in annotations missing from info: S35

The problem is I have no idea how to fix this, given if I print the channels in raw and raw_filtered I get:

Which clearly shows the channel being there, and I never meddle with the info.

Any suggestions more than welcome!

  • MNE version: e.g. 0.23.4
  • operating system: Ubuntu

Hello, I assume it has to do with the fact that you drop channels from the data you fit ICA on, while keeping those channels in the data you then apply the ICA unmixing matrix to.

I’m a little confused - I was following exactly the tutorial here Repairing artifacts with ICA — MNE 1.0.0 documentation where the same is done - the ica is fitted to the filtered data and then the normal raw is used to plot the sources

Edit: I reread your comment and do you think it’s because I drop the ECG channel? I tried doing plot_sources with raw_filtered instead and no joy there either (same error)

Edit 2: Just to check your hunch, I tried rerunning without dropping the ECG channel, and I still get the same error - there must be some kind of mismatch between the info and annotations but I have no idea how to fix

Is there any chance you could share your data with me so I can take a look?

I can’t unfortunately - I tried just looking directly at the channel names in the info structure using:

info = mne.io.read_info(input_path+fname)
    print(info['ch_names'])

And S35 is most certainly there so the error that it’s missing from info is really confusing…

What happens if you fit and apply ICA on the exact same data? That is, don’t run ICA on the filtered data and apply it to the unfiltered data (as is normally recommended), but just use your raw everywhere?

Note that this is normally not recommended, but merely an attempt to better understand the problem you’re seeing here

Also, can you please provide the complete traceback if you hit the error again? Not just the last line or two, but all of them?

Same error if I just use raw rather than raw_filtered, here it is:

Traceback (most recent call last):
  File "/data/pt_02569/Python_Cardiac/main.py", line 74, in <module>
    run_ica(subject, condition, srmr_nr, sampling_rate)
  File "/data/pt_02569/Python_Cardiac/ICA.py", line 49, in run_ica
    ica.plot_sources(raw)  # Just for visualising
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/preprocessing/ica.py", line 1852, in plot_sources
    show_scrollbars=show_scrollbars)
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/viz/ica.py", line 88, in plot_ica_sources
    show_scrollbars=show_scrollbars)
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/viz/ica.py", line 989, in _plot_sources
    inst_array.set_annotations(inst.annotations)
  File "<decorator-gen-183>", line 24, in set_annotations
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/io/base.py", line 659, in set_annotations
    new_annotations._prune_ch_names(self.info, on_missing)
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/annotations.py", line 422, in _prune_ch_names
    on_missing, 'At least one channel name in '
  File "/data/pt_02569/Python_Cardiac/venv/lib/python3.6/site-packages/mne/utils/check.py", line 757, in _on_missing
    raise error_klass(msg)
ValueError: At least one channel name in annotations missing from info: S35

And I guess my ica problems get even weirder… If I plot the ICA components, it shows that almost all of them explain a high amount of the variance, which doesn’t make sense

This is only the scores for the automated artifact detection, so you’re not seeing how much variance each component explains in this figure.

As for your issue, I just realized that your MNE version is quite old. Is there any chance you could update to MNE-Python 1.0 and see if the problem persists?

Otherwise I’m at a loss and I think I cannot help without getting my hands on the data.

I will try! I guess I’m not super concerned about it - when I use plot_overlay it is taking out the heart artefact pretty well

So whatever quirk/bug it is it’s just not letting me plot the sources but the ICA seems to do just fine! Thanks for your help and I’ll update if I change my MNE version :slight_smile:

I don’t think it’s working well based on this figure and the scores you presented earlier… In the first subplot in the last figure you posted, one can clearly see a black trace capturing heartbeats. I wouldn’t really trust these results…

The black trace is my actual ECG channel and I don’t apply ICA to it so all good there :slight_smile:

If I exclude it I get the following:

Because I was allowing the auto selection, I think it’s using far too many components (I think I’m right in that it selects all the red bars in the plot_scores figure?) so it’s kind of killing the whole signal, but other than that it is removing the heart artefact