Note2-基于MNE实现脑电源定位的论文级别可视化

摘要

好的可视化能够清楚直观地展示实验结果。脑电(EEG)目前常见的研究往往基于头皮地形图进行可视化,解释层次仅止步于额叶/颞叶/顶叶/枕叶,对于大脑机理的解释粒度较为粗糙。通过源定位+可视化,能够让研究结果更为细腻,展示不同脑区的神经活动表现。本文基于MNE框架实现论文级直接可用的可视化,示例如下图所示。脑区划分方式/colorbar颜色均可自行调整。


环境准备与脑电源定位提取

点击链接参考上一篇博客

可视化代码实现与解析

首先载入必要的库并读取MRI标准头骨。

import mne
import os.path as op
from mne.datasets import fetch_fsaverage
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
# Download fsaverage files
fs_dir = fetch_fsaverage(verbose=True)
subjects_dir = op.dirname(fs_dir)
subject = "fsaverage"

源定位是将头皮的n个电极映射到大脑的m个源,m个源的数量由mne.setup_source_space确定。此处由之前的源定位提取过程实现。由于m个源较多,通常我们使用脑区模板将其整合为p个脑区的分区,便于后续研究脑区功能或者脑网络等。如下为定义与之前提取过程相同的脑区模板annotation与具体的脑区标签label

annotation = 'aparc'
alpha_label = 0.9  # Set the transparency of the color patches

labels = mne.read_labels_from_annot(subject, annotation, subjects_dir=subjects_dir)
labels = [label for label in labels if label.name != 'unknown-lh']

接着设定使用的数据与对应颜色条类型与取值范围。通常情况下数据应该来自于模型或者统计的计算结果。此处为随机化生成。注释部分为使用正负值对比颜色条。此处为使用hot的热力图色条。

data = np.random.randn(68)
norm = plt.Normalize(data.min(), data.max())
cmap = "hot"
# cmap = "RdBu_r"
# data_lim = np.max(np.abs([data.max(),data.min()]))
# norm = colors.TwoSlopeNorm(vmin=-data_lim, vcenter=0, vmax=data_lim)
map_vir = plt.cm.get_cmap(cmap)

接着定义左右脑变量。surf设置是平面展开(flated)还是3d(inflated),背景设置为白色。

brain_lh = mne.viz.Brain(subject, hemi='lh', surf='inflated', subjects_dir=subjects_dir, background='white')
brain_rh = mne.viz.Brain(subject, hemi='rh', surf='inflated', subjects_dir=subjects_dir, background='white')

使用下述代码为每一个脑区label上色。如果某个脑区不显著不想上色可以使用注释部分跳过即可。

for i, (label, value) in enumerate(zip(labels, data)):
    # Get the color based on the data value
    color = map_vir(norm(value))[:3]

    # If you don't want to color certain areas, you can use the following code
    # 
    # if i in [0,1,2,3]:
    #     continue

    if label.hemi == 'lh': 
        brain_lh.add_label(label, color=color, alpha=alpha_label)
    else:
        brain_rh.add_label(label, color=color, alpha=alpha_label)

下述代码添加了分区的线条,如果不想要也可以直接注释掉。

brain_lh.add_annotation(annotation)
brain_rh.add_annotation(annotation)

下述代码设定了具体的拍摄生成图片方式,对于左右脑的内外侧分别进行了快照。并在内侧的下面配上了颜色条。

for view in ['lateral','medial']:
    if view == 'medial':
        colorbar_show = True
    else:
        colorbar_show = False

    fig, axes = plt.subplots(1, 2, figsize=(10, 5))

    # left hemisphere
    brain_lh.show_view(view)  #  ,distance=400
    brain_lh.plotter.off_screen = True
    brain_lh.screenshot(mode='rgb')
    img_lh = brain_lh.plotter.screenshot()
    axes[0].imshow(img_lh)
    axes[0].axis('off')
    # axes[0].set_title('Left Hemisphere')

    # right hemisphere
    brain_rh.show_view(view)
    brain_rh.plotter.off_screen = True
    brain_rh.screenshot(mode='rgb')
    img_rh = brain_rh.screenshot()
    axes[1].imshow(img_rh)
    axes[1].axis('off')
    # axes[1].set_title('Right Hemisphere')

    if colorbar_show:
        sm = plt.cm.ScalarMappable(cmap=map_vir, norm=norm)
        cbar = fig.colorbar(mappable=sm,
                        ax=axes.ravel(),
                        orientation='horizontal',
                        fraction=0.08,
                        pad=0,
                        spacing='uniform',
                        alpha=alpha_label)    # 'vertical', 'horizontal'

        cbar.outline.set_linewidth(0.05)  # Set border width
        cbar.ax.tick_params(labelsize=15)  # Set tick label font size
        cbar.ax.set_title('Sample Title', fontsize=30)

    plt.tight_layout()
    plt.savefig(f"sample_{view}.png")

