1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
|
"""Functions to make simple plot on evoked M/EEG data (besides topographies)
"""
from __future__ import print_function
# Authors: Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>
# Denis Engemann <denis.engemann@gmail.com>
# Martin Luessi <mluessi@nmr.mgh.harvard.edu>
# Eric Larson <larson.eric.d@gmail.com>
# Cathy Nangini <cnangini@gmail.com>
# Mainak Jas <mainak@neuro.hut.fi>
#
# License: Simplified BSD
from itertools import cycle
import numpy as np
from ..io.pick import channel_type
from ..externals.six import string_types
from .utils import _mutable_defaults, _check_delayed_ssp
from .utils import _draw_proj_checkbox, tight_layout
def _plot_evoked(evoked, picks, exclude, unit, show,
ylim, proj, xlim, hline, units,
scalings, titles, axes, plot_type,
cmap=None):
"""Aux function for plot_evoked and plot_evoked_image (cf. docstrings)
Extra param is:
plot_type : str, value ('butterfly' | 'image')
The type of graph to plot: 'butterfly' plots each channel as a line
(x axis: time, y axis: amplitude). 'image' plots a 2D image where
color depicts the amplitude of each channel at a given time point
(x axis: time, y axis: channel). In 'image' mode, the plot is not
interactive.
"""
import matplotlib.pyplot as plt
if axes is not None and proj == 'interactive':
raise RuntimeError('Currently only single axis figures are supported'
' for interactive SSP selection.')
scalings, titles, units = _mutable_defaults(('scalings', scalings),
('titles', titles),
('units', units))
channel_types = set(key for d in [scalings, titles, units] for key in d)
channel_types = sorted(channel_types) # to guarantee consistent order
if picks is None:
picks = list(range(evoked.info['nchan']))
bad_ch_idx = [evoked.ch_names.index(ch) for ch in evoked.info['bads']
if ch in evoked.ch_names]
if len(exclude) > 0:
if isinstance(exclude, string_types) and exclude == 'bads':
exclude = bad_ch_idx
elif (isinstance(exclude, list)
and all([isinstance(ch, string_types) for ch in exclude])):
exclude = [evoked.ch_names.index(ch) for ch in exclude]
else:
raise ValueError('exclude has to be a list of channel names or '
'"bads"')
picks = list(set(picks).difference(exclude))
types = [channel_type(evoked.info, idx) for idx in picks]
n_channel_types = 0
ch_types_used = []
for t in channel_types:
if t in types:
n_channel_types += 1
ch_types_used.append(t)
axes_init = axes # remember if axes where given as input
fig = None
if axes is None:
fig, axes = plt.subplots(n_channel_types, 1)
if isinstance(axes, plt.Axes):
axes = [axes]
elif isinstance(axes, np.ndarray):
axes = list(axes)
if axes_init is not None:
fig = axes[0].get_figure()
if not len(axes) == n_channel_types:
raise ValueError('Number of axes (%g) must match number of channel '
'types (%g)' % (len(axes), n_channel_types))
# instead of projecting during each iteration let's use the mixin here.
if proj is True and evoked.proj is not True:
evoked = evoked.copy()
evoked.apply_proj()
times = 1e3 * evoked.times # time in miliseconds
for ax, t in zip(axes, ch_types_used):
ch_unit = units[t]
this_scaling = scalings[t]
if unit is False:
this_scaling = 1.0
ch_unit = 'NA' # no unit
idx = [picks[i] for i in range(len(picks)) if types[i] == t]
if len(idx) > 0:
# Parameters for butterfly interactive plots
if plot_type == 'butterfly':
if any([i in bad_ch_idx for i in idx]):
colors = ['k'] * len(idx)
for i in bad_ch_idx:
if i in idx:
colors[idx.index(i)] = 'r'
ax._get_lines.color_cycle = iter(colors)
else:
ax._get_lines.color_cycle = cycle(['k'])
# Set amplitude scaling
D = this_scaling * evoked.data[idx, :]
# plt.axes(ax)
if plot_type == 'butterfly':
ax.plot(times, D.T)
elif plot_type == 'image':
im = ax.imshow(D, interpolation='nearest', origin='lower',
extent=[times[0], times[-1], 0, D.shape[0]],
aspect='auto', cmap=cmap)
plt.colorbar(im, ax=ax)
if xlim is not None:
if xlim == 'tight':
xlim = (times[0], times[-1])
ax.set_xlim(xlim)
if ylim is not None and t in ylim:
if plot_type == 'butterfly':
ax.set_ylim(ylim[t])
elif plot_type == 'image':
im.set_clim(ylim[t])
ax.set_title(titles[t] + ' (%d channel%s)' % (
len(D), 's' if len(D) > 1 else ''))
ax.set_xlabel('time (ms)')
if plot_type == 'butterfly':
ax.set_ylabel('data (%s)' % ch_unit)
elif plot_type == 'image':
ax.set_ylabel('channels (%s)' % ch_unit)
else:
raise ValueError("plot_type has to be 'butterfly' or 'image'."
"Got %s." % plot_type)
if (plot_type == 'butterfly') and (hline is not None):
for h in hline:
ax.axhline(h, color='r', linestyle='--', linewidth=2)
if axes_init is None:
plt.subplots_adjust(0.175, 0.08, 0.94, 0.94, 0.2, 0.63)
if proj == 'interactive':
_check_delayed_ssp(evoked)
params = dict(evoked=evoked, fig=fig, projs=evoked.info['projs'],
axes=axes, types=types, units=units, scalings=scalings,
unit=unit, ch_types_used=ch_types_used, picks=picks,
plot_update_proj_callback=_plot_update_evoked,
plot_type=plot_type)
_draw_proj_checkbox(None, params)
if show and plt.get_backend() != 'agg':
plt.show()
fig.canvas.draw() # for axes plots update axes.
tight_layout(fig=fig)
return fig
def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
ylim=None, proj=False, xlim='tight', hline=None, units=None,
scalings=None, titles=None, axes=None, plot_type="butterfly"):
"""Plot evoked data
Note: If bad channels are not excluded they are shown in red.
Parameters
----------
evoked : instance of Evoked
The evoked data
picks : array-like of int | None
The indices of channels to plot. If None show all.
exclude : list of str | 'bads'
Channels names to exclude from being shown. If 'bads', the
bad channels are excluded.
unit : bool
Scale plot with channel (SI) unit.
show : bool
Call pyplot.show() as the end or not.
ylim : dict | None
ylim for plots. e.g. ylim = dict(eeg=[-200e-6, 200e6])
Valid keys are eeg, mag, grad, misc. If None, the ylim parameter
for each channel equals the pyplot default.
xlim : 'tight' | tuple | None
xlim for plots.
proj : bool | 'interactive'
If true SSP projections are applied before display. If 'interactive',
a check box for reversible selection of SSP projection vectors will
be shown.
hline : list of floats | None
The values at which to show an horizontal line.
units : dict | None
The units of the channel types used for axes lables. If None,
defaults to `dict(eeg='uV', grad='fT/cm', mag='fT')`.
scalings : dict | None
The scalings of the channel types to be applied for plotting. If None,`
defaults to `dict(eeg=1e6, grad=1e13, mag=1e15)`.
titles : dict | None
The titles associated with the channels. If None, defaults to
`dict(eeg='EEG', grad='Gradiometers', mag='Magnetometers')`.
axes : instance of Axis | list | None
The axes to plot to. If list, the list must be a list of Axes of
the same length as the number of channel types. If instance of
Axes, there must be only one channel type plotted.
"""
return _plot_evoked(evoked=evoked, picks=picks, exclude=exclude, unit=unit,
show=show, ylim=ylim, proj=proj, xlim=xlim,
hline=hline, units=units, scalings=scalings,
titles=titles, axes=axes, plot_type="butterfly")
def plot_evoked_image(evoked, picks=None, exclude='bads', unit=True, show=True,
clim=None, proj=False, xlim='tight', units=None,
scalings=None, titles=None, axes=None, cmap='RdBu_r'):
"""Plot evoked data as images
Parameters
----------
evoked : instance of Evoked
The evoked data
picks : array-like of int | None
The indices of channels to plot. If None show all.
exclude : list of str | 'bads'
Channels names to exclude from being shown. If 'bads', the
bad channels are excluded.
unit : bool
Scale plot with channel (SI) unit.
show : bool
Call pyplot.show() as the end or not.
clim : dict | None
clim for plots. e.g. clim = dict(eeg=[-200e-6, 200e6])
Valid keys are eeg, mag, grad, misc. If None, the clim parameter
for each channel equals the pyplot default.
xlim : 'tight' | tuple | None
xlim for plots.
proj : bool | 'interactive'
If true SSP projections are applied before display. If 'interactive',
a check box for reversible selection of SSP projection vectors will
be shown.
units : dict | None
The units of the channel types used for axes lables. If None,
defaults to `dict(eeg='uV', grad='fT/cm', mag='fT')`.
scalings : dict | None
The scalings of the channel types to be applied for plotting. If None,`
defaults to `dict(eeg=1e6, grad=1e13, mag=1e15)`.
titles : dict | None
The titles associated with the channels. If None, defaults to
`dict(eeg='EEG', grad='Gradiometers', mag='Magnetometers')`.
axes : instance of Axis | list | None
The axes to plot to. If list, the list must be a list of Axes of
the same length as the number of channel types. If instance of
Axes, there must be only one channel type plotted.
cmap : matplotlib colormap
Colormap.
"""
return _plot_evoked(evoked=evoked, picks=picks, exclude=exclude, unit=unit,
show=show, ylim=clim, proj=proj, xlim=xlim,
hline=None, units=units, scalings=scalings,
titles=titles, axes=axes, plot_type="image",
cmap=cmap)
def _plot_update_evoked(params, bools):
""" update the plot evoked lines
"""
picks, evoked = [params[k] for k in ('picks', 'evoked')]
times = evoked.times * 1e3
projs = [proj for ii, proj in enumerate(params['projs'])
if ii in np.where(bools)[0]]
params['proj_bools'] = bools
new_evoked = evoked.copy()
new_evoked.info['projs'] = []
new_evoked.add_proj(projs)
new_evoked.apply_proj()
for ax, t in zip(params['axes'], params['ch_types_used']):
this_scaling = params['scalings'][t]
idx = [picks[i] for i in range(len(picks)) if params['types'][i] == t]
D = this_scaling * new_evoked.data[idx, :]
if params['plot_type'] == 'butterfly':
[line.set_data(times, di) for line, di in zip(ax.lines, D)]
else:
ax.images[0].set_data(D)
params['fig'].canvas.draw()
|