Compute coherence in source space using a MNE inverse solution

This example computes the coherence between a seed in the left auditory cortex and the rest of the brain based on single-trial MNE-dSPM inverse solutions.

# Author: Martin Luessi <mluessi@nmr.mgh.harvard.edu>
#
# License: BSD (3-clause)

import numpy as np

import mne
from mne.datasets import sample
from mne.minimum_norm import (apply_inverse, apply_inverse_epochs,
                              read_inverse_operator)
from mne.connectivity import seed_target_indices, spectral_connectivity

print(__doc__)

Read the data

First we’ll read in the sample MEG data that we’ll use for computing coherence between channels. We’ll convert this into epochs in order to compute the event-related coherence.

data_path = sample.data_path()
subjects_dir = data_path + '/subjects'
fname_inv = data_path + '/MEG/sample/sample_audvis-meg-oct-6-meg-inv.fif'
fname_raw = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
fname_event = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif'
label_name_lh = 'Aud-lh'
fname_label_lh = data_path + '/MEG/sample/labels/%s.label' % label_name_lh

event_id, tmin, tmax = 1, -0.2, 0.5
method = "dSPM"  # use dSPM method (could also be MNE or sLORETA)

# Load data.
inverse_operator = read_inverse_operator(fname_inv)
label_lh = mne.read_label(fname_label_lh)
raw = mne.io.read_raw_fif(fname_raw)
events = mne.read_events(fname_event)

# Add a bad channel.
raw.info['bads'] += ['MEG 2443']

# pick MEG channels.
picks = mne.pick_types(raw.info, meg=True, eeg=False, stim=False, eog=True,
                       exclude='bads')

# Read epochs.
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
                    baseline=(None, 0),
                    reject=dict(mag=4e-12, grad=4000e-13, eog=150e-6))

Out:

Reading inverse operator decomposition from /home/circleci/mne_data/MNE-sample-data/MEG/sample/sample_audvis-meg-oct-6-meg-inv.fif...
    Reading inverse operator info...
    [done]
    Reading inverse operator decomposition...
    [done]
    305 x 305 full covariance (kind = 1) found.
    Read a total of 4 projection items:
        PCA-v1 (1 x 102) active
        PCA-v2 (1 x 102) active
        PCA-v3 (1 x 102) active
        Average EEG reference (1 x 60) active
    Noise covariance matrix read.
    22494 x 22494 diagonal covariance (kind = 2) found.
    Source covariance matrix read.
    22494 x 22494 diagonal covariance (kind = 6) found.
    Orientation priors read.
    22494 x 22494 diagonal covariance (kind = 5) found.
    Depth priors read.
    Did not find the desired covariance matrix (kind = 3)
    Reading a source space...
    Computing patch statistics...
    Patch information added...
    Distance information added...
    [done]
    Reading a source space...
    Computing patch statistics...
    Patch information added...
    Distance information added...
    [done]
    2 source spaces read
    Read a total of 4 projection items:
        PCA-v1 (1 x 102) active
        PCA-v2 (1 x 102) active
        PCA-v3 (1 x 102) active
        Average EEG reference (1 x 60) active
    Source spaces transformed to the inverse solution coordinate frame
Opening raw data file /home/circleci/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.
Not setting metadata
Not setting metadata
72 matching events found
Setting baseline interval to [-0.19979521315838786, 0.0] sec
Applying baseline correction (mode: mean)
Created an SSP operator (subspace dimension = 3)
4 projection items activated

Choose channels for coherence estimation

Next we’ll calculate our channel sources. Then we’ll find the most active vertex in the left auditory cortex, which we will later use as seed for the connectivity computation.

snr = 3.0
lambda2 = 1.0 / snr ** 2
evoked = epochs.average()
stc = apply_inverse(evoked, inverse_operator, lambda2, method,
                    pick_ori="normal")

# Restrict the source estimate to the label in the left auditory cortex.
stc_label = stc.in_label(label_lh)

# Find number and index of vertex with most power.
src_pow = np.sum(stc_label.data ** 2, axis=1)
seed_vertno = stc_label.vertices[0][np.argmax(src_pow)]
seed_idx = np.searchsorted(stc.vertices[0], seed_vertno)  # index in orig stc

# Generate index parameter for seed-based connectivity analysis.
n_sources = stc.data.shape[0]
indices = seed_target_indices([seed_idx], np.arange(n_sources))