下述代码关闭两个Brain的可视化界面。

# Close the Brain object
brain_lh.close()
brain_rh.close()

完整代码如下:

import mne
import os.path as op
from mne.datasets import fetch_fsaverage
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors

# Download fsaverage files
fs_dir = fetch_fsaverage(verbose=True)
subjects_dir = op.dirname(fs_dir)
subject = "fsaverage"

annotation = 'aparc'
alpha_label = 0.9
labels = mne.read_labels_from_annot(subject, annotation, subjects_dir=subjects_dir)
labels = [label for label in labels if label.name != 'unknown-lh']


data = np.random.randn(68)
norm = plt.Normalize(data.min(), data.max())
cmap = "hot"
# cmap = "RdBu_r"
# data_lim = np.max(np.abs([data.max(),data.min()]))
# norm = colors.TwoSlopeNorm(vmin=-data_lim, vcenter=0, vmax=data_lim)
map_vir = plt.cm.get_cmap(cmap)


brain_lh = mne.viz.Brain(subject, hemi='lh', surf='inflated', subjects_dir=subjects_dir, background='white')
brain_rh = mne.viz.Brain(subject, hemi='rh', surf='inflated', subjects_dir=subjects_dir, background='white')

for i, (label, value) in enumerate(zip(labels, data)):
    # Get the color based on the data value
    color = map_vir(norm(value))[:3]

    # If you don't want to color certain areas, you can use the following code
    # 
    # if i in [0,1,2,3]:
    #     continue

    if label.hemi == 'lh': 
        brain_lh.add_label(label, color=color, alpha=alpha_label)
    else:
        brain_rh.add_label(label, color=color, alpha=alpha_label)
brain_lh.add_annotation(annotation)
brain_rh.add_annotation(annotation)

for view in ['lateral','medial']:
    if view == 'medial':
        colorbar_show = True
    else:
        colorbar_show = False

    fig, axes = plt.subplots(1, 2, figsize=(10, 5))

    # left hemisphere
    brain_lh.show_view(view)  #  ,distance=400
    brain_lh.plotter.off_screen = True
    brain_lh.screenshot(mode='rgb')
    img_lh = brain_lh.plotter.screenshot()
    axes[0].imshow(img_lh)
    axes[0].axis('off')
    # axes[0].set_title('Left Hemisphere')

    # right hemisphere
    brain_rh.show_view(view)
    brain_rh.plotter.off_screen = True
    brain_rh.screenshot(mode='rgb')
    img_rh = brain_rh.screenshot()
    axes[1].imshow(img_rh)
    axes[1].axis('off')
    # axes[1].set_title('Right Hemisphere')

    if colorbar_show:
        sm = plt.cm.ScalarMappable(cmap=map_vir, norm=norm)
        cbar = fig.colorbar(mappable=sm,
                        ax=axes.ravel(),
                        orientation='horizontal',
                        fraction=0.08,
                        pad=0,
                        spacing='uniform',
                        alpha=alpha_label)    # 'vertical', 'horizontal'

        cbar.outline.set_linewidth(0.05)  # Set border width
        cbar.ax.tick_params(labelsize=15)  # Set tick label font size
        cbar.ax.set_title('Sample Title', fontsize=30)

    plt.tight_layout()
    plt.savefig(f"sample_{view}.png")

# 关闭 Brain 对象
brain_lh.close()
brain_rh.close()

后记

上面就是完整代码啦,希望对各位同学能够有所帮助。感觉有用的话,欢迎给本教程对应的github项目加个星,不胜感激。

如果对于头皮电极图自定义可视化感兴趣,也可以参考我之前的魔改工作。里面也还附了SEED以及Neuroscan最新电极帽的电极数据montage。欢迎自取。

如果有疑问,也欢迎在评论区提问(看的不及时)或者发送邮件至pan_gd@buaa.edu.cn

posted @ 2025-05-28 22:18  BrandonPan  阅读(86)  评论(0)    收藏  举报