list of virtual sensors per parcel

  • MNE version: 1.6.1
    -OS: MacOS sonoma 14.4.1

Hello everyone,

I am working with MEG data and epochs. After a typical preprocessing, I created the stc object using dSPM (not relevant).

inv = mne.minimum_norm.make_inverse_operator(info=raw.info,
forward=forward,
noise_cov=noise_cov,
loose=‘auto’,
depth=0.8,
fixed=‘auto’,
rank=None,
use_cps=True
)

stc = mne.minimum_norm.apply_inverse_epochs(epochs = epochs,
inverse_operator = inv,
lambda2 = lambda2,
method = method
)

everything works perfectly. Then I use the parcel (Schaefers200) with the method mean_flip:
sub_labels = mne.read_labels_from_annot(‘fsaverage’,parc = parc_met,
subjects_dir=mri_subj_dir)

subject_labels = mne.morph_labels(sub_labels, subject_to = pnum_subj,
subjects_dir = mri_subj_dir)

mne.write_labels_to_annot(subject_labels, subject = pnum_subj,
parc=parc_met, subjects_dir = mri_subj_dir,
overwrite=True)

stc_parcels = mne.extract_label_time_course(labels = subject_labels, src = src, stcs = stc, mode=‘mean_flip’)

a few questions:

1: the plot of stc has some negative time course (why?)
2: if I want to know what virtual sensor are inside a parcel, I found this association of virtual sensors and vertices: vertices_id_lh = inv[‘src’][0][‘vertno’]
Is it correct?

3: if yes to 2 I reversed the info to grab the virtual sensors in vertices_id_lh from sub_labels[parcel_index].vertices.
The problem is that if I plot the average of the activity of the time series of the virtual sensors obtained this way, I have a different plot with respect to this plot:
plt.plot(stc[epoch_index].times,stc_parcels[epoch_index][parcel_index].T)

why?

Thanks a lot in advance,

Ivano

Hi Ivano,

There are a couple of reasons for this. So starting with - neural activity is always positive - why do the source estimates go negative. 1) Since you have neural activity that is always positive - as soon as you apply a high-pass filter or DC-offset your data, you reset the average of your data to approximately zero. So now average neural firing activity is defined as zero and less than average activity is represented as negative. 2) Minimum norm style source localization is a fancy regression of the recorded data onto the forward model. The forward model incorporates an orientation of the source. If you are using the cortical orientation as a prior - on the two sides of a cortical fold, you will have the pyramidal neurons pointing in opposite directions. So when you regress the data on the forward model output it can be explained as either a positive signal on the one side or equally likely as a negative signal on the other side. That is why you get the banding pattern on the inflated surface. The ‘mean-flip’ operation might take care of some of this - but it does not resolve the issue in point1.
Some of this is explained here: The role of dipole orientations in distributed source localization — MNE 1.7.0 documentation

The stc vertices are based on the original freesurfer volume. So inv.vertices[0] is a ~4000 length vector, but the values go up to 150,000 - which is referencing the original freesurfer vertex.

Here is the code to match up the parcel vertices and the source vertices, from def _hemilabel_stc(self, label) in the source_estimate.py file.

        # find index of the Label's vertices
        idx = np.nonzero(np.isin(stc_vertices, label.vertices))[0]

        # find output vertices
        vertices = stc_vertices[idx]

–Jeff

1 Like

Thanks, Jeff, for your precise reply.

Regarding my first question, I believe your point #2 is correct (#1 is not applicable to my case, as I have oscillations that are both positive and negative - what is entirely positive is the dSPM solution).

Concerning my second question, with your help, I managed to find that my code was wrong (though I still have no idea why). Now, the plot of the parcel (mean_flip) and the plot obtained using a ‘handmade’ average of the virtual sensors in a parcel are almost identical. I’m still not sure why they’re not perfectly identical, but at least the list of virtual sensors is correct.

just a quick update: For some of the parcels, ‘mean_flip’ is still giving me weird plots. I think the function might be getting rid of some outliers, or perhaps the ‘flip’ operation is adding negative values to the average. I’m not sure.