def _construct_topo_side(info, kwargs): from mne.viz.topomap import _check_outlines, _find_topomap_coords radius = 0.5 ll = np.linspace(0, 2 * np.pi, 101) head_x = np.cos(ll) * radius head_y = np.sin(ll) * radius mask_outlines = np.c_[head_x, head_y] below_zero = mask_outlines[:, 0] < 0 removed_len = below_zero.sum() filling = np.zeros((removed_len, 2)) filling[:, 1] = np.linspace(0.5, -0.5, num=removed_len) mask_outlines[below_zero, :] = filling head_pos = dict(center=(0., 0.)) picks = range(len(info['ch_names'])) pos = _find_topomap_coords(info, picks=picks) # TODO currently uses outlines='head', but should change later pos, outlines = _check_outlines(pos, outlines='head', head_pos=head_pos) outlines['mask_pos'] = (mask_outlines[:, 0], mask_outlines[:, 1]) kwargs.update(dict(outlines=outlines, head_pos=head_pos)) # scale pos to min - max of the circle scale_x = 0.425 / pos[:, 0].max() scale_y = 0.425 / np.abs(pos[:, 1]).max() pos[:, 0] *= scale_x pos[:, 1] *= scale_y info = pos return info, kwargs
def __init__(self, url=None): super().__init__() if url is None: ws_url = "ws://localhost:7777" else: ws_url = url self.setWindowTitle("Contact Impedance") self.ws_imp = WS_Imp(contact_plot=self, url=ws_url) self.timer_interval = 0.5 self.ch_label = list() gs_kw = dict(width_ratios=[30,1], height_ratios=[1]) self.fig, (self.ax, self.ax2) = plt.subplots(1, 2, gridspec_kw=gs_kw) self.canvas = FigureCanvas(self.fig) self.pos = list(channel_dict_2D.values()) # get all X,Y values self.ch_names_ = list(channel_dict_2D.keys()) # get all channel's names self.pos, self.outlines = topomap._check_outlines(self.pos, 'head') # from mne.viz libs, normalize the pos self.cm = plt.cm.get_cmap('RdYlGn_r') self.norm = mpl.colors.Normalize(vmin=0, vmax=2000) self.colorbar = ColorbarBase(self.ax2, cmap=self.cm, norm=self.norm, ticks=[0, 500, 1000, 1500, 2000]) self.colorbar.set_ticklabels(['0 KOhm','500', '1000', '1500', '2000']) while len(self.ch_label) is 0: pass self.plt_idx = [self.ch_names_.index(name) for name in self.ch_label] # get the index of those required channels self.ch_table = QtGui.QTableWidget(len(self.ch_label), 2, parent=self) item = QtGui.QTableWidgetItem("Channel") self.ch_table.setHorizontalHeaderItem (0, item) item = QtGui.QTableWidgetItem("Impedance (KOhm)") self.ch_table.setHorizontalHeaderItem (1, item) self.draw(self.ch_label, [0]*len(self.ch_label)) header = self.ch_table.horizontalHeader() header.setResizeMode(QtGui.QHeaderView.ResizeToContents) header.setStretchLastSection(True) hlayout = QtGui.QHBoxLayout(self) hlayout.addWidget(self.canvas) hlayout.addWidget(self.ch_table) self.setup_signal_handler() self.show() self.value = 0
def init_ui(self): self.cmap = mpl.cm.get_cmap('Dark2') self.norm = mpl.colors.Normalize(vmin=0, vmax=8) self.fig, (self.axes) = plt.subplots(len(self.ws_data.ch_label) + 2, 1) self.colorbar = ColorbarBase(self.axes[-1], cmap=self.cmap, norm=self.norm, ticks=[i + 0.5 for i in range(8)]) self.colorbar.set_ticklabels([ 'Delta (1-3 Hz)', 'Theta (4-7 Hz)', 'Low Alpha (8-10 Hz)', 'High Alpha (11-12 Hz)', 'Low Beta (13-15 Hz)', 'Mid Beta (16-19 Hz)', 'High Beta (20-35 Hz)', 'Gamma (36-50 Hz)' ]) self.canvas = FigureCanvas(self.fig) self.pos = list(channel_dict_2D.values()) # get all X,Y values self.ch_names_ = list( channel_dict_2D.keys()) # get all channel's names self.pos, self.outlines = topomap._check_outlines( self.pos, 'head') # from mne.viz libs, normalize the pos topomap._draw_outlines(self.axes[0], self.outlines) self.plt_idx = [ self.ch_names_.index(name) for name in self.ws_data.ch_label ] # get the index of those required channels ch_pos = [self.pos[idx] * 5 / 6 for idx in self.plt_idx] for idx, pos in enumerate(ch_pos): pos += [0.47, 0.47] self.axes[idx + 1].set_position(list(pos) + [0.06, 0.06]) self.axes[idx + 1].axis("off") self.axes[idx + 1].grid(True, axis='y') self.axes[0].set_position([0, 0, 1, 1]) self.axes[-1].set_position([0.80, 0.85, 0.03, 0.13]) self.resize(1000, 800) hlayout = QtGui.QHBoxLayout(self) hlayout.addWidget(self.canvas)
def _plot_topomap(data, pos, vmin=None, vmax=None, cmap=None, sensors=True, res=64, axes=None, names=None, show_names=False, mask=None, mask_params=None, outlines='head', contours=6, image_interp='bilinear', show=True, head_pos=None, onselect=None, extrapolate='box', border=0): import matplotlib.pyplot as plt from matplotlib.widgets import RectangleSelector data = np.asarray(data) if isinstance(pos, Info): # infer pos from Info object picks = _pick_data_channels(pos) # pick only data channels pos = pick_info(pos, picks) # check if there is only 1 channel type, and n_chans matches the data ch_type = {channel_type(pos, idx) for idx, _ in enumerate(pos["chs"])} info_help = ("Pick Info with e.g. mne.pick_info and " "mne.io.pick.channel_indices_by_type.") if len(ch_type) > 1: raise ValueError("Multiple channel types in Info structure. " + info_help) elif len(pos["chs"]) != data.shape[0]: raise ValueError("Number of channels in the Info object and " "the data array does not match. " + info_help) else: ch_type = ch_type.pop() if any(type_ in ch_type for type_ in ('planar', 'grad')): # deal with grad pairs from mne.channels.layout import (_merge_grad_data, find_layout, _pair_grad_sensors) picks, pos = _pair_grad_sensors(pos, find_layout(pos)) data = _merge_grad_data(data[picks]).reshape(-1) else: picks = list(range(data.shape[0])) pos = _find_topomap_coords(pos, picks=picks) if data.ndim > 1: raise ValueError("Data needs to be array of shape (n_sensors,); got " "shape %s." % str(data.shape)) # Give a helpful error message for common mistakes regarding the position # matrix. pos_help = ("Electrode positions should be specified as a 2D array with " "shape (n_channels, 2). Each row in this matrix contains the " "(x, y) position of an electrode.") if pos.ndim != 2: error = ("{ndim}D array supplied as electrode positions, where a 2D " "array was expected").format(ndim=pos.ndim) raise ValueError(error + " " + pos_help) elif pos.shape[1] == 3: error = ("The supplied electrode positions matrix contains 3 columns. " "Are you trying to specify XYZ coordinates? Perhaps the " "mne.channels.create_eeg_layout function is useful for you.") raise ValueError(error + " " + pos_help) # No error is raised in case of pos.shape[1] == 4. In this case, it is # assumed the position matrix contains both (x, y) and (width, height) # values, such as Layout.pos. elif pos.shape[1] == 1 or pos.shape[1] > 4: raise ValueError(pos_help) if len(data) != len(pos): raise ValueError("Data and pos need to be of same length. Got data of " "length %s, pos of length %s" % (len(data), len(pos))) norm = min(data) >= 0 vmin, vmax = _setup_vmin_vmax(data, vmin, vmax, norm) if cmap is None: cmap = 'Reds' if norm else 'RdBu_r' pos, outlines = _check_outlines(pos, outlines, head_pos) assert isinstance(outlines, dict) ax = axes if axes else plt.gca() _prepare_topomap(pos, ax) _use_default_outlines = any(k.startswith('head') for k in outlines) if _use_default_outlines: # prepare masking _autoshrink(outlines, pos, res) mask_params = _handle_default('mask_params', mask_params) # find mask limits xlim = np.inf, -np.inf, ylim = np.inf, -np.inf, mask_ = np.c_[outlines['mask_pos']] xmin, xmax = (np.min(np.r_[xlim[0], mask_[:, 0]]), np.max(np.r_[xlim[1], mask_[:, 0]])) ymin, ymax = (np.min(np.r_[ylim[0], mask_[:, 1]]), np.max(np.r_[ylim[1], mask_[:, 1]])) # interpolate the data, we multiply clip radius by 1.06 so that pixelated # edges of the interpolated image would appear under the mask head_radius = (None if extrapolate == 'local' else outlines['clip_radius'][0] * 1.06) xi = np.linspace(xmin, xmax, res) yi = np.linspace(ymin, ymax, res) Xi, Yi = np.meshgrid(xi, yi) interp = _GridData(pos, extrapolate, head_radius, border).set_values(data) Zi = interp.set_locations(Xi, Yi)() # plot outline patch_ = None if 'patch' in outlines: patch_ = outlines['patch'] patch_ = patch_() if callable(patch_) else patch_ patch_.set_clip_on(False) ax.add_patch(patch_) ax.set_transform(ax.transAxes) ax.set_clip_path(patch_) if _use_default_outlines: from matplotlib import patches patch_ = patches.Ellipse((0, 0), 2 * outlines['clip_radius'][0], 2 * outlines['clip_radius'][1], clip_on=True, transform=ax.transData) # plot interpolated map im = ax.imshow(Zi, cmap=cmap, vmin=vmin, vmax=vmax, origin='lower', aspect='equal', extent=(xmin, xmax, ymin, ymax), interpolation=image_interp) # This tackles an incomprehensible matplotlib bug if no contours are # drawn. To avoid rescalings, we will always draw contours. # But if no contours are desired we only draw one and make it invisible. linewidth = mask_params['markeredgewidth'] no_contours = False if isinstance(contours, (np.ndarray, list)): pass # contours precomputed elif contours == 0: contours, no_contours = 1, True if (Zi == Zi[0, 0]).all(): cont = None # can't make contours for constant-valued functions else: with warnings.catch_warnings(record=True): warnings.simplefilter('ignore') cont = ax.contour(Xi, Yi, Zi, contours, colors='k', linewidths=linewidth / 2.) if no_contours and cont is not None: for col in cont.collections: col.set_visible(False) if patch_ is not None: im.set_clip_path(patch_) if cont is not None: for col in cont.collections: col.set_clip_path(patch_) pos_x, pos_y = pos.T if sensors is not False and mask is None: _plot_sensors(pos_x, pos_y, sensors=sensors, ax=ax) elif sensors and mask is not None: idx = np.where(mask)[0] ax.plot(pos_x[idx], pos_y[idx], **mask_params) idx = np.where(~mask)[0] _plot_sensors(pos_x[idx], pos_y[idx], sensors=sensors, ax=ax) elif not sensors and mask is not None: idx = np.where(mask)[0] ax.plot(pos_x[idx], pos_y[idx], **mask_params) if isinstance(outlines, dict): _draw_outlines(ax, outlines) if show_names: if names is None: raise ValueError("To show names, a list of names must be provided" " (see `names` keyword).") if show_names is True: def _show_names(x): return x else: _show_names = show_names show_idx = np.arange(len(names)) if mask is None else np.where(mask)[0] for ii, (p, ch_id) in enumerate(zip(pos, names)): if ii not in show_idx: continue ch_id = _show_names(ch_id) ax.text(p[0], p[1], ch_id, horizontalalignment='center', verticalalignment='center', size='x-small') if onselect is not None: ax.RS = RectangleSelector(ax, onselect=onselect) plt_show(show) return im, cont, interp, patch_
def test_plot_topomap(): """Test topomap plotting.""" import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter('always') res = 8 fast_test = {"res": res, "contours": 0, "sensors": False} evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) # Test animation _, anim = evoked.animate_topomap(ch_type='grad', times=[0, 0.1], butterfly=False) anim._func(1) # _animate has to be tested separately on 'Agg' backend. plt.close('all') ev_bad = evoked.copy().pick_types(meg=False, eeg=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) plt_topomap = partial(ev_bad.plot_topomap, **fast_test) plt_topomap(times=ev_bad.times[:2] - 1e-6) # auto, plots EEG assert_raises(ValueError, plt_topomap, ch_type='mag') assert_raises(TypeError, plt_topomap, head_pos='foo') assert_raises(KeyError, plt_topomap, head_pos=dict(foo='bar')) assert_raises(ValueError, plt_topomap, head_pos=dict(center=0)) assert_raises(ValueError, plt_topomap, times=[-100]) # bad time assert_raises(ValueError, plt_topomap, times=[[0]]) # bad time evoked.plot_topomap([0.1], ch_type='eeg', scalings=1, res=res, contours=[-100, 0, 100]) plt_topomap = partial(evoked.plot_topomap, **fast_test) plt_topomap(0.1, layout=layout, scalings=dict(mag=0.1)) plt.close('all') axes = [plt.subplot(221), plt.subplot(222)] plt_topomap(axes=axes, colorbar=False) plt.close('all') plt_topomap(times=[-0.1, 0.2]) plt.close('all') evoked_grad = evoked.copy().crop(0, 0).pick_types(meg='grad') mask = np.zeros((204, 1), bool) mask[[0, 3, 5, 6]] = True names = [] def proc_names(x): names.append(x) return x[4:] evoked_grad.plot_topomap(ch_type='grad', times=[0], mask=mask, show_names=proc_names, **fast_test) assert_equal(sorted(names), ['MEG 011x', 'MEG 012x', 'MEG 013x', 'MEG 014x']) mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True plt_topomap(ch_type='mag', outlines=None) times = [0.1] plt_topomap(times, ch_type='grad', mask=mask) plt_topomap(times, ch_type='planar1') plt_topomap(times, ch_type='planar2') plt_topomap(times, ch_type='grad', mask=mask, show_names=True, mask_params={'marker': 'x'}) plt.close('all') assert_raises(ValueError, plt_topomap, times, ch_type='eeg', average=-1e3) assert_raises(ValueError, plt_topomap, times, ch_type='eeg', average='x') p = plt_topomap(times, ch_type='grad', image_interp='bilinear', show_names=lambda x: x.replace('MEG', '')) subplot = [ x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot) ][0] assert_true( all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Plot array for ch_type in ('mag', 'grad'): evoked_ = evoked.copy().pick_types(eeg=False, meg=ch_type) plot_topomap(evoked_.data[:, 0], evoked_.info, **fast_test) # fail with multiple channel types assert_raises(ValueError, plot_topomap, evoked.data[0, :], evoked.info) # Test title def get_texts(p): return [ x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text) ] p = plt_topomap(times, ch_type='eeg', average=0.01) assert_equal(len(get_texts(p)), 0) p = plt_topomap(times, ch_type='eeg', title='Custom') texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter('always') plt_topomap(times, ch_type='mag', layout=None) assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive') # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter('always') fig1 = evoked.plot_topomap('interactive', 'mag', proj='interactive', **fast_test) _fake_click(fig1, fig1.axes[1], (0.5, 0.5)) # click slider data_max = np.max(fig1.axes[0].images[0]._A) fig2 = plt.gcf() _fake_click(fig2, fig2.axes[0], (0.075, 0.775)) # toggle projector # make sure projector gets toggled assert_true(np.max(fig1.axes[0].images[0]._A) != data_max) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos[:, :2] pos, outlines = _check_outlines(pos, 'head') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.5) pos, outlines = _check_outlines(pos, 'skirt') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(not outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.625) pos, outlines = _check_outlines(pos, 'skirt', head_pos={'scale': [1.2, 1.2]}) assert_array_equal(outlines['clip_radius'], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type='eeg', outlines='skirt', **fast_test) # Pass custom outlines without patch evoked.plot_topomap(times, ch_type='eeg', outlines=outlines, **fast_test) plt.close('all') # Test interactive cmap fig = plot_evoked_topomap(evoked, times=[0., 0.1], ch_type='eeg', cmap=('Reds', True), title='title', **fast_test) fig.canvas.key_press_event('up') fig.canvas.key_press_event(' ') fig.canvas.key_press_event('down') cbar = fig.get_axes()[0].CB # Fake dragging with mouse. ax = cbar.cbar.ax _fake_click(fig, ax, (0.1, 0.1)) _fake_click(fig, ax, (0.1, 0.2), kind='motion') _fake_click(fig, ax, (0.1, 0.3), kind='release') _fake_click(fig, ax, (0.1, 0.1), button=3) _fake_click(fig, ax, (0.1, 0.2), button=3, kind='motion') _fake_click(fig, ax, (0.1, 0.3), kind='release') fig.canvas.scroll_event(0.5, 0.5, -0.5) # scroll down fig.canvas.scroll_event(0.5, 0.5, 0.5) # scroll up plt.close('all') # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines=outlines, **fast_test) # Remove digitization points. Now topomap should fail evoked.info['dig'] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg') plt.close('all') # Error for missing names n_channels = len(pos) data = np.ones(n_channels) assert_raises(ValueError, plot_topomap, data, pos, show_names=True) # Test error messages for invalid pos parameter pos_1d = np.zeros(n_channels) pos_3d = np.zeros((n_channels, 2, 2)) assert_raises(ValueError, plot_topomap, data, pos_1d) assert_raises(ValueError, plot_topomap, data, pos_3d) assert_raises(ValueError, plot_topomap, data, pos[:3, :]) pos_x = pos[:, :1] pos_xyz = np.c_[pos, np.zeros(n_channels)[:, np.newaxis]] assert_raises(ValueError, plot_topomap, data, pos_x) assert_raises(ValueError, plot_topomap, data, pos_xyz) # An #channels x 4 matrix should work though. In this case (x, y, width, # height) is assumed. pos_xywh = np.c_[pos, np.zeros((n_channels, 2))] plot_topomap(data, pos_xywh) plt.close('all') # Test peak finder axes = [plt.subplot(131), plt.subplot(132)] with warnings.catch_warnings(record=True): # rightmost column evoked.plot_topomap(times='peaks', axes=axes, **fast_test) plt.close('all') evoked.data = np.zeros(evoked.data.shape) evoked.data[50][1] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[1]) evoked.data[80][100] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 100]]) evoked.data[2][95] = 2 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 95]]) assert_array_equal(_find_peaks(evoked, 1), evoked.times[95]) # Test excluding bads channels evoked_grad.info['bads'] += [evoked_grad.info['ch_names'][0]] orig_bads = evoked_grad.info['bads'] evoked_grad.plot_topomap(ch_type='grad', times=[0]) assert_array_equal(evoked_grad.info['bads'], orig_bads) plt.close('all')
def test_plot_topomap(): """Test topomap plotting """ import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter("always") res = 16 evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0)) # Test animation _, anim = evoked.animate_topomap(ch_type="grad", times=[0, 0.1], butterfly=False) anim._func(1) # _animate has to be tested separately on 'Agg' backend. plt.close("all") ev_bad = evoked.pick_types(meg=False, eeg=True, copy=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) ev_bad.plot_topomap(times=ev_bad.times[:2] - 1e-6) # auto, plots EEG assert_raises(ValueError, ev_bad.plot_topomap, ch_type="mag") assert_raises(TypeError, ev_bad.plot_topomap, head_pos="foo") assert_raises(KeyError, ev_bad.plot_topomap, head_pos=dict(foo="bar")) assert_raises(ValueError, ev_bad.plot_topomap, head_pos=dict(center=0)) assert_raises(ValueError, ev_bad.plot_topomap, times=[-100]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time evoked.plot_topomap(0.1, layout=layout, scale=dict(mag=0.1)) plt.close("all") axes = [plt.subplot(221), plt.subplot(222)] evoked.plot_topomap(axes=axes, colorbar=False) plt.close("all") evoked.plot_topomap(times=[-0.1, 0.2]) plt.close("all") mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True evoked.plot_topomap(ch_type="mag", outlines=None) times = [0.1] evoked.plot_topomap(times, ch_type="eeg", res=res, scale=1) evoked.plot_topomap(times, ch_type="grad", mask=mask, res=res) evoked.plot_topomap(times, ch_type="planar1", res=res) evoked.plot_topomap(times, ch_type="planar2", res=res) evoked.plot_topomap(times, ch_type="grad", mask=mask, res=res, show_names=True, mask_params={"marker": "x"}) plt.close("all") assert_raises(ValueError, evoked.plot_topomap, times, ch_type="eeg", res=res, average=-1000) assert_raises(ValueError, evoked.plot_topomap, times, ch_type="eeg", res=res, average="hahahahah") p = evoked.plot_topomap( times, ch_type="grad", res=res, show_names=lambda x: x.replace("MEG", ""), image_interp="bilinear" ) subplot = [x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot)][0] assert_true(all("MEG" not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Test title def get_texts(p): return [x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text)] p = evoked.plot_topomap(times, ch_type="eeg", res=res, average=0.01) assert_equal(len(get_texts(p)), 0) p = evoked.plot_topomap(times, ch_type="eeg", title="Custom", res=res) texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], "Custom") plt.close("all") # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter("always") evoked.plot_topomap(times, ch_type="mag", layout=None, res=res) assert_raises( RuntimeError, plot_evoked_topomap, evoked, 0.1, "mag", proj="interactive" ) # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter("always") evoked.plot_topomap(0.1, "mag", proj="interactive", res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(0.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) with warnings.catch_warnings(record=True): # file conventions warnings.simplefilter("always") projs = read_proj(ecg_fname) projs = [pp for pp in projs if pp["desc"].lower().find("eeg") < 0] plot_projs_topomap(projs, res=res) plt.close("all") ax = plt.subplot(111) plot_projs_topomap([projs[0]], res=res, axes=ax) # test axes param plt.close("all") for ch in evoked.info["chs"]: if ch["coil_type"] == FIFF.FIFFV_COIL_EEG: ch["loc"].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info["dig"][85] pos = make_eeg_layout(evoked.info).pos[:, :2] pos, outlines = _check_outlines(pos, "head") assert_true("head" in outlines.keys()) assert_true("nose" in outlines.keys()) assert_true("ear_left" in outlines.keys()) assert_true("ear_right" in outlines.keys()) assert_true("autoshrink" in outlines.keys()) assert_true(outlines["autoshrink"]) assert_true("clip_radius" in outlines.keys()) assert_array_equal(outlines["clip_radius"], 0.5) pos, outlines = _check_outlines(pos, "skirt") assert_true("head" in outlines.keys()) assert_true("nose" in outlines.keys()) assert_true("ear_left" in outlines.keys()) assert_true("ear_right" in outlines.keys()) assert_true("autoshrink" in outlines.keys()) assert_true(not outlines["autoshrink"]) assert_true("clip_radius" in outlines.keys()) assert_array_equal(outlines["clip_radius"], 0.625) pos, outlines = _check_outlines(pos, "skirt", head_pos={"scale": [1.2, 1.2]}) assert_array_equal(outlines["clip_radius"], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type="eeg", outlines="skirt") # Pass custom outlines without patch evoked.plot_topomap(times, ch_type="eeg", outlines=outlines) plt.close("all") # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=0.46, clip_on=True, transform=plt.gca().transAxes) outlines["patch"] = patch plot_evoked_topomap(evoked, times, ch_type="eeg", outlines=outlines) # Remove digitization points. Now topomap should fail evoked.info["dig"] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type="eeg") plt.close("all") # Error for missing names n_channels = len(pos) data = np.ones(n_channels) assert_raises(ValueError, plot_topomap, data, pos, show_names=True) # Test error messages for invalid pos parameter pos_1d = np.zeros(n_channels) pos_3d = np.zeros((n_channels, 2, 2)) assert_raises(ValueError, plot_topomap, data, pos_1d) assert_raises(ValueError, plot_topomap, data, pos_3d) assert_raises(ValueError, plot_topomap, data, pos[:3, :]) pos_x = pos[:, :1] pos_xyz = np.c_[pos, np.zeros(n_channels)[:, np.newaxis]] assert_raises(ValueError, plot_topomap, data, pos_x) assert_raises(ValueError, plot_topomap, data, pos_xyz) # An #channels x 4 matrix should work though. In this case (x, y, width, # height) is assumed. pos_xywh = np.c_[pos, np.zeros((n_channels, 2))] plot_topomap(data, pos_xywh) plt.close("all") # Test peak finder axes = [plt.subplot(131), plt.subplot(132)] with warnings.catch_warnings(record=True): # rightmost column evoked.plot_topomap(times="peaks", axes=axes) plt.close("all") evoked.data = np.zeros(evoked.data.shape) evoked.data[50][1] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[1]) evoked.data[80][100] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 100]]) evoked.data[2][95] = 2 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 95]]) assert_array_equal(_find_peaks(evoked, 1), evoked.times[95])
def test_plot_topomap(): """Test topomap plotting """ import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter('always') res = 16 evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) ev_bad = evoked.pick_types(meg=False, eeg=True, copy=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) ev_bad.plot_topomap(times=ev_bad.times[:2] - 1e-6) # auto, should plot EEG assert_raises(ValueError, ev_bad.plot_topomap, ch_type='mag') assert_raises(TypeError, ev_bad.plot_topomap, head_pos='foo') assert_raises(KeyError, ev_bad.plot_topomap, head_pos=dict(foo='bar')) assert_raises(ValueError, ev_bad.plot_topomap, head_pos=dict(center=0)) assert_raises(ValueError, ev_bad.plot_topomap, times=[-100]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time evoked.plot_topomap(0.1, layout=layout, scale=dict(mag=0.1)) plt.close('all') mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True evoked.plot_topomap(None, ch_type='mag', outlines=None) times = [0.1] evoked.plot_topomap(times, ch_type='eeg', res=res, scale=1) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res) evoked.plot_topomap(times, ch_type='planar1', res=res) evoked.plot_topomap(times, ch_type='planar2', res=res) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res, show_names=True, mask_params={'marker': 'x'}) plt.close('all') assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average=-1000) assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average='hahahahah') p = evoked.plot_topomap(times, ch_type='grad', res=res, show_names=lambda x: x.replace('MEG', ''), image_interp='bilinear') subplot = [x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot)][0] assert_true(all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Test title def get_texts(p): return [x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text)] p = evoked.plot_topomap(times, ch_type='eeg', res=res, average=0.01) assert_equal(len(get_texts(p)), 0) p = evoked.plot_topomap(times, ch_type='eeg', title='Custom', res=res) texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter('always') evoked.plot_topomap(times, ch_type='mag', layout=None, res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive') # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter('always') evoked.plot_topomap(0.1, 'mag', proj='interactive', res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) with warnings.catch_warnings(record=True): # file conventions warnings.simplefilter('always') projs = read_proj(ecg_fname) projs = [pp for pp in projs if pp['desc'].lower().find('eeg') < 0] plot_projs_topomap(projs, res=res) plt.close('all') for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: if ch['eeg_loc'] is not None: ch['eeg_loc'].fill(0) ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos pos, outlines = _check_outlines(pos, 'head') # test 1: pass custom outlines without patch def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) # test 2: pass custom outlines with patch callable outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines='head') # Remove digitization points. Now topomap should fail evoked.info['dig'] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg') plt.close('all')
def draw(self, data, ch_label): self.pos = np.array(list(channel_dict_2D.values())) self.ch_names_ = list(channel_dict_2D.keys()) self.pos, self.outlines = topomap._check_outlines(self.pos, 'head') center = 0.5 * (self.pos.max(axis=0) + self.pos.min(axis=0)) scale = 1.0 / (self.pos.max(axis=0) - self.pos.min(axis=0)) scale[0] = scale[0] * 1.3 self.plt_idx = [self.ch_names_.index(name) for name in ch_label] ch_pos = np.array([self.pos[idx] * 5 / 6 for idx in self.plt_idx]) mask = np.ones((len(ch_pos), 1), dtype=bool) for idx in range(8): x_idx = idx // 4 y_idx = idx % 4 if len(self.plots) <= idx: self.axes[x_idx][y_idx].set_title(self.titles[idx]) if self.parent.ch_loc: marker = "." else: marker = "" im, cont, interp = mne.viz.topomap._plot_topomap( data[idx], ch_pos, axes=self.axes[x_idx][y_idx], contours=10, show=False, mask=mask, mask_params=dict(marker=marker), head_pos=dict(center=center, scale=scale * 1.1), cmap="RdBu_r", names=ch_label, show_names=self.parent.ch_loc) self.colorbar_ax.set_position([0.9, 0.04, 0.03, 0.15]) self.plots.append([im, cont, interp]) else: im, cont, interp = self.plots[idx] Zi = interp.set_values(data[idx])() im.set_data(Zi) # must be removed and re-added if len(cont.collections) > 0: tp = cont.collections[0] visible = tp.get_visible() patch_ = tp.get_clip_path() color = tp.get_color() lw = tp.get_linewidth() for tp in cont.collections[:]: tp.remove() cont = self.axes[x_idx][y_idx].contour(interp.Xi, interp.Yi, Zi, 10, colors=color, linewidths=lw) for tp in cont.collections: tp.set_visible(visible) tp.set_clip_path(patch_) self.plots[idx][1] = cont self.plots[idx][2] = interp self.fig.canvas.draw()
def test_plot_topomap(): """Test topomap plotting.""" import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked res = 8 fast_test = dict(res=res, contours=0, sensors=False, time_unit='s') fast_test_noscale = dict(res=res, contours=0, sensors=False) evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) # Test animation _, anim = evoked.animate_topomap(ch_type='grad', times=[0, 0.1], butterfly=False, time_unit='s') anim._func(1) # _animate has to be tested separately on 'Agg' backend. plt.close('all') ev_bad = evoked.copy().pick_types(meg=False, eeg=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) plt_topomap = partial(ev_bad.plot_topomap, **fast_test) plt_topomap(times=ev_bad.times[:2] - 1e-6) # auto, plots EEG pytest.raises(ValueError, plt_topomap, ch_type='mag') pytest.raises(TypeError, plt_topomap, head_pos='foo') pytest.raises(KeyError, plt_topomap, head_pos=dict(foo='bar')) pytest.raises(ValueError, plt_topomap, head_pos=dict(center=0)) pytest.raises(ValueError, plt_topomap, times=[-100]) # bad time pytest.raises(ValueError, plt_topomap, times=[[0]]) # bad time evoked.plot_topomap([0.1], ch_type='eeg', scalings=1, res=res, contours=[-100, 0, 100], time_unit='ms') plt_topomap = partial(evoked.plot_topomap, **fast_test) plt_topomap(0.1, layout=layout, scalings=dict(mag=0.1)) plt.close('all') axes = [plt.subplot(221), plt.subplot(222)] plt_topomap(axes=axes, colorbar=False) plt.close('all') plt_topomap(times=[-0.1, 0.2]) plt.close('all') evoked_grad = evoked.copy().crop(0, 0).pick_types(meg='grad') mask = np.zeros((204, 1), bool) mask[[0, 3, 5, 6]] = True names = [] def proc_names(x): names.append(x) return x[4:] evoked_grad.plot_topomap(ch_type='grad', times=[0], mask=mask, show_names=proc_names, **fast_test) assert_equal(sorted(names), ['MEG 011x', 'MEG 012x', 'MEG 013x', 'MEG 014x']) mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True plt_topomap(ch_type='mag', outlines=None) times = [0.1] plt_topomap(times, ch_type='grad', mask=mask) plt_topomap(times, ch_type='planar1') plt_topomap(times, ch_type='planar2') plt_topomap(times, ch_type='grad', mask=mask, show_names=True, mask_params={'marker': 'x'}) plt.close('all') pytest.raises(ValueError, plt_topomap, times, ch_type='eeg', average=-1e3) pytest.raises(ValueError, plt_topomap, times, ch_type='eeg', average='x') p = plt_topomap(times, ch_type='grad', image_interp='bilinear', show_names=lambda x: x.replace('MEG', '')) subplot = [x for x in p.get_children() if 'Subplot' in str(type(x))] assert len(subplot) >= 1, [type(x) for x in p.get_children()] subplot = subplot[0] assert (all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Plot array for ch_type in ('mag', 'grad'): evoked_ = evoked.copy().pick_types(eeg=False, meg=ch_type) plot_topomap(evoked_.data[:, 0], evoked_.info, **fast_test_noscale) # fail with multiple channel types pytest.raises(ValueError, plot_topomap, evoked.data[0, :], evoked.info) # Test title def get_texts(p): return [x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text)] p = plt_topomap(times, ch_type='eeg', average=0.01) assert_equal(len(get_texts(p)), 0) p = plt_topomap(times, ch_type='eeg', title='Custom') texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning plt_topomap(times, ch_type='mag', layout=None) # projs have already been applied pytest.raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive', time_unit='s') # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) fig1 = evoked.plot_topomap('interactive', 'mag', proj='interactive', **fast_test) _fake_click(fig1, fig1.axes[1], (0.5, 0.5)) # click slider data_max = np.max(fig1.axes[0].images[0]._A) fig2 = plt.gcf() _fake_click(fig2, fig2.axes[0], (0.075, 0.775)) # toggle projector # make sure projector gets toggled assert (np.max(fig1.axes[0].images[0]._A) != data_max) pytest.raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50), time_unit='s') pytest.raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6], time_unit='s') for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos[:, :2] pos, outlines = _check_outlines(pos, 'head') assert ('head' in outlines.keys()) assert ('nose' in outlines.keys()) assert ('ear_left' in outlines.keys()) assert ('ear_right' in outlines.keys()) assert ('autoshrink' in outlines.keys()) assert (outlines['autoshrink']) assert ('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.5) pos, outlines = _check_outlines(pos, 'skirt') assert ('head' in outlines.keys()) assert ('nose' in outlines.keys()) assert ('ear_left' in outlines.keys()) assert ('ear_right' in outlines.keys()) assert ('autoshrink' in outlines.keys()) assert (not outlines['autoshrink']) assert ('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.625) pos, outlines = _check_outlines(pos, 'skirt', head_pos={'scale': [1.2, 1.2]}) assert_array_equal(outlines['clip_radius'], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type='eeg', outlines='skirt', **fast_test) # Pass custom outlines without patch evoked.plot_topomap(times, ch_type='eeg', outlines=outlines, **fast_test) plt.close('all') # Test interactive cmap fig = plot_evoked_topomap(evoked, times=[0., 0.1], ch_type='eeg', cmap=('Reds', True), title='title', **fast_test) fig.canvas.key_press_event('up') fig.canvas.key_press_event(' ') fig.canvas.key_press_event('down') cbar = fig.get_axes()[0].CB # Fake dragging with mouse. ax = cbar.cbar.ax _fake_click(fig, ax, (0.1, 0.1)) _fake_click(fig, ax, (0.1, 0.2), kind='motion') _fake_click(fig, ax, (0.1, 0.3), kind='release') _fake_click(fig, ax, (0.1, 0.1), button=3) _fake_click(fig, ax, (0.1, 0.2), button=3, kind='motion') _fake_click(fig, ax, (0.1, 0.3), kind='release') fig.canvas.scroll_event(0.5, 0.5, -0.5) # scroll down fig.canvas.scroll_event(0.5, 0.5, 0.5) # scroll up plt.close('all') # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines=outlines, **fast_test) # Remove digitization points. Now topomap should fail evoked.info['dig'] = None pytest.raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg', time_unit='s') plt.close('all') # Error for missing names n_channels = len(pos) data = np.ones(n_channels) pytest.raises(ValueError, plot_topomap, data, pos, show_names=True) # Test error messages for invalid pos parameter pos_1d = np.zeros(n_channels) pos_3d = np.zeros((n_channels, 2, 2)) pytest.raises(ValueError, plot_topomap, data, pos_1d) pytest.raises(ValueError, plot_topomap, data, pos_3d) pytest.raises(ValueError, plot_topomap, data, pos[:3, :]) pos_x = pos[:, :1] pos_xyz = np.c_[pos, np.zeros(n_channels)[:, np.newaxis]] pytest.raises(ValueError, plot_topomap, data, pos_x) pytest.raises(ValueError, plot_topomap, data, pos_xyz) # An #channels x 4 matrix should work though. In this case (x, y, width, # height) is assumed. pos_xywh = np.c_[pos, np.zeros((n_channels, 2))] plot_topomap(data, pos_xywh) plt.close('all') # Test peak finder axes = [plt.subplot(131), plt.subplot(132)] evoked.plot_topomap(times='peaks', axes=axes, **fast_test) plt.close('all') evoked.data = np.zeros(evoked.data.shape) evoked.data[50][1] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[1]) evoked.data[80][100] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 100]]) evoked.data[2][95] = 2 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 95]]) assert_array_equal(_find_peaks(evoked, 1), evoked.times[95]) # Test excluding bads channels evoked_grad.info['bads'] += [evoked_grad.info['ch_names'][0]] orig_bads = evoked_grad.info['bads'] evoked_grad.plot_topomap(ch_type='grad', times=[0], time_unit='ms') assert_array_equal(evoked_grad.info['bads'], orig_bads) plt.close('all')
def test_plot_topomap(): """Test topomap plotting """ import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter('always') res = 16 evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) # Test animation _, anim = evoked.animate_topomap(ch_type='grad', times=[0, 0.1], butterfly=False) anim._func(1) # _animate has to be tested separately on 'Agg' backend. plt.close('all') ev_bad = evoked.copy().pick_types(meg=False, eeg=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) ev_bad.plot_topomap(times=ev_bad.times[:2] - 1e-6) # auto, plots EEG assert_raises(ValueError, ev_bad.plot_topomap, ch_type='mag') assert_raises(TypeError, ev_bad.plot_topomap, head_pos='foo') assert_raises(KeyError, ev_bad.plot_topomap, head_pos=dict(foo='bar')) assert_raises(ValueError, ev_bad.plot_topomap, head_pos=dict(center=0)) assert_raises(ValueError, ev_bad.plot_topomap, times=[-100]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time evoked.plot_topomap(0.1, layout=layout, scale=dict(mag=0.1)) plt.close('all') axes = [plt.subplot(221), plt.subplot(222)] evoked.plot_topomap(axes=axes, colorbar=False) plt.close('all') evoked.plot_topomap(times=[-0.1, 0.2]) plt.close('all') mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True evoked.plot_topomap(ch_type='mag', outlines=None) times = [0.1] evoked.plot_topomap(times, ch_type='eeg', res=res, scale=1) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res) evoked.plot_topomap(times, ch_type='planar1', res=res) evoked.plot_topomap(times, ch_type='planar2', res=res) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res, show_names=True, mask_params={'marker': 'x'}) plt.close('all') assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average=-1000) assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average='hahahahah') p = evoked.plot_topomap(times, ch_type='grad', res=res, show_names=lambda x: x.replace('MEG', ''), image_interp='bilinear') subplot = [ x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot) ][0] assert_true( all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Plot array for ch_type in ('mag', 'grad'): evoked_ = evoked.copy().pick_types(eeg=False, meg=ch_type) plot_topomap(evoked_.data[:, 0], evoked_.info) # fail with multiple channel types assert_raises(ValueError, plot_topomap, evoked.data[0, :], evoked.info) # Test title def get_texts(p): return [ x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text) ] p = evoked.plot_topomap(times, ch_type='eeg', res=res, average=0.01) assert_equal(len(get_texts(p)), 0) p = evoked.plot_topomap(times, ch_type='eeg', title='Custom', res=res) texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter('always') evoked.plot_topomap(times, ch_type='mag', layout=None, res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive') # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter('always') evoked.plot_topomap(0.1, 'mag', proj='interactive', res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) with warnings.catch_warnings(record=True): # file conventions warnings.simplefilter('always') projs = read_proj(ecg_fname) projs = [pp for pp in projs if pp['desc'].lower().find('eeg') < 0] plot_projs_topomap(projs, res=res) plt.close('all') ax = plt.subplot(111) plot_projs_topomap([projs[0]], res=res, axes=ax) # test axes param plt.close('all') for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos[:, :2] pos, outlines = _check_outlines(pos, 'head') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.5) pos, outlines = _check_outlines(pos, 'skirt') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(not outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.625) pos, outlines = _check_outlines(pos, 'skirt', head_pos={'scale': [1.2, 1.2]}) assert_array_equal(outlines['clip_radius'], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type='eeg', outlines='skirt') # Pass custom outlines without patch evoked.plot_topomap(times, ch_type='eeg', outlines=outlines) plt.close('all') # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines=outlines) # Remove digitization points. Now topomap should fail evoked.info['dig'] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg') plt.close('all') # Error for missing names n_channels = len(pos) data = np.ones(n_channels) assert_raises(ValueError, plot_topomap, data, pos, show_names=True) # Test error messages for invalid pos parameter pos_1d = np.zeros(n_channels) pos_3d = np.zeros((n_channels, 2, 2)) assert_raises(ValueError, plot_topomap, data, pos_1d) assert_raises(ValueError, plot_topomap, data, pos_3d) assert_raises(ValueError, plot_topomap, data, pos[:3, :]) pos_x = pos[:, :1] pos_xyz = np.c_[pos, np.zeros(n_channels)[:, np.newaxis]] assert_raises(ValueError, plot_topomap, data, pos_x) assert_raises(ValueError, plot_topomap, data, pos_xyz) # An #channels x 4 matrix should work though. In this case (x, y, width, # height) is assumed. pos_xywh = np.c_[pos, np.zeros((n_channels, 2))] plot_topomap(data, pos_xywh) plt.close('all') # Test peak finder axes = [plt.subplot(131), plt.subplot(132)] with warnings.catch_warnings(record=True): # rightmost column evoked.plot_topomap(times='peaks', axes=axes) plt.close('all') evoked.data = np.zeros(evoked.data.shape) evoked.data[50][1] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[1]) evoked.data[80][100] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 100]]) evoked.data[2][95] = 2 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 95]]) assert_array_equal(_find_peaks(evoked, 1), evoked.times[95])
def test_plot_topomap(): """Test topomap plotting """ import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter('always') res = 16 evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) ev_bad = evoked.pick_types(meg=False, eeg=True, copy=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) ev_bad.plot_topomap(times=ev_bad.times[:2] - 1e-6) # auto, should plot EEG assert_raises(ValueError, ev_bad.plot_topomap, ch_type='mag') assert_raises(TypeError, ev_bad.plot_topomap, head_pos='foo') assert_raises(KeyError, ev_bad.plot_topomap, head_pos=dict(foo='bar')) assert_raises(ValueError, ev_bad.plot_topomap, head_pos=dict(center=0)) assert_raises(ValueError, ev_bad.plot_topomap, times=[-100]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time evoked.plot_topomap(0.1, layout=layout, scale=dict(mag=0.1)) plt.close('all') axes = [plt.subplot(221), plt.subplot(222)] evoked.plot_topomap(axes=axes, colorbar=False) plt.close('all') evoked.plot_topomap(times=[-0.1, 0.2]) plt.close('all') mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True evoked.plot_topomap(ch_type='mag', outlines=None) times = [0.1] evoked.plot_topomap(times, ch_type='eeg', res=res, scale=1) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res) evoked.plot_topomap(times, ch_type='planar1', res=res) evoked.plot_topomap(times, ch_type='planar2', res=res) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res, show_names=True, mask_params={'marker': 'x'}) plt.close('all') assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average=-1000) assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average='hahahahah') p = evoked.plot_topomap(times, ch_type='grad', res=res, show_names=lambda x: x.replace('MEG', ''), image_interp='bilinear') subplot = [x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot)][0] assert_true(all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Test title def get_texts(p): return [x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text)] p = evoked.plot_topomap(times, ch_type='eeg', res=res, average=0.01) assert_equal(len(get_texts(p)), 0) p = evoked.plot_topomap(times, ch_type='eeg', title='Custom', res=res) texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter('always') evoked.plot_topomap(times, ch_type='mag', layout=None, res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive') # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter('always') evoked.plot_topomap(0.1, 'mag', proj='interactive', res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) with warnings.catch_warnings(record=True): # file conventions warnings.simplefilter('always') projs = read_proj(ecg_fname) projs = [pp for pp in projs if pp['desc'].lower().find('eeg') < 0] plot_projs_topomap(projs, res=res) plt.close('all') ax = plt.subplot(111) plot_projs_topomap([projs[0]], res=res, axes=ax) # test axes param plt.close('all') for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos[:, :2] pos, outlines = _check_outlines(pos, 'head') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.5) pos, outlines = _check_outlines(pos, 'skirt') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(not outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.625) pos, outlines = _check_outlines(pos, 'skirt', head_pos={'scale': [1.2, 1.2]}) assert_array_equal(outlines['clip_radius'], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type='eeg', outlines='skirt') # Pass custom outlines without patch evoked.plot_topomap(times, ch_type='eeg', outlines=outlines) plt.close('all') # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines=outlines) # Remove digitization points. Now topomap should fail evoked.info['dig'] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg') plt.close('all') # Error for missing names n_channels = len(pos) data = np.ones(n_channels) assert_raises(ValueError, plot_topomap, data, pos, show_names=True) # Test error messages for invalid pos parameter pos_1d = np.zeros(n_channels) pos_3d = np.zeros((n_channels, 2, 2)) assert_raises(ValueError, plot_topomap, data, pos_1d) assert_raises(ValueError, plot_topomap, data, pos_3d) assert_raises(ValueError, plot_topomap, data, pos[:3, :]) pos_x = pos[:, :1] pos_xyz = np.c_[pos, np.zeros(n_channels)[:, np.newaxis]] assert_raises(ValueError, plot_topomap, data, pos_x) assert_raises(ValueError, plot_topomap, data, pos_xyz) # An #channels x 4 matrix should work though. In this case (x, y, width, # height) is assumed. pos_xywh = np.c_[pos, np.zeros((n_channels, 2))] plot_topomap(data, pos_xywh) plt.close('all') # Test peak finder axes = [plt.subplot(131), plt.subplot(132)] evoked.plot_topomap(times='peaks', axes=axes) plt.close('all') evoked.data = np.zeros(evoked.data.shape) evoked.data[50][1] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[1]) evoked.data[80][100] = 1 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 100]]) evoked.data[2][95] = 2 assert_array_equal(_find_peaks(evoked, 10), evoked.times[[1, 95]]) assert_array_equal(_find_peaks(evoked, 1), evoked.times[95])
def plot_topomap(data, pos, vmin=None, vmax=None, cmap=None, sensors=True, res=64, axes=None, names=None, show_names=False, mask=None, mask_params=None, outlines='head', image_mask=None, contours=6, image_interp='bilinear', show=True, head_pos=None, onselect=None, axis=None): ''' see the docstring for mne.viz.plot_topomap, which i've simply modified to return more objects ''' from matplotlib.widgets import RectangleSelector from mne.io.pick import (channel_type, pick_info, _pick_data_channels) from mne.utils import warn from mne.viz.utils import (_setup_vmin_vmax, plt_show) from mne.defaults import _handle_default from mne.channels.layout import _find_topomap_coords from mne.io.meas_info import Info from mne.viz.topomap import _check_outlines, _prepare_topomap, _griddata, _make_image_mask, _plot_sensors, \ _draw_outlines data = np.asarray(data) if isinstance(pos, Info): # infer pos from Info object picks = _pick_data_channels(pos) # pick only data channels pos = pick_info(pos, picks) # check if there is only 1 channel type, and n_chans matches the data ch_type = set(channel_type(pos, idx) for idx, _ in enumerate(pos["chs"])) info_help = ("Pick Info with e.g. mne.pick_info and " "mne.channels.channel_indices_by_type.") if len(ch_type) > 1: raise ValueError("Multiple channel types in Info structure. " + info_help) elif len(pos["chs"]) != data.shape[0]: raise ValueError("Number of channels in the Info object and " "the data array does not match. " + info_help) else: ch_type = ch_type.pop() if any(type_ in ch_type for type_ in ('planar', 'grad')): # deal with grad pairs from ..channels.layout import (_merge_grad_data, find_layout, _pair_grad_sensors) picks, pos = _pair_grad_sensors(pos, find_layout(pos)) data = _merge_grad_data(data[picks]).reshape(-1) else: picks = list(range(data.shape[0])) pos = _find_topomap_coords(pos, picks=picks) if data.ndim > 1: raise ValueError("Data needs to be array of shape (n_sensors,); got " "shape %s." % str(data.shape)) # Give a helpful error message for common mistakes regarding the position # matrix. pos_help = ("Electrode positions should be specified as a 2D array with " "shape (n_channels, 2). Each row in this matrix contains the " "(x, y) position of an electrode.") if pos.ndim != 2: error = ("{ndim}D array supplied as electrode positions, where a 2D " "array was expected").format(ndim=pos.ndim) raise ValueError(error + " " + pos_help) elif pos.shape[1] == 3: error = ("The supplied electrode positions matrix contains 3 columns. " "Are you trying to specify XYZ coordinates? Perhaps the " "mne.channels.create_eeg_layout function is useful for you.") raise ValueError(error + " " + pos_help) # No error is raised in case of pos.shape[1] == 4. In this case, it is # assumed the position matrix contains both (x, y) and (width, height) # values, such as Layout.pos. elif pos.shape[1] == 1 or pos.shape[1] > 4: raise ValueError(pos_help) if len(data) != len(pos): raise ValueError("Data and pos need to be of same length. Got data of " "length %s, pos of length %s" % (len(data), len(pos))) norm = min(data) >= 0 vmin, vmax = _setup_vmin_vmax(data, vmin, vmax, norm) if cmap is None: cmap = 'Reds' if norm else 'RdBu_r' pos, outlines = _check_outlines(pos, outlines, head_pos) if axis is not None: axes = axis warn('axis parameter is deprecated and will be removed in 0.13. ' 'Use axes instead.', DeprecationWarning) ax = axes if axes else plt.gca() pos_x, pos_y = _prepare_topomap(pos, ax) if outlines is None: xmin, xmax = pos_x.min(), pos_x.max() ymin, ymax = pos_y.min(), pos_y.max() else: xlim = np.inf, -np.inf, ylim = np.inf, -np.inf, mask_ = np.c_[outlines['mask_pos']] xmin, xmax = (np.min(np.r_[xlim[0], mask_[:, 0]]), np.max(np.r_[xlim[1], mask_[:, 0]])) ymin, ymax = (np.min(np.r_[ylim[0], mask_[:, 1]]), np.max(np.r_[ylim[1], mask_[:, 1]])) # interpolate data xi = np.linspace(xmin, xmax, res) yi = np.linspace(ymin, ymax, res) Xi, Yi = np.meshgrid(xi, yi) Zi = _griddata(pos_x, pos_y, data, Xi, Yi) if outlines is None: _is_default_outlines = False elif isinstance(outlines, dict): _is_default_outlines = any(k.startswith('head') for k in outlines) if _is_default_outlines and image_mask is None: # prepare masking image_mask, pos = _make_image_mask(outlines, pos, res) mask_params = _handle_default('mask_params', mask_params) # plot outline linewidth = mask_params['markeredgewidth'] patch = None if 'patch' in outlines: patch = outlines['patch'] patch_ = patch() if callable(patch) else patch patch_.set_clip_on(False) ax.add_patch(patch_) ax.set_transform(ax.transAxes) ax.set_clip_path(patch_) # plot map and countour im = ax.imshow(Zi, cmap=cmap, vmin=vmin, vmax=vmax, origin='lower', aspect='equal', extent=(xmin, xmax, ymin, ymax), interpolation=image_interp) # This tackles an incomprehensible matplotlib bug if no contours are # drawn. To avoid rescalings, we will always draw contours. # But if no contours are desired we only draw one and make it invisible . no_contours = False if contours in (False, None): contours, no_contours = 1, True cont = ax.contour(Xi, Yi, Zi, contours, colors='k', linewidths=linewidth) if no_contours is True: for col in cont.collections: col.set_visible(False) if _is_default_outlines: from matplotlib import patches patch_ = patches.Ellipse((0, 0), 2 * outlines['clip_radius'][0], 2 * outlines['clip_radius'][1], clip_on=True, transform=ax.transData) if _is_default_outlines or patch is not None: im.set_clip_path(patch_) if cont is not None: for col in cont.collections: col.set_clip_path(patch_) if sensors is not False and mask is None: _plot_sensors(pos_x, pos_y, sensors=sensors, ax=ax) elif sensors and mask is not None: idx = np.where(mask)[0] ax.plot(pos_x[idx], pos_y[idx], **mask_params) idx = np.where(~mask)[0] _plot_sensors(pos_x[idx], pos_y[idx], sensors=sensors, ax=ax) elif not sensors and mask is not None: idx = np.where(mask)[0] ax.plot(pos_x[idx], pos_y[idx], **mask_params) if isinstance(outlines, dict): _draw_outlines(ax, outlines) if show_names: if names is None: raise ValueError("To show names, a list of names must be provided" " (see `names` keyword).") if show_names is True: def _show_names(x): return x else: _show_names = show_names show_idx = np.arange(len(names)) if mask is None else np.where(mask)[0] for ii, (p, ch_id) in enumerate(zip(pos, names)): if ii not in show_idx: continue ch_id = _show_names(ch_id) ax.text(p[0], p[1], ch_id, horizontalalignment='center', verticalalignment='center', size='x-small') plt.subplots_adjust(top=.95) if onselect is not None: ax.RS = RectangleSelector(ax, onselect=onselect) plt_show(show) return ax, im, cont, pos_x, pos_y
def test_plot_topomap(): """Test topomap plotting """ import matplotlib.pyplot as plt from matplotlib.patches import Circle # evoked warnings.simplefilter('always') res = 16 evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0)) ev_bad = evoked.pick_types(meg=False, eeg=True, copy=True) ev_bad.pick_channels(ev_bad.ch_names[:2]) ev_bad.plot_topomap(times=ev_bad.times[:2] - 1e-6) # auto, should plot EEG assert_raises(ValueError, ev_bad.plot_topomap, ch_type='mag') assert_raises(TypeError, ev_bad.plot_topomap, head_pos='foo') assert_raises(KeyError, ev_bad.plot_topomap, head_pos=dict(foo='bar')) assert_raises(ValueError, ev_bad.plot_topomap, head_pos=dict(center=0)) assert_raises(ValueError, ev_bad.plot_topomap, times=[-100]) # bad time assert_raises(ValueError, ev_bad.plot_topomap, times=[[0]]) # bad time evoked.plot_topomap(0.1, layout=layout, scale=dict(mag=0.1)) plt.close('all') axes = [plt.subplot(221), plt.subplot(222)] evoked.plot_topomap(axes=axes, colorbar=False) plt.close('all') evoked.plot_topomap(times=[-0.1, 0.2]) plt.close('all') mask = np.zeros_like(evoked.data, dtype=bool) mask[[1, 5], :] = True evoked.plot_topomap(None, ch_type='mag', outlines=None) times = [0.1] evoked.plot_topomap(times, ch_type='eeg', res=res, scale=1) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res) evoked.plot_topomap(times, ch_type='planar1', res=res) evoked.plot_topomap(times, ch_type='planar2', res=res) evoked.plot_topomap(times, ch_type='grad', mask=mask, res=res, show_names=True, mask_params={'marker': 'x'}) plt.close('all') assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average=-1000) assert_raises(ValueError, evoked.plot_topomap, times, ch_type='eeg', res=res, average='hahahahah') p = evoked.plot_topomap(times, ch_type='grad', res=res, show_names=lambda x: x.replace('MEG', ''), image_interp='bilinear') subplot = [x for x in p.get_children() if isinstance(x, matplotlib.axes.Subplot)][0] assert_true(all('MEG' not in x.get_text() for x in subplot.get_children() if isinstance(x, matplotlib.text.Text))) # Test title def get_texts(p): return [x.get_text() for x in p.get_children() if isinstance(x, matplotlib.text.Text)] p = evoked.plot_topomap(times, ch_type='eeg', res=res, average=0.01) assert_equal(len(get_texts(p)), 0) p = evoked.plot_topomap(times, ch_type='eeg', title='Custom', res=res) texts = get_texts(p) assert_equal(len(texts), 1) assert_equal(texts[0], 'Custom') plt.close('all') # delaunay triangulation warning with warnings.catch_warnings(record=True): # can't show warnings.simplefilter('always') evoked.plot_topomap(times, ch_type='mag', layout=None, res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag', proj='interactive') # projs have already been applied # change to no-proj mode evoked = read_evokeds(evoked_fname, 'Left Auditory', baseline=(None, 0), proj=False) with warnings.catch_warnings(record=True): warnings.simplefilter('always') evoked.plot_topomap(0.1, 'mag', proj='interactive', res=res) assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50)) assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6]) with warnings.catch_warnings(record=True): # file conventions warnings.simplefilter('always') projs = read_proj(ecg_fname) projs = [pp for pp in projs if pp['desc'].lower().find('eeg') < 0] plot_projs_topomap(projs, res=res) plt.close('all') ax = plt.subplot(111) plot_projs_topomap([projs[0]], res=res, axes=ax) # test axes param plt.close('all') for ch in evoked.info['chs']: if ch['coil_type'] == FIFF.FIFFV_COIL_EEG: if ch['eeg_loc'] is not None: ch['eeg_loc'].fill(0) ch['loc'].fill(0) # Remove extra digitization point, so EEG digitization points # correspond with the EEG electrodes del evoked.info['dig'][85] pos = make_eeg_layout(evoked.info).pos pos, outlines = _check_outlines(pos, 'head') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.5) pos, outlines = _check_outlines(pos, 'skirt') assert_true('head' in outlines.keys()) assert_true('nose' in outlines.keys()) assert_true('ear_left' in outlines.keys()) assert_true('ear_right' in outlines.keys()) assert_true('autoshrink' in outlines.keys()) assert_true(not outlines['autoshrink']) assert_true('clip_radius' in outlines.keys()) assert_array_equal(outlines['clip_radius'], 0.625) pos, outlines = _check_outlines(pos, 'skirt', head_pos={'scale': [1.2, 1.2]}) assert_array_equal(outlines['clip_radius'], 0.75) # Plot skirt evoked.plot_topomap(times, ch_type='eeg', outlines='skirt') # Pass custom outlines without patch evoked.plot_topomap(times, ch_type='eeg', outlines=outlines) plt.close('all') # Pass custom outlines with patch callable def patch(): return Circle((0.5, 0.4687), radius=.46, clip_on=True, transform=plt.gca().transAxes) outlines['patch'] = patch plot_evoked_topomap(evoked, times, ch_type='eeg', outlines=outlines) # Remove digitization points. Now topomap should fail evoked.info['dig'] = None assert_raises(RuntimeError, plot_evoked_topomap, evoked, times, ch_type='eeg') plt.close('all')