Skip to content

[MRG] plot_ica_properties #3275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 62 commits into from
Jun 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ae90d83
first sketch of plot_properties
mmagnuski Jun 1, 2016
c00db72
ax -> axes, now axes returned correctly
mmagnuski Jun 2, 2016
5886a41
pep8
mmagnuski Jun 2, 2016
347768a
input checks
mmagnuski Jun 2, 2016
25069ec
more pep8
mmagnuski Jun 2, 2016
eb256cc
segment_raw
mmagnuski Jun 2, 2016
66ecc4a
support plot_ica_properties for Raw inst
mmagnuski Jun 2, 2016
6cd0d00
rename skeleton to something less scary, change fig size, add axis la…
mmagnuski Jun 3, 2016
726fb1e
_validate_if_list_of_axes comes to life
mmagnuski Jun 3, 2016
fda3a77
add axes kwarg to plot_epochs_image
mmagnuski Jun 3, 2016
367e286
address some of the comments
mmagnuski Jun 4, 2016
2ac3628
forgot to add this - do not use 'smart segment length'
mmagnuski Jun 4, 2016
0a3d4d7
declutter: set axis ticklabels font size to 8
mmagnuski Jun 4, 2016
e3bdc01
use plot_epochs_image in plot_properties
mmagnuski Jun 4, 2016
c68f464
new kwargs, add some air to freq plot
mmagnuski Jun 4, 2016
953f600
make flake more happy (still one more left)
mmagnuski Jun 4, 2016
649df75
make flake happy
mmagnuski Jun 4, 2016
f83fe45
_plot_ica_topomap
mmagnuski Jun 6, 2016
9cc0dd4
test for validate_if_list_of_axes
mmagnuski Jun 6, 2016
abfe7ec
plot_std param
mmagnuski Jun 6, 2016
34df9ee
docstring and cleanup
mmagnuski Jun 6, 2016
703e2c5
fix docstring, add plot_properties method for ica
mmagnuski Jun 6, 2016
d73a7f0
add plot_properties test
mmagnuski Jun 6, 2016
95d951d
pep8, flake
mmagnuski Jun 6, 2016
2a0c1f6
address comments
mmagnuski Jun 6, 2016
b9eba08
add show param
mmagnuski Jun 6, 2016
def2de5
revert removing verbose arg
mmagnuski Jun 6, 2016
51ad0f8
be happy, flake
mmagnuski Jun 6, 2016
0ce0ae2
_validate_if_list... accepts flat numpy arrays, some tests
mmagnuski Jun 7, 2016
034ab95
little fix to plot_properties and more tests
mmagnuski Jun 7, 2016
7adc9fa
segment method for _BaseRaw
mmagnuski Jun 7, 2016
2de5797
address comments
mmagnuski Jun 7, 2016
a43ad90
psd_kws param
mmagnuski Jun 7, 2016
388b72a
fix circular import
mmagnuski Jun 7, 2016
e38cb0f
fixes
mmagnuski Jun 7, 2016
326dd13
allow segment_length to be int
mmagnuski Jun 8, 2016
d5ea637
fix docstring, pass psd_kws from ica method to plot_properties
mmagnuski Jun 8, 2016
d76f53a
fix test for psd_kws
mmagnuski Jun 8, 2016
b661a01
this is for you, flake
mmagnuski Jun 8, 2016
1674e05
fix two-figures bug
mmagnuski Jun 8, 2016
de59279
multiple picks -> multiple figures + test
mmagnuski Jun 8, 2016
4dd10a3
flake, add sigma param
mmagnuski Jun 8, 2016
d736d40
fix empty slice warning
mmagnuski Jun 11, 2016
9942e34
fix y label issue
mmagnuski Jun 11, 2016
e057900
adress comments, speed up tests a little
mmagnuski Jun 12, 2016
b91214c
fix test
mmagnuski Jun 12, 2016
0644a32
change tutorial on ICA and one example
mmagnuski Jun 12, 2016
95e397c
make flake happy
mmagnuski Jun 12, 2016
e60b41a
add figsize and some fixes
mmagnuski Jun 12, 2016
0b18bb2
fix docstring
mmagnuski Jun 12, 2016
71dbf13
speed up tests, increase coverage
mmagnuski Jun 12, 2016
b5bb30d
address comments
mmagnuski Jun 14, 2016
fd10115
set random_state when during ICA construction
mmagnuski Jun 14, 2016
836d0f5
fix arg names in the test
mmagnuski Jun 15, 2016
b4af3dd
set fmax based on lowpass, lowpass vline, fix
mmagnuski Jun 15, 2016
6846398
update what's new, address comment
mmagnuski Jun 15, 2016
016302a
address another round of comments
mmagnuski Jun 16, 2016
67dc7c2
address comments
mmagnuski Jun 17, 2016
ecf063f
address comments
mmagnuski Jun 17, 2016
bd53c60
rename to plot_ica_properties, remove cmap arg
mmagnuski Jun 24, 2016
1a79787
fix whats_new
mmagnuski Jun 25, 2016
e859433
fix flake, remove _plot_ica_grid added by accident during rebase
mmagnuski Jun 25, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Changelog

- Add label center of mass function :func:`mne.Label.center_of_mass` by `Eric Larson`_

- Added :func:`mne.viz.ica.plot_ica_properties` that allows ploting of independent component properties similar to ``pop_prop`` in EEGLAB. Also :class:`mne.preprocessing.ica.ICA` has :func:`mne.preprocessing.ica.ICA.plot_properties` method now. Added by `Mikołaj Magnuski`_

BUG
~~~

Expand Down Expand Up @@ -59,6 +61,8 @@ API

- :func:`mne.concatenate_epochs` and :func:`mne.compute_covariance` now check to see if all :class:`Epochs` instances have the same MEG-to-Head transformation, and errors by default if they do not by `Eric Larson`_

- Added option to pass a list of axes to :func:`mne.viz.epochs.plot_epochs_image` by `Mikołaj Magnuski`_

.. _changes_0_12:

Version 0.12
Expand Down Expand Up @@ -1603,3 +1607,5 @@ of commits):
.. _Pablo-Arias: https://github.com/Pablo-Arias

.. _Alexander Rudiuk: https://github.com/ARudiuk

.. _Mikołaj Magnuski: https://github.com/mmagnuski
1 change: 1 addition & 0 deletions examples/preprocessing/plot_run_ica.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@
ecg_inds, scores = ica.find_bads_ecg(ecg_epochs)

ica.plot_components(ecg_inds)
ica.plot_properties(epochs, picks=ecg_inds)
28 changes: 27 additions & 1 deletion mne/epochs.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from .channels.channels import (ContainsMixin, UpdateChannelsMixin,
SetChannelsMixin, InterpolationMixin)
from .filter import resample, detrend, FilterMixin
from .event import _read_events_fif
from .event import _read_events_fif, make_fixed_length_events
from .fixes import in1d, _get_args
from .viz import (plot_epochs, plot_epochs_psd, plot_epochs_psd_topomap,
plot_epochs_image, plot_topo_image_epochs)
Expand Down Expand Up @@ -3112,3 +3112,29 @@ def average_movements(epochs, head_pos=None, orig_sfreq=None, picks=None,
_remove_meg_projs(evoked) # remove MEG projectors, they won't apply now
logger.info('Created Evoked dataset from %s epochs' % (count,))
return (evoked, mapping) if return_mapping else evoked


@verbose
def _segment_raw(raw, segment_length=1., verbose=None, **kwargs):
"""Divide continuous raw data into equal-sized
consecutive epochs.

Parameters
----------
raw : instance of Raw
Raw data to divide into segments.
segment_length : float
Length of each segment in seconds. Defaults to 1.
verbose: bool
Whether to report what is being done by printing text.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also doc that **kwargs will be passed to Epochs

**kwargs
Any additional keyword arguments are passed to ``Epochs`` constructor.

Returns
-------
epochs : instance of ``Epochs``
Segmented data.
"""
events = make_fixed_length_events(raw, 1, duration=segment_length)
return Epochs(raw, events, event_id=[1], tmin=0., tmax=segment_length,
verbose=verbose, baseline=None, **kwargs)
11 changes: 9 additions & 2 deletions mne/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,15 @@ def make_fixed_length_events(raw, id, start=0, stop=None, duration=1.,
new_events : array
The new events.
"""
from .io.base import _BaseRaw
if not isinstance(raw, _BaseRaw):
raise ValueError('Input data must be an instance of Raw, got'
' %s instead.' % (type(raw)))
if not isinstance(id, int):
raise ValueError('id must be an integer')
if not isinstance(duration, (int, float)):
raise ValueError('duration must be an integer of a float, '
'got %s instead.' % (type(duration)))
start = raw.time_as_index(start)[0]
if stop is not None:
stop = raw.time_as_index(stop)[0]
Expand All @@ -775,8 +784,6 @@ def make_fixed_length_events(raw, id, start=0, stop=None, duration=1.,
stop = min([stop + raw.first_samp, raw.last_samp + 1])
else:
stop = min([stop, len(raw.times)])
if not isinstance(id, int):
raise ValueError('id must be an integer')
# Make sure we don't go out the end of the file:
stop -= int(np.ceil(raw.info['sfreq'] * duration))
# This should be inclusive due to how we generally use start and stop...
Expand Down
53 changes: 53 additions & 0 deletions mne/preprocessing/ica.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from ..epochs import _BaseEpochs
from ..viz import (plot_ica_components, plot_ica_scores,
plot_ica_sources, plot_ica_overlay)
from ..viz.ica import plot_ica_properties
from ..viz.utils import (_prepare_trellis, tight_layout, plt_show,
_setup_vmin_vmax)
from ..viz.topomap import (_prepare_topo_plot, _check_outlines,
Expand Down Expand Up @@ -1400,6 +1401,58 @@ def plot_components(self, picks=None, ch_type=None, res=64, layout=None,
image_interp=image_interp,
head_pos=head_pos)

def plot_properties(self, inst, picks=None, axes=None, dB=True,
plot_std=True, topomap_args=None, image_args=None,
psd_args=None, figsize=None, show=True):
"""Display component properties: topography, epochs image, ERP,
power spectrum and epoch variance.

Parameters
----------
inst: instance of Epochs or Raw
The data to use in plotting properties.
picks : int | array-like of int | None
The components to be displayed. If None, plot will show the first
five sources. If more than one components were chosen in the picks,
each one will be plotted in a separate figure. Defaults to None.
axes: list of matplotlib axes | None
List of five matplotlib axes to use in plotting: [topo_axis,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

topomap_axis?

image_axis, erp_axis, spectrum_axis, variance_axis]. If None a new
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agramfort I have called it ts_axis (for time series axis) in plot_joint, but maybe ERP would be better?

figure with relevant axes is created. Defaults to None.
dB: bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would set dB =True by default

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, that would be better.

Whether to plot spectrum in dB. Defaults to True.
plot_std: bool | float
Whether to plot standard deviation in ERP/ERF and spectrum plots.
Defaults to True, which plots one standard deviation above/below.
If set to float allows to control how many standard deviations are
plotted. For example 2.5 will plot 2.5 standard deviation
above/below.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess True would be cast to int ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To 1., I mean.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do it explicitly in the code - if bool then set relevant variable to 1.
Do you mean it's unnecessary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. I guess it's okay.

topomap_args : dict | None
Dictionary of arguments to ``plot_topomap``. If None, doesn't pass
any additional arguments. Defaults to None.
image_args : dict | None
Dictionary of arguments to ``plot_epochs_image``. If None, doesn't
pass any additional arguments. Defaults to None.
psd_args : dict | None
Dictionary of arguments to ``psd_multitaper``. If None, doesn't
pass any additional arguments. Defaults to None.
figsize : array-like of size (2,) | None
Allows to control size of the figure. If None the figure size
defauls to [7., 6.].
show : bool
Show figure if True.

Returns
-------
fig : list
List of matplotlib figures.
"""
return plot_ica_properties(inst, self, picks=picks, axes=axes,
dB=dB, plot_std=plot_std,
topomap_args=topomap_args,
image_args=image_args, psd_args=psd_args,
figsize=figsize, show=show)

def plot_sources(self, inst, picks=None, exclude=None, start=None,
stop=None, title=None, show=True, block=False):
"""Plot estimated latent sources given the unmixing matrix.
Expand Down
5 changes: 5 additions & 0 deletions mne/tests/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ def test_make_fixed_length_events():
# With bad limits (no resulting events)
assert_raises(ValueError, make_fixed_length_events, raw, 1,
tmin, tmax - 1e-3, duration)
# not raw, bad id or duration
assert_raises(ValueError, make_fixed_length_events, raw, 2.3)
assert_raises(ValueError, make_fixed_length_events, 'not raw', 2)
assert_raises(ValueError, make_fixed_length_events, raw, 23, tmin, tmax,
'abc')


def test_define_events():
Expand Down
30 changes: 24 additions & 6 deletions mne/viz/epochs.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
def plot_epochs_image(epochs, picks=None, sigma=0., vmin=None,
vmax=None, colorbar=True, order=None, show=True,
units=None, scalings=None, cmap='RdBu_r',
fig=None, overlay_times=None):
fig=None, axes=None, overlay_times=None):
"""Plot Event Related Potential / Fields image

Parameters
Expand Down Expand Up @@ -71,6 +71,11 @@ def plot_epochs_image(epochs, picks=None, sigma=0., vmin=None,
Figure instance to draw the image to. Figure must contain two axes for
drawing the single trials and evoked responses. If None a new figure is
created. Defaults to None.
axes : list of matplotlib axes | None
List of axes instances to draw the image, erp and colorbar to.
Must be of length three if colorbar is True (with the last list element
being the colorbar axes) or two if colorbar is False. If both fig and
axes are passed an error is raised. Defaults to None.
overlay_times : array-like, shape (n_epochs,) | None
If not None the parameter is interpreted as time instants in seconds
and is added to the image. It is typically useful to display reaction
Expand All @@ -95,8 +100,20 @@ def plot_epochs_image(epochs, picks=None, sigma=0., vmin=None,
raise ValueError('Scalings and units must have the same keys.')

picks = np.atleast_1d(picks)
if fig is not None and len(picks) > 1:
if (fig is not None or axes is not None) and len(picks) > 1:
raise ValueError('Only single pick can be drawn to a figure.')
if axes is not None:
if fig is not None:
raise ValueError('Both figure and axes were passed, please'
'decide between the two.')
from .utils import _validate_if_list_of_axes
oblig_len = 3 if colorbar else 2
_validate_if_list_of_axes(axes, obligatory_len=oblig_len)
ax1, ax2 = axes[:2]
# if axes were passed - we ignore fig param and get figure from axes
fig = ax1.get_figure()
if colorbar:
ax3 = axes[-1]
evoked = epochs.average(picks)
data = epochs.get_data()[:, picks, :]
scale_vmin = True if vmin is None else False
Expand Down Expand Up @@ -154,7 +171,11 @@ def plot_epochs_image(epochs, picks=None, sigma=0., vmin=None,
this_data = ndimage.gaussian_filter1d(this_data, sigma=sigma,
axis=0)
plt.figure(this_fig.number)
ax1 = plt.subplot2grid((3, 10), (0, 0), colspan=9, rowspan=2)
if axes is None:
ax1 = plt.subplot2grid((3, 10), (0, 0), colspan=9, rowspan=2)
ax2 = plt.subplot2grid((3, 10), (2, 0), colspan=9, rowspan=1)
if colorbar:
ax3 = plt.subplot2grid((3, 10), (0, 9), colspan=1, rowspan=3)
if scale_vmin:
vmin *= scalings[ch_type]
if scale_vmax:
Expand All @@ -167,9 +188,6 @@ def plot_epochs_image(epochs, picks=None, sigma=0., vmin=None,
if this_overlay_times is not None:
plt.plot(1e3 * this_overlay_times, 0.5 + np.arange(len(this_data)),
'k', linewidth=2)
ax2 = plt.subplot2grid((3, 10), (2, 0), colspan=9, rowspan=1)
if colorbar:
ax3 = plt.subplot2grid((3, 10), (0, 9), colspan=1, rowspan=3)
ax1.set_title(epochs.ch_names[idx])
ax1.set_ylabel('Epochs')
ax1.axis('auto')
Expand Down
Loading