Out:

    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 1711']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
Removing projector <Projection | Average EEG reference, active : True, n_channels : 60>
Preparing the inverse operator for use...
    Scaled noise and source covariance from nave = 1 to nave = 55
    Created the regularized inverter
    Created an SSP operator (subspace dimension = 3)
    Created the whitener using a noise covariance matrix with rank 302 (3 small eigenvalues omitted)
    Computing noise-normalization factors (dSPM)...
[done]
Applying inverse operator to "1"...
    Picked 305 channels from the data
    Computing inverse...
    Eigenleads need to be weighted ...
    Computing residual...
    Explained  59.3% variance
    dSPM...
[done]

Compute the inverse solution for each epoch. By using “return_generator=True” stcs will be a generator object instead of a list. This allows us so to compute the coherence without having to keep all source estimates in memory.

snr = 1.0  # use lower SNR for single epochs
lambda2 = 1.0 / snr ** 2
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method,
                            pick_ori="normal", return_generator=True)

Compute the coherence between sources

Now we are ready to compute the coherence in the alpha and beta band. fmin and fmax specify the lower and upper freq. for each band, respectively.

To speed things up, we use 2 parallel jobs and use mode=’fourier’, which uses a FFT with a Hanning window to compute the spectra (instead of a multitaper estimation, which has a lower variance but is slower). By using faverage=True, we directly average the coherence in the alpha and beta band, i.e., we will only get 2 frequency bins.

fmin = (8., 13.)
fmax = (13., 30.)
sfreq = raw.info['sfreq']  # the sampling frequency

coh, freqs, times, n_epochs, n_tapers = spectral_connectivity(
    stcs, method='coh', mode='fourier', indices=indices,
    sfreq=sfreq, fmin=fmin, fmax=fmax, faverage=True, n_jobs=1)

print('Frequencies in Hz over which coherence was averaged for alpha: ')
print(freqs[0])
print('Frequencies in Hz over which coherence was averaged for beta: ')
print(freqs[1])

Out:

Connectivity computation...
Preparing the inverse operator for use...
    Scaled noise and source covariance from nave = 1 to nave = 1
    Created the regularized inverter
    Created an SSP operator (subspace dimension = 3)
    Created the whitener using a noise covariance matrix with rank 302 (3 small eigenvalues omitted)
    Computing noise-normalization factors (dSPM)...
[done]
Picked 305 channels from the data
Computing inverse...
    Eigenleads need to be weighted ...
Processing epoch : 1 / 72 (at most)
    computing connectivity for 7498 connections
    using t=-0.200s..0.499s for estimation (106 points)
    computing connectivity for the bands:
     band 1: 8.5Hz..12.7Hz (4 points)
     band 2: 14.2Hz..29.7Hz (12 points)
    connectivity scores will be averaged for each band
    using FFT with a Hanning window to estimate spectra
    the following metrics will be computed: Coherence
    computing connectivity for epoch 1
Processing epoch : 2 / 72 (at most)
    computing connectivity for epoch 2
Processing epoch : 3 / 72 (at most)
    computing connectivity for epoch 3
Processing epoch : 4 / 72 (at most)
    computing connectivity for epoch 4
Processing epoch : 5 / 72 (at most)
    computing connectivity for epoch 5
Processing epoch : 6 / 72 (at most)
    computing connectivity for epoch 6
Processing epoch : 7 / 72 (at most)
    computing connectivity for epoch 7
Processing epoch : 8 / 72 (at most)
    computing connectivity for epoch 8
Processing epoch : 9 / 72 (at most)
    computing connectivity for epoch 9
Processing epoch : 10 / 72 (at most)
    computing connectivity for epoch 10
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 11 / 72 (at most)
    computing connectivity for epoch 11
Processing epoch : 12 / 72 (at most)
    computing connectivity for epoch 12
Processing epoch : 13 / 72 (at most)
    computing connectivity for epoch 13
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 14 / 72 (at most)
    computing connectivity for epoch 14
Processing epoch : 15 / 72 (at most)
    computing connectivity for epoch 15
Processing epoch : 16 / 72 (at most)
    computing connectivity for epoch 16
Processing epoch : 17 / 72 (at most)
    computing connectivity for epoch 17
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 18 / 72 (at most)
    computing connectivity for epoch 18
Processing epoch : 19 / 72 (at most)
    computing connectivity for epoch 19
