mne-tools / mne-python

MNE: Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python
https://mne.tools
BSD 3-Clause "New" or "Revised" License
2.7k stars 1.31k forks source link

How to plot a VolSourceEstimate with a discrete source space? #8124

Closed kpauski closed 3 years ago

kpauski commented 4 years ago

I have a pre-defined discrete source space and a corresponding leadfield for the subject, but no MRI data. There is following data for source space with 20001 dipoles:

pos_p: (20001, 3) locations pos_nn: (20001, 3) orientations pos_e: (39998, 3) triangles of the surface

With those I create source space using vol_src = mne.setup_volume_source_space(None, pos={'rr': pos_p, 'nn': pos_nn}, surface = {'rr':pos_p, 'tris': pos_e}) which is of a kind 'discrete'.

Then I have a source estimate data of shape (20001, 2000) and a VolSourceEstimate stc = mne.VolSourceEstimate(data, vertices=np.array(range(20001)), tmin=-1, tstep=0.001)

I try stc.plot(vol_src) and get ValueError: Source space must be volume type, got discrete.

Is there a way to plot a VolSourceEstimate with discrete source space? The source space includes a triangular surface edges, so shouldn't it be possible to plot it as a surface?

agramfort commented 4 years ago

please provide a full code snippet to replicate the error with just a copy paste

larsoner commented 4 years ago

The source space includes a triangular surface edges, so shouldn't it be possible to plot it as a surface?

This must have come from some other software or custom definitions -- if you use MNE's setup_source_space the relationship to the FreeSurfer surfaces is automatically kept track of and you end up with a surface source space.

Is this an option for you?

If not, we can at least probably add basic vector plotting support, but it won't interpolate into a surface mesh properly. Another option is to figure out a way to morph your data onto the standard FreeSurfer surface definition for the subject...

larsoner commented 4 years ago

Looking again, I think there is a misunderstanding. When you do:

vol_src = mne.setup_volume_source_space(..., surface = {'rr':pos_p, 'tris': pos_e})

you are setting the surface within which source space points must exist if setting up a volumetric grid. If you pass pos as a dict specifying positions, it's ignored. Maybe a docstring update would be useful here.

One thing we could do is add support to _Brain to allow passing surface=dict(...) to give the surface to plot onto directly. However, I think something that would probably work better for you is instead mapping your source space data onto the nearest FreeSurfer vertex locations for the given subject. Then many more nice functions will be available for you.

Do you have FreeSurfer reconstructions for your subject(s)?

kpauski commented 4 years ago

Thank you for your answer. Now I understand why it didn't work.

Unfortunately, I don't have FreeSurfer reconstructions of the subject.

larsoner commented 4 years ago

Can you upload your surface(s) and your STC somewhere? I can look into how difficult it is to hack into our _Brain object to allow a custom surface + discrete source space.

larsoner commented 3 years ago

Closing--I think if using non-FreeSurfer data we can't currently help, but at some point if someone uses a discrete source space for example with sample I think we could figure out how to visualize it at least using a VectorSourceEstimate-like vector plot

yuty2009 commented 9 months ago

I encountered exactly the same problem as @kpauski. I have a resting state fMRI time series extracted from the brain areas in AAL atlas, i.e. a data matrix of shape (200, 116). I want to treat the fMRI time series as estimated EEG sources and take advantage of MNE toolbox to do some computation and visualization. So I did the following:

ts = np.random.randn(200, 116) # time series

atlas = nilearn.datasets.fetch_atlas_aal()
atlas_img = nibabel.load(atlas['maps'])
aal_coords = nilearn.plotting.find_parcellation_cut_coords(atlas_img)
pos = {'rr': aal_coords, 'nn': aal_coords}
src = mne.setup_volume_source_space(subject='sample', pos=pos, verbose=True)

vertices = [np.arange(len(aal_coords))]
stc = mne.VolSourceEstimate(ts.T, vertices, tmin=0.0, tstep=1.0, subject='sample')
stc.plot(src)

I got "ValueError: Source space must contain volume type, got discrete" when I tried to plot the source with "stc.plot(src)". While the VolSourceEstimate cannot be plotted with a discrete source space, what can a discrete source space, created by mne.setup_volume_source_space, be used for?

larsoner commented 9 months ago

what can a discrete source space, created by mne.setup_volume_source_space, be used for?

Other operations of *SourceEstimate classes are supported, like cropping and such. And you have access to data and vertices. But indeed discrete source spaces are in generaly a bit limiting.

What I would suggest perhaps you could do instead is figure out how to map the AAL values into a volumetric source space. Basically all values within a given parcel could have the same value. Then you'd be able to plot the data.

Long-term in theory this would be a "label-ized" (or really "atlas-ized") source estimate data that we'd support plotting directly. It's on our roadmap but will be a bit of work. So in the meantime, upsampling the AAL atlas values to a VolSourceEstimate might be the best way to go.

Briefly, I'd try to get the AAL atlas into MGZ-like / FreeSurfer-compatible format for fsaverage so you can use setup_volume_source_space with the volume_label and mri arguments. This would get you a SourceSpaces where len(src) == 200, i.e., has one volume source space for each of the 200 AAL parcels. If you can get that far, we can work through how to create a VolSourceEstimate where the vertices are taken from the SourceSpaces with the data in the right place.