Skip to content

Commit

Permalink
MRG: Unify axis labeling (mne-tools#5079)
Browse files Browse the repository at this point in the history
* FIX: Unify axis labeling

* FIX: Cleaner vars

* FIX: Missed a sec
  • Loading branch information
larsoner authored and agramfort committed Apr 3, 2018
1 parent 76b6d1e commit dba99f1
Showing 18 changed files with 86 additions and 112 deletions.
4 changes: 2 additions & 2 deletions doc/manual/cookbook.rst
Original file line number Diff line number Diff line change
@@ -145,8 +145,8 @@ Rejection using annotations
The reject keyword of :class:`mne.Epochs` is used for rejecting bad epochs
based on peak-to-peak thresholds. Bad segments of data can also be rejected
by marking segments of raw data with annotations. See
:ref:`tut_artifacts_reject` and :class:`mne.Annotations` for more
information.
:ref:`sphx_glr_auto_tutorials_plot_artifacts_correction_rejection.py`
and :class:`mne.Annotations` for more .

Once the :class:`mne.Epochs` are constructed, they can be averaged to obtain
:class:`mne.Evoked` data as::
4 changes: 3 additions & 1 deletion doc/whats_new.rst
Original file line number Diff line number Diff line change
@@ -95,7 +95,7 @@ Changelog

- Add the Picard algorithm to perform ICA for :class:`mne.preprocessing.ICA`, by `Pierre Ablin`_ and `Alex Gramfort`_

- Add ability to supply a mask to the plot in :func:`mne.viz.plot_evoked_image` by `Jona Sassenhagen`.
- Add ability to supply a mask to the plot in :func:`mne.viz.plot_evoked_image` by `Jona Sassenhagen`_

- Add :func:`mne.time_frequency.csd_morlet` and :func:`mne.time_frequency.csd_array_morlet` to estimate cross-spectral density using Morlet wavelets, by `Marijn van Vliet`_

@@ -175,6 +175,8 @@ API

- Changed the behavior of :meth:`mne.io.Raw.pick_channels` and similar methods to be consistent with :func:`mne.pick_channels` to treat channel list as a set (ignoring order) -- if reordering is necessary use ``inst.reorder_channels``, by `Eric Larson`_

- Changed the labeling of some plotting functions to use more standard capitalization and units, e.g. "Time (s)" instead of "time [sec]" by `Eric Larson`_

- ``mne.time_frequency.csd_epochs`` has been refactored into :func:`mne.time_frequency.csd_fourier` and :func:`mne.time_frequency.csd_multitaper`, by `Marijn van Vliet`_

- ``mne.time_frequency.csd_array`` has been refactored into :func:`mne.time_frequency.csd_array_fourier` and :func:`mne.time_frequency.csd_array_multitaper`, by `Marijn van Vliet`_
12 changes: 8 additions & 4 deletions mne/filter.py
Original file line number Diff line number Diff line change
@@ -625,8 +625,10 @@ def construct_iir_filter(iir_params, f_pass=None, f_stop=None, sfreq=None,
>>> print((iir_params['b'], iir_params['a'], iir_params['padlen'])) # doctest:+SKIP
(array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]), [1, 0], 0)
For more information, see the tutorials :ref:`tut_background_filtering`
and :ref:`tut_artifacts_filter`.
For more information, see the tutorials
:ref:`sphx_glr_auto_tutorials_plot_background_filtering.py`
and
:ref:`sphx_glr_auto_tutorials_plot_artifacts_correction_filtering.py`.
""" # noqa: E501
from scipy.signal import iirfilter, iirdesign
known_filters = ('bessel', 'butter', 'butterworth', 'cauer', 'cheby1',
@@ -851,8 +853,10 @@ def filter_data(data, sfreq, l_freq, h_freq, picks=None, filter_length='auto',
Notes
-----
For more information, see the tutorials :ref:`tut_background_filtering`
and :ref:`tut_artifacts_filter`, and :func:`mne.filter.create_filter`.
For more information, see the tutorials
:ref:`sphx_glr_auto_tutorials_plot_background_filtering.py`
and
:ref:`sphx_glr_auto_tutorials_plot_artifacts_correction_filtering.py`.
"""
if not isinstance(data, np.ndarray):
raise ValueError('data must be an array')
6 changes: 4 additions & 2 deletions mne/io/base.py
Original file line number Diff line number Diff line change
@@ -1240,8 +1240,10 @@ def filter(self, l_freq, h_freq, picks=None, filter_length='auto',
Notes
-----
For more information, see the tutorials :ref:`tut_background_filtering`
and :ref:`tut_artifacts_filter`.
For more information, see the tutorials
:ref:`sphx_glr_auto_tutorials_plot_background_filtering.py`
and
:ref:`sphx_glr_auto_tutorials_plot_artifacts_correction_filtering.py`.
"""
_check_preload(self, 'raw.filter')
update_info, picks = _filt_check_picks(self.info, picks,
8 changes: 3 additions & 5 deletions mne/viz/epochs.py
Original file line number Diff line number Diff line change
@@ -923,10 +923,8 @@ def plot_epochs_psd(epochs, fmin=0, fmax=np.inf, tmin=None, tmax=None,
color=color, alpha=area_alpha)
if make_label:
if ii == len(picks_list) - 1:
ax.set_xlabel('Freq (Hz)')
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.set_xlim(freqs[0], freqs[-1])
ax.set_xlabel('Frequency (Hz)')
ax.set(ylabel=ylabel, title=title, xlim=(freqs[0], freqs[-1]))
if make_label:
tight_layout(pad=0.1, h_pad=0.1, w_pad=0.1, fig=fig)
plt_show(show)
@@ -1955,7 +1953,7 @@ def _plot_histogram(params):
for idx in range(len(types)):
ax = plt.subplot(len(types), 1, idx + 1)
plt.xlabel(units[types[idx]])
plt.ylabel('count')
plt.ylabel('Count')
color = colors[types[idx]]
rej = None
if epochs.reject is not None and types[idx] in epochs.reject.keys():
22 changes: 7 additions & 15 deletions mne/viz/evoked.py
Original file line number Diff line number Diff line change
@@ -273,8 +273,7 @@ def _plot_evoked(evoked, picks, exclude, unit, show, ylim, proj, xlim, hline,
units, scalings, hline, gfp, types, zorder, xlim, ylim,
times, bad_ch_idx, titles, ch_types_used, selectable,
False, line_alpha=1.)
for ax in axes:
ax.set_xlabel('Time (ms)')
plt.setp(axes, xlabel='Time (ms)')

elif plot_type == 'image':
for ax, this_type in zip(axes, ch_types_used):
@@ -292,8 +291,7 @@ def _plot_evoked(evoked, picks, exclude, unit, show, ylim, proj, xlim, hline,
plot_type=plot_type)
_draw_proj_checkbox(None, params)

for ax in fig.axes[:len(ch_types_used) - 1]:
ax.set_xlabel('')
plt.setp(fig.axes[:len(ch_types_used) - 1], xlabel='')
fig.canvas.draw() # for axes plots update axes.
if set_tight_layout:
tight_layout(fig=fig)
@@ -548,15 +546,14 @@ def _plot_image(data, ax, this_type, picks, cmap, unit, units, scalings, times,
if xlim == 'tight':
xlim = (times[0], times[-1])
ax.set_xlim(xlim)
ax.set_xlabel('Time (ms)')

if colorbar:
cbar = plt.colorbar(im, ax=ax)
cbar.ax.set_title(ch_unit)
if cmap[1]:
ax.CB = DraggableColorbar(cbar, im)

ax.set_ylabel('Channels (index)')
ax.set(ylabel='Channel (index)', xlabel='Time (ms)')

if (draw_mask or draw_contour) and mask is not None:
if mask.all():
@@ -1152,16 +1149,15 @@ def whitened_gfp(x, rank=None):

ax = ax_gfp[i]
ax.set_title(title if n_columns > 1 else
'whitened global field power (GFP),'
' method = "%s"' % label)
'Whitened GFP, method = "%s"' % label)

data = evoked_white.data[sub_picks]
gfp = whitened_gfp(data, rank=this_rank)
ax.plot(times, gfp,
label=label if n_columns > 1 else title,
color=color if n_columns > 1 else ch_colors[ch],
lw=0.5)
ax.set(xlabel='times [ms]', ylabel='GFP [chi^2]',
ax.set(xlabel='Time (ms)', ylabel='GFP ($\chi^2$)',
xlim=[times[0], times[-1]], ylim=(0, 10))
ax.axhline(1, color='red', linestyle='--', lw=2.)
if n_columns > 1:
@@ -1216,10 +1212,7 @@ def plot_snr_estimate(evoked, inv, show=True):
# http://bconnelly.net/2013/10/creating-colorblind-friendly-figures/
ax.plot(evoked.times, snr_est, color=[0.0, 0.6, 0.5])
ax.plot(evoked.times, snr, color=[0.8, 0.4, 0.0])
ax.set_xlim(lims[:2])
ax.set_ylim(lims[2:])
ax.set_ylabel('SNR')
ax.set_xlabel('Time (sec)')
ax.set(xlim=lims[:2], ylim=lims[2:], ylabel='SNR', xlabel='Time (s)')
if evoked.comment is not None:
ax.set_title(evoked.comment)
plt.draw()
@@ -2105,8 +2098,7 @@ def plot_compare_evokeds(evokeds, picks=None, gfp=False, colors=None,
ax_cb.set_yticks(np.arange(len(the_colors)))
ax_cb.set_yticklabels(np.array(color_conds)[color_order])
ax_cb.yaxis.tick_right()
ax_cb.set_xticks(())
ax_cb.set_ylabel(cmap_label)
ax_cb.set(xticks=(), ylabel=cmap_label)

plt_show(show)
return ax.figure
33 changes: 12 additions & 21 deletions mne/viz/ica.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
_helper_raw_resize, _plot_raw_onkey, plt_show)
from .topomap import (_prepare_topo_plot, plot_topomap, _hide_frame,
_plot_ica_topomap)
from .raw import _prepare_mne_browse_raw, _plot_raw_traces
from .raw import _prepare_mne_browse_raw, _plot_raw_traces, _convert_psds
from .epochs import _prepare_mne_browse_epochs, plot_epochs_image
from .evoked import _butterfly_on_button_press, _butterfly_onpick
from ..utils import warn
@@ -258,9 +258,9 @@ def set_title_and_labels(ax, title, xlab, ylab):
fig, axes = _create_properties_layout(figsize=figsize)

# spectrum
this_psd = psds[:, idx, :]
if dB:
this_psd = 10 * np.log10(this_psd)
this_psd = psds[:, idx, :].copy()
psd_ylabel = _convert_psds(this_psd, dB, estimate='auto', scaling=1.,
unit='AU', ch_names=ica.ch_names)
psds_mean = this_psd.mean(axis=0)
diffs = this_psd - psds_mean
# the distribution of power for each frequency bin is highly
@@ -301,10 +301,10 @@ def set_title_and_labels(ax, title, xlab, ylab):
# ----------
axes[0].set_title(ica._ica_names[pick])

set_title_and_labels(axes[1], 'epochs image and ERP/ERF', [], 'Epochs')
set_title_and_labels(axes[1], 'Epochs image and ERP/ERF', [], 'Epochs')

# erp
set_title_and_labels(axes[2], [], 'time', 'AU\n')
set_title_and_labels(axes[2], [], 'Time (s)', 'AU\n')
axes[2].spines["right"].set_color('k')
axes[2].set_xlim(epochs_src.times[[0, -1]])
# remove half of yticks if more than 5
@@ -320,8 +320,7 @@ def set_title_and_labels(ax, title, xlab, ylab):
axes[1].set_ylim([-0.5, ica_data.shape[1] + 0.5])

# spectrum
ylabel = 'dB' if dB else 'power'
set_title_and_labels(axes[3], 'spectrum', 'frequency', ylabel)
set_title_and_labels(axes[3], 'Spectrum', 'Frequency (Hz)', psd_ylabel)
axes[3].yaxis.labelpad = 0
axes[3].set_xlim(freqs[[0, -1]])
ylim = axes[3].get_ylim()
@@ -330,7 +329,7 @@ def set_title_and_labels(ax, title, xlab, ylab):
axes[1].axhline(0, color='k', linewidth=.5)

# epoch variance
set_title_and_labels(axes[4], 'epochs variance', 'epoch', 'AU')
set_title_and_labels(axes[4], 'Epochs variance', 'Epoch (index)', 'AU')

all_fig.append(fig)

@@ -418,10 +417,7 @@ def _plot_ica_sources_evoked(evoked, picks, exclude, title, show, ica,
lines.extend(ax.plot(times, evoked.data[ii].T, picker=3.,
color='k', zorder=1))

ax.set_title(title)
ax.set_xlim(times[[0, -1]])
ax.set_xlabel('Time (ms)')
ax.set_ylabel('(NA)')
ax.set(title=title, xlim=times[[0, -1]], xlabel='Time (ms)', ylabel='(NA)')
if len(exclude) > 0:
plt.legend(loc='best')
tight_layout(fig=fig)
@@ -613,7 +609,7 @@ def plot_ica_overlay(ica, inst, exclude=None, picks=None, start=None,
start=start, stop=stop)
data_cln, _ = raw_cln[picks, start_compare:stop_compare]
fig = _plot_ica_overlay_raw(data=data, data_cln=data_cln,
times=times * 1e3, title=title,
times=times, title=title,
ch_types_used=ch_types_used, show=show)
elif isinstance(inst, Evoked):
if start is not None and stop is not None:
@@ -652,10 +648,7 @@ def _plot_ica_overlay_raw(data, data_cln, times, title, ch_types_used, show):
plt.suptitle(title)
ax1.plot(times, data.T, color='r')
ax1.plot(times, data_cln.T, color='k')
ax1.set_xlabel('time (s)')
ax1.set_xlim(times[0], times[-1])
ax1.set_xlim(times[0], times[-1])
ax1.set_title('Raw data')
ax1.set(xlabel='Time (s)', xlim=times[[0, -1]], title='Raw data')

_ch_types = {'mag': 'Magnetometers',
'grad': 'Gradiometers',
@@ -664,9 +657,7 @@ def _plot_ica_overlay_raw(data, data_cln, times, title, ch_types_used, show):
ax2.set_title('Average across channels ({0})'.format(ch_types))
ax2.plot(times, data.mean(0), color='r')
ax2.plot(times, data_cln.mean(0), color='k')
ax2.set_xlim(100, 106)
ax2.set_xlabel('time (ms)')
ax2.set_xlim(times[0], times[-1])
ax2.set(xlabel='Time (s)', xlim=times[[0, -1]])
tight_layout(fig=fig)

fig.subplots_adjust(top=0.90)
43 changes: 20 additions & 23 deletions mne/viz/misc.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
"""Functions to make simple plots with M/EEG data."""

from __future__ import print_function
@@ -137,7 +138,7 @@ def plot_cov(cov, info, exclude=[], colorbar=True, proj=False, show_svd=True,
s[s <= 0] = 1e-10 * s[s > 0].min()
s = np.sqrt(s) * scaling
axes[0, k].plot(s)
axes[0, k].set(ylabel='Noise std (%s)' % unit, yscale='log',
axes[0, k].set(ylabel=u'Noise σ (%s)' % unit, yscale='log',
xlabel='Eigenvalue index', title=name)
tight_layout(fig=fig_svd)

@@ -224,9 +225,7 @@ def plot_source_spectrogram(stcs, freq_bins, tmin=None, tmax=None,
cmap='Reds')
ax = plt.gca()

plt.title('Time-frequency source power')
plt.xlabel('Time (s)')
plt.ylabel('Frequency (Hz)')
ax.set(title='Source power', xlabel='Time (s)', ylabel='Frequency (Hz)')

time_tick_labels = [str(np.round(t, 2)) for t in time_bounds]
n_skip = 1 + len(time_bounds) // 10
@@ -481,7 +480,7 @@ def plot_events(events, sfreq=None, first_samp=0, color=None, event_id=None,
"""
if sfreq is None:
sfreq = 1.0
xlabel = 'samples'
xlabel = 'Samples'
else:
xlabel = 'Time (s)'

@@ -542,8 +541,7 @@ def plot_events(events, sfreq=None, first_samp=0, color=None, event_id=None,
else:
ax.set_ylim([min_event - 1, max_event + 1])

ax.set_xlabel(xlabel)
ax.set_ylabel('Events id')
ax.set(xlabel=xlabel, ylabel='Events id')

ax.grid(True)

@@ -599,9 +597,7 @@ def plot_dipole_amplitudes(dipoles, colors=None, show=True):
ax.plot(dip.times, dip.amplitude * 1e9, color=color, linewidth=1.5)
xlim[0] = min(xlim[0], dip.times[0])
xlim[1] = max(xlim[1], dip.times[-1])
ax.set_xlim(xlim)
ax.set_xlabel('Time (sec)')
ax.set_ylabel('Amplitude (nAm)')
ax.set(xlim=xlim, xlabel='Time (s)', ylabel='Amplitude (nAm)')
if show:
fig.show(warn=False)
return fig
@@ -755,31 +751,32 @@ def plot_filter(h, sfreq, freq=None, gain=None, title=None, color='#1f77b4',
gd = group_delay((h, [1.]), omega)[1]
title = 'FIR filter' if title is None else title
gd /= sfreq
fig, axes = plt.subplots(3) # eventually axes could be a parameter
# eventually axes could be a parameter
fig, (ax_time, ax_freq, ax_delay) = plt.subplots(3)
t = np.arange(len(h)) / sfreq
f = omega * sfreq / (2 * np.pi)
axes[0].plot(t, h, color=color)
axes[0].set(xlim=t[[0, -1]], xlabel='Time (sec)',
ylabel='Amplitude h(n)', title=title)
ax_time.plot(t, h, color=color)
ax_time.set(xlim=t[[0, -1]], xlabel='Time (s)',
ylabel='Amplitude', title=title)
mag = 10 * np.log10(np.maximum((H * H.conj()).real, 1e-20))
axes[1].plot(f, mag, color=color, linewidth=2, zorder=4)
ax_freq.plot(f, mag, color=color, linewidth=2, zorder=4)
if freq is not None and gain is not None:
plot_ideal_filter(freq, gain, axes[1], fscale=fscale,
plot_ideal_filter(freq, gain, ax_freq, fscale=fscale,
title=None, show=False)
axes[1].set(ylabel='Magnitude (dB)', xlabel='', xscale=fscale)
ax_freq.set(ylabel='Magnitude (dB)', xlabel='', xscale=fscale)
sl = slice(0 if fscale == 'linear' else 1, None, None)
axes[2].plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4)
axes[2].set(xlim=flim, ylabel='Group delay (sec)', xlabel='Frequency (Hz)',
xscale=fscale)
ax_delay.plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4)
ax_delay.set(xlim=flim, ylabel='Group delay (s)', xlabel='Frequency (Hz)',
xscale=fscale)
xticks, xticklabels = _filter_ticks(flim, fscale)
dlim = [0, 1.05 * gd[1:].max()]
for ax, ylim, ylabel in zip(axes[1:], (alim, dlim),
('Amplitude (dB)', 'Delay (sec)')):
for ax, ylim, ylabel in ((ax_freq, alim, 'Amplitude (dB)'),
(ax_delay, dlim, 'Delay (s)')):
if xticks is not None:
ax.set(xticks=xticks)
ax.set(xticklabels=xticklabels)
ax.set(xlim=flim, ylim=ylim, xlabel='Frequency (Hz)', ylabel=ylabel)
adjust_axes(axes)
adjust_axes([ax_time, ax_freq, ax_delay])
tight_layout()
plt_show(show)
return fig
7 changes: 2 additions & 5 deletions mne/viz/raw.py
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=20,
events : array | None
Events to show with vertical bars.
duration : float
Time window (sec) to plot. The lesser of this value and the duration
Time window (s) to plot. The lesser of this value and the duration
of the raw file will be used.
start : float
Initial time to show (can be changed dynamically once plotted). If
@@ -633,10 +633,7 @@ def _convert_psds(psds, dB, estimate, scaling, unit, ch_names):
warn(msg)

if estimate == 'auto':
if dB:
estimate = 'power'
else:
estimate = 'amplitude'
estimate = 'power' if dB else 'amplitude'

if estimate == 'amplitude':
np.sqrt(psds, out=psds)
Loading

0 comments on commit dba99f1

Please sign in to comment.