注意
转到末尾下载完整示例代码。
可视化分段数据(Epochs)#
本教程展示如何将分段(epoch)数据绘制为时间序列、如何绘制分段数据的频谱密度、如何将 Epochs 绘制为图像映射,以及如何绘制存储在 Epochs 对象中的传感器位置和投影器。
我们先导入所需的模块、加载连续(原始)示例数据,并对其进行裁剪以节省内存:
# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
import mne
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = sample_data_folder / "MEG" / "sample" / "sample_audvis_raw.fif"
raw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False).crop(tmax=120)
为了创建 Epochs 数据结构,我们会提取存储在 stim 通道中的事件 ID,使用事件字典将这些整数事件 ID 映射为更具描述性的条件标签,然后将其连同 Raw 数据以及所需的 Epoch 时间范围 tmin 和 tmax 一起传给 Epochs 构造函数(这些步骤的详细说明见 Epochs 数据结构:不连续数据)。
events = mne.find_events(raw, stim_channel="STI 014")
event_dict = {
"auditory/left": 1,
"auditory/right": 2,
"visual/left": 3,
"visual/right": 4,
"face": 5,
"button": 32,
}
epochs = mne.Epochs(raw, events, tmin=-0.2, tmax=0.5, event_id=event_dict, preload=True)
del raw
Finding events on: STI 014
176 events found on stim channel STI 014
Event IDs: [ 1 2 3 4 5 32]
Not setting metadata
176 matching events found
Setting baseline interval to [-0.19979521315838786, 0.0] s
Applying baseline correction (mode: mean)
Created an SSP operator (subspace dimension = 3)
3 projection items activated
Loading data for 176 events and 421 original time points ...
1 bad epochs dropped
将 Epochs 绘制为时间序列#
要将分段数据可视化为时间序列(每个通道一条时间序列),可以使用 mne.Epochs.plot 方法。它会创建一个交互式窗口,你可以在其中滚动浏览各个 Epoch 和通道,启用或禁用尚未应用的 SSP 投影器以查看它们对信号的影响,甚至可以手动标记坏道(点击通道名称)或坏 Epoch(点击数据),以便稍后剔除。标记为“坏”的通道会以浅灰色显示,并会被添加到 epochs.info['bads'];标记为坏的 Epoch 会在 epochs.drop_log 中记为 'USER'。
这里我们只绘制示例数据集中的“catch”试次,并传入 events 数组,以便同时标记按键反应(我们会将其绘制为红色,并将定义每个 Epoch 时间零点的“face”事件绘制为蓝色)。还需要传入 event_dict,这样 plot 方法才知道“button”指的是什么——这是因为通过调用 epochs['face'] 对条件取子集时,会自动从 epochs.event_id 中清除已被剔除的条目:
catch_trials_and_buttonpresses = mne.pick_events(events, include=[5, 32])
epochs["face"].plot(
events=catch_trials_and_buttonpresses,
event_id=event_dict,
event_color=dict(button="red", face="blue"),
)

要同时查看所有传感器,我们可以使用蝴蝶模式并按选择分组:
epochs["face"].plot(
events=catch_trials_and_buttonpresses,
event_id=event_dict,
event_color=dict(button="red", face="blue"),
group_by="selection",
butterfly=True,
)
绘制 Epochs 对象中的投影器#
在上面的图中,我们可以看到磁强计通道中存在心跳伪迹,因此在继续之前,我们先从磁盘加载 ECG 投影器并将其应用到数据上:
ecg_proj_file = sample_data_folder / "MEG" / "sample" / "sample_audvis_ecg-proj.fif"
ecg_projs = mne.read_proj(ecg_proj_file)
epochs.add_proj(ecg_projs)
epochs.apply_proj()
Read a total of 6 projection items:
ECG-planar-999--0.200-0.400-PCA-01 (1 x 203) idle
ECG-planar-999--0.200-0.400-PCA-02 (1 x 203) idle
ECG-axial-999--0.200-0.400-PCA-01 (1 x 102) idle
ECG-axial-999--0.200-0.400-PCA-02 (1 x 102) idle
ECG-eeg-999--0.200-0.400-PCA-01 (1 x 59) idle
ECG-eeg-999--0.200-0.400-PCA-02 (1 x 59) idle
6 projection items deactivated
Created an SSP operator (subspace dimension = 9)
9 projection items activated
SSP projectors applied...
正如我们在 Plotting projectors from Raw objects 一节中所见,可以使用相同的 plot_projs_topomap 方法绘制 Epochs 对象中存在的投影器。原有的三个空房间磁强计投影器继承自 Raw 文件,而我们又为每种传感器类型添加了两个 ECG 投影器,因此应该会看到九个投影器地形图:
epochs.plot_projs_topomap(vlim="joint")

注意,这些场图展示的是已经被移除的信号成分(因为在对数据分段时,Raw 数据中的投影器默认会被应用;而且我们在从文件添加额外的 ECG 投影器后调用了 apply_proj)。你可以通过查看投影器的 'active' 字段来验证这一点:
print(all(proj["active"] for proj in epochs.info["projs"]))
True
绘制传感器位置#
与 Raw 对象一样,Epochs 对象也会记录传感器位置,可以使用 plot_sensors 方法将其可视化:
epochs.plot_sensors(kind="3d", ch_type="all")
epochs.plot_sensors(kind="topomap", ch_type="all")
绘制 Epochs 的功率谱#
同样,与 Raw 对象一样,Epochs 对象可以通过 compute_psd() 转换为频谱密度,然后用 EpochsSpectrum 的 plot() 方法绘制。
epochs["auditory"].compute_psd().plot(picks="eeg", exclude="bads", amplitude=False)

Using multitaper spectrum estimation with 7 DPSS windows
Plotting power spectral density (dB=True).
Averaging across epochs before plotting...
还可以使用 EpochsSpectrum 的 plot_topomap() 方法,将各传感器的频谱功率估计绘制为头皮地形图。默认参数会绘制五个频带(δ、θ、α、β、γ),基于磁强计通道(如果存在)计算功率,并以类似 dB 的对数尺度绘制功率估计:
spectrum = epochs["visual/right"].compute_psd()
spectrum.plot_topomap()

Using multitaper spectrum estimation with 7 DPSS windows
Averaging across epochs before plotting...
注意
在引入 EpochsSpectrum 类之前,上述图形可以通过以下方式绘制:
Epochs 对象的 plot_psd() 和 plot_psd_topomap 方法仍然保留,以支持旧版分析脚本,但新代码应改用 EpochsSpectrum 对象的 API。
与 plot_projs_topomap 一样,EpochsSpectrum.plot_topomap() 具有 vlim='joint' 选项,可在所有子图之间统一固定颜色条的范围,从而更好地反映各频带的相对幅度。你可以通过 ch_type 参数更改所使用的通道类型;如果想查看不同于默认值的频带,bands 参数接受一个 dict,其键提供子图标题,值提供要绘制的单个频点,或频带的下边界/上边界:
bands = {"10 Hz": 10, "15 Hz": 15, "20 Hz": 20, "10-20 Hz": (10, 20)}
spectrum.plot_topomap(bands=bands, vlim="joint", ch_type="grad")

Averaging across epochs before plotting...
如果你希望使用未变换的功率估计,可以传入 dB=False。还可以通过传入 normalize=True,将功率估计除以所有频率上的总功率来进行归一化。详情请参阅 plot_topomap 的文档字符串。
将 Epochs 绘制为图像映射#
同时可视化多个 Epoch 的一种便捷方法是将其绘制为图像映射:图像中的每一行像素代表一个 Epoch,水平轴代表时间,每个像素的颜色代表该 Epoch 在该时间采样点上的信号值。当然,这需要为每个通道分别绘制一幅图像映射,或者需要某种跨通道组合信息的方法。后者可以使用 plot_image 方法实现;前者可以通过 plot_image 方法(一次一个通道)或 plot_topo_image 方法(同时显示所有传感器)实现。
默认情况下,plot_image 生成的图像映射会附带一个比例尺,用于指示颜色映射的范围,并显示一条时间序列,表示跨 Epoch 的平均信号及其围绕均值的自助法(bootstrap)95% 置信带。plot_image 是一个高度可定制的方法,具有许多参数,包括对辅助颜色条和平均时间序列子图的定制。完整细节请参阅 plot_image 和 mne.viz.plot_compare_evokeds(用于绘制平均时间序列)的文档字符串。这里我们将展示所有带有听觉刺激的 Epoch 在磁强计上的平均值:
epochs["auditory"].plot_image(picks="mag", combine="mean")

Not setting metadata
81 matching events found
No baseline correction applied
0 projection items activated
combining channels using "mean"
要为单个传感器或一小组传感器绘制图像映射,可使用 picks 参数。传入 combine=None(默认值)会为 picks 中的每个传感器分别绘制图形;传入 combine='gfp' 则会绘制全局场强(global field power),适合组合那些响应极性相反的传感器。
Not setting metadata
81 matching events found
No baseline correction applied
0 projection items activated
Not setting metadata
81 matching events found
No baseline correction applied
0 projection items activated
Not setting metadata
81 matching events found
No baseline correction applied
0 projection items activated
combining channels using RMS (grad channels)
要为所有传感器绘制图像映射,请使用 plot_topo_image,它针对同时绘制大量图像映射进行了优化,并且(在交互式会话中)允许你点击每个小图像映射,弹出一个单独的图形窗口显示完整尺寸的图像(相当于仅对该传感器调用 plot_image)。在本教程所示的较小尺度下,很难从这些图中看清有用的细节;在交互绘图时,通常最好将拓扑图像图最大化到全屏。默认图形为黑色背景,因此这里我们指定白色背景和黑色前景文字。默认情况下,plot_topo_image 会在同一幅图中显示磁强计和梯度计(因此不显示颜色条,因为这些传感器的尺度不同),所以我们还会传入一个 Layout,将每幅图限制为一种通道类型。不过,首先我们还要剔除那些信号水平异常高的 Epoch,因为它们会使颜色映射的范围过于极端,从而掩盖我们感兴趣的较小信号波动。
reject_criteria = dict(
mag=3000e-15, # 3000 fT
grad=3000e-13, # 3000 fT/cm
eeg=150e-6,
) # 150 µV
epochs.drop_bad(reject=reject_criteria)
for ch_type, title in dict(mag="Magnetometers", grad="Gradiometers").items():
layout = mne.channels.find_layout(epochs.info, ch_type=ch_type)
epochs["auditory/left"].plot_topo_image(
layout=layout, fig_facecolor="w", font_color="k", title=title
)
Rejecting epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 004', 'EEG 005', 'EEG 006', 'EEG 007', 'EEG 015', 'EEG 016', 'EEG 023', 'EEG 039', 'EEG 041', 'EEG 044', 'EEG 045', 'EEG 046', 'EEG 047', 'EEG 048', 'EEG 049', 'EEG 050', 'EEG 051', 'EEG 052', 'EEG 054', 'EEG 055', 'EEG 056', 'EEG 057', 'EEG 058', 'EEG 059']
Rejecting epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 007', 'EEG 048', 'EEG 055']
Rejecting epoch based on EEG : ['EEG 007']
Rejecting epoch based on EEG : ['EEG 003', 'EEG 007']
Rejecting epoch based on MAG : ['MEG 1711']
Rejecting epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 007']
Rejecting epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 007']
Rejecting epoch based on MAG : ['MEG 1711']
8 bad epochs dropped
要为所有 EEG 传感器绘制图像映射,请将 EEG 的 layout 作为 plot_topo_image 的 layout 参数传入。这里还需注意 sigma 参数的使用,它会沿垂直方向(跨 Epoch)对每幅图像映射进行平滑,这有助于在众多小图像映射中看清模式(通过将噪声较大的 Epoch 涂抹到相邻 Epoch 上,同时强化相邻 Epoch 相似的区域)。然而,sigma 也可能掩盖那些持续存在极端值、本应被剔除的 Epoch,因此应谨慎使用。
layout = mne.channels.find_layout(epochs.info, ch_type="eeg")
epochs["auditory/left"].plot_topo_image(
layout=layout, fig_facecolor="w", font_color="k", sigma=1
)

脚本总运行时间:(0 分钟 9.897 秒)