Processing epoch : 20 / 72 (at most)
    computing connectivity for epoch 20
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 21 / 72 (at most)
    computing connectivity for epoch 21
Processing epoch : 22 / 72 (at most)
    computing connectivity for epoch 22
Processing epoch : 23 / 72 (at most)
    computing connectivity for epoch 23
    Rejecting  epoch based on MAG : ['MEG 1711']
Processing epoch : 24 / 72 (at most)
    computing connectivity for epoch 24
Processing epoch : 25 / 72 (at most)
    computing connectivity for epoch 25
Processing epoch : 26 / 72 (at most)
    computing connectivity for epoch 26
Processing epoch : 27 / 72 (at most)
    computing connectivity for epoch 27
Processing epoch : 28 / 72 (at most)
    computing connectivity for epoch 28
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 29 / 72 (at most)
    computing connectivity for epoch 29
Processing epoch : 30 / 72 (at most)
    computing connectivity for epoch 30
Processing epoch : 31 / 72 (at most)
    computing connectivity for epoch 31
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 32 / 72 (at most)
    computing connectivity for epoch 32
Processing epoch : 33 / 72 (at most)
    computing connectivity for epoch 33
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 34 / 72 (at most)
    computing connectivity for epoch 34
Processing epoch : 35 / 72 (at most)
    computing connectivity for epoch 35
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 36 / 72 (at most)
    computing connectivity for epoch 36
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 37 / 72 (at most)
    computing connectivity for epoch 37
Processing epoch : 38 / 72 (at most)
    computing connectivity for epoch 38
Processing epoch : 39 / 72 (at most)
    computing connectivity for epoch 39
Processing epoch : 40 / 72 (at most)
    computing connectivity for epoch 40
Processing epoch : 41 / 72 (at most)
    computing connectivity for epoch 41
Processing epoch : 42 / 72 (at most)
    computing connectivity for epoch 42
Processing epoch : 43 / 72 (at most)
    computing connectivity for epoch 43
Processing epoch : 44 / 72 (at most)
    computing connectivity for epoch 44
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 45 / 72 (at most)
    computing connectivity for epoch 45
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 46 / 72 (at most)
    computing connectivity for epoch 46
Processing epoch : 47 / 72 (at most)
    computing connectivity for epoch 47
Processing epoch : 48 / 72 (at most)
    computing connectivity for epoch 48
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EOG : ['EOG 061']
Processing epoch : 49 / 72 (at most)
    computing connectivity for epoch 49
Processing epoch : 50 / 72 (at most)
    computing connectivity for epoch 50
Processing epoch : 51 / 72 (at most)
    computing connectivity for epoch 51
Processing epoch : 52 / 72 (at most)
    computing connectivity for epoch 52
Processing epoch : 53 / 72 (at most)
    computing connectivity for epoch 53
Processing epoch : 54 / 72 (at most)
    computing connectivity for epoch 54
Processing epoch : 55 / 72 (at most)
    computing connectivity for epoch 55
[done]
[Connectivity computation done]
Frequencies in Hz over which coherence was averaged for alpha:
[ 8.49926873  9.91581352 11.33235831 12.74890309]
Frequencies in Hz over which coherence was averaged for beta:
[14.16544788 15.58199267 16.99853746 18.41508225 19.83162704 21.24817182
 22.66471661 24.0812614  25.49780619 26.91435098 28.33089577 29.74744055]

Generate coherence sources and plot

Finally, we’ll generate a SourceEstimate with the coherence. This is simple since we used a single seed. For more than one seed we would have to choose one of the slices within coh.

Note

We use a hack to save the frequency axis as time.

Finally, we’ll plot this source estimate on the brain.

tmin = np.mean(freqs[0])
tstep = np.mean(freqs[1]) - tmin
coh_stc = mne.SourceEstimate(coh, vertices=stc.vertices, tmin=1e-3 * tmin,
                             tstep=1e-3 * tstep, subject='sample')

# Now we can visualize the coherence using the plot method.
brain = coh_stc.plot('sample', 'inflated', 'both',
                     time_label='Coherence %0.1f Hz',
                     subjects_dir=subjects_dir,
                     clim=dict(kind='value', lims=(0.25, 0.4, 0.65)))
brain.show_view('lateral')
mne inverse coherence epochs

Total running time of the script: ( 0 minutes 25.635 seconds)

Estimated memory usage: 113 MB

Gallery generated by Sphinx-Gallery