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

[ENH] Add "roi" feature to `mne.viz.Brain` #9520

Closed alexrockhill closed 3 years ago

alexrockhill commented 3 years ago

One thing that is nice for plotting in 3D with stereoEEG is to be able to plot ROIs. There is already a surfaces keyword argument in mne.viz.plot_alignment does something similar. We've just added the marching cubes implementation in #9484 so it would be as simple as passing an atlas in the subjects directory, locating the aseg file based on the atlas, running marching cubes which only takes a second at most and then plotting the surface.

A call could look like this:

mne.viz.plot_alignment(raw.info, atlas='desikan-killiany', rois=('hippocampus', 'putamen', 'caudate'))
larsoner commented 3 years ago

I'm inclined instead to improve the Brain interface, where it's easy to plot labels, parcellations, etc. We're adding sensor support there, and you can already combine the figure there with plot_alignment if you want something static.

alexrockhill commented 3 years ago

Sounds good, that's why I raised the issue was to figure out the best way to do that

larsoner commented 3 years ago

Give fig = plot_alignment(...) plus mne.viz.Brain(...figure=fig) a try and see how far you can get!

alexrockhill commented 3 years ago

After thinking about it a bit and looking at the code, what would you think about an mne.viz.plot_rois where the mne.viz.plot_alignment is refactored into helper functions which can be shared. I'm not sure I understand the reason for the complexity of mne.viz.Brain, as I remember it in Pysurfer it was mostly for surface plotting and colormaps which I'm not sure has the best overlap. Just bringing up a suggestion of an idea for how to do this.

larsoner commented 3 years ago

what would you think about an mne.viz.plot_rois where the mne.viz.plot_alignment is refactored into helper functions which can be shared

I would not add a third method that allows plotting brain surfaces. Arguably plot_alignment should already use Brain...

Give fig = plot_alignment(...) plus mne.viz.Brain(...figure=fig) a try and see how far you can get!

Along these lines, what does this not do that you need it to do? (Just using fnirs data here because it's the quickest route to "electrodes" in MNI coords):

import mne
subjects_dir = mne.datasets.sample.data_path() + '/subjects'
raw = mne.io.read_raw_nirx(mne.datasets.fnirs_motor.data_path() + '/Participant-1')
fig = mne.viz.plot_alignment(
    raw.info, subject='fsaverage', trans='fsaverage', fnirs=True, dig=True,
    mri_fiducials=True, surfaces=dict(head=0.1), coord_frame='mri')
brain = mne.viz.Brain(
    'fsaverage', 'both', 'pial', subjects_dir=subjects_dir, figure=fig,
    units='m', alpha=0.2, cortex='low_contrast')
brain.add_annotation('aparc.a2009s', borders=False)

Screenshot from 2021-07-15 15-47-28

I cooked this up in about 2 minutes, and already it does a lot of stuff. I would not want to write a function to replicate all these options, and if we tried to make a simple one, inevitably people would want some of the above stuff... for example with Brain you can soon just do add_aseg(...) to get what you want. FYI there is also #8803 to someday add sensors to brain, too.

TL;DR: plot_alignment is good for managing dig + electrode locations + coord frames, let it do that; Brain is good for visualizing brain stuff, let it do that

alexrockhill commented 3 years ago
import mne
subjects_dir = mne.datasets.sample.data_path() + '/subjects'
raw = mne.io.read_raw_nirx(mne.datasets.fnirs_motor.data_path() + '/Participant-1')
fig = mne.viz.plot_alignment(
    raw.info, subject='fsaverage', trans='fsaverage', fnirs=True, dig=True,
    mri_fiducials=True, surfaces=dict(head=0.1), coord_frame='mri')
brain = mne.viz.Brain(
    'fsaverage', 'both', 'pial', subjects_dir=subjects_dir, figure=fig,
    units='m', alpha=0.2, cortex='low_contrast')
brain.add_annotation('aparc.a2009s', borders=False)

Awesome, I'm totally on the same page, it would be nice to have brain as a context manager in a pyplot/pyvista sort of way that you can call plotting functions from it without having to pass the subject and subjects_dir twice which I think makes the above example clunky. Looking at mne.viz.Brain it seems a bit complicated with iter_views and their dependency on hemi but maybe that will get refactored a bit.

larsoner commented 3 years ago

For now let's keep it simple and just pass subject and subjects dir, even if it's a bit clunky

alexrockhill commented 3 years ago

Sounds good to me, looking forward to the stable version of mne.viz.Brain