Skip to content
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

[MRG] Forward argument axes from plot_sensors to DigMontage.plot #11470

Merged
merged 12 commits into from
Feb 15, 2023
1 change: 1 addition & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Enhancements
- Adjusted the algorithm used in :class:`mne.decoding.SSD` to support non-full rank data (:gh:`11458` by :newcontrib:`Thomas Binns`)
- Changed suggested type for ``ch_groups``` in `mne.viz.plot_sensors` from array to list of list(s) (arrays are still supported). (:gh:`11465` by `Hyonyoung Shin`_)
- Add support for UCL/FIL OPM data using :func:`mne.io.read_raw_fil` (:gh:`11366` by :newcontrib:`George O'Neill` and `Robert Seymour`_)
- Forward argument ``axes`` from `mne.viz.plot_sensors` to `mne.channels.DigMontage.plot` (:gh:`11470` by :newcontrib:`Jan Ebert` and `Mathieu Scheltienne`_)
- Added ability to read stimulus durations from SNIRF files when using :func:`mne.io.read_raw_snirf` (:gh:`11397` by `Robert Luke`_)
- Add :meth:`mne.Info.save` to save an :class:`mne.Info` object to a fif file (:gh:`11401` by `Alex Rockhill`_)
- Improved error message when downloads are corrupted for :func:`mne.datasets.sample.data_path` and related functions (:gh:`11407` by `Eric Larson`_)
Expand Down
26 changes: 14 additions & 12 deletions doc/changes/names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@

.. _Denis Engemann: http://denis-engemann.de

.. _Dinara Issagaliyeva: https://github.com/dissagaliyeva

.. _Dirk Gütlin: https://github.com/DiGyt

.. _Dmitrii Altukhov: https://github.com/dmalt
Expand Down Expand Up @@ -178,6 +180,8 @@

.. _Hamid Maymandi: https://github.com/HamidMandi

.. _Hakimeh Pourakbari: https://github.com/Hpakbari

.. _Hari Bharadwaj: http://www.haribharadwaj.com

.. _Henrich Kolkhorst: https://github.com/hekolk
Expand All @@ -200,6 +204,8 @@

.. _Jair Montoya Martinez: https://github.com/jmontoyam

.. _Jan Ebert: https://www.jan-ebert.com/

.. _Jan Sedivy: https://github.com/honzaseda

.. _Jan Sosulski: https://jan-sosulski.de
Expand All @@ -214,6 +220,8 @@

.. _Jeff Stout: https://megcore.nih.gov/index.php/Staff

.. _Jennifer Behnke: https://github.com/JKBehnke

.. _Jeroen Van Der Donckt: https://github.com/jvdd

.. _Jesper Duemose Nielsen: https://github.com/jdue
Expand Down Expand Up @@ -378,6 +386,8 @@

.. _Paul Roujansky: https://github.com/paulroujansky

.. _Pavel Navratil: https://github.com/navrpa13

.. _Peter Molfese: https://github.com/pmolfese

.. _Phillip Alday: https://palday.bitbucket.io
Expand Down Expand Up @@ -492,6 +502,8 @@

.. _Theodore Papadopoulo: https://github.com/papadop

.. _Thomas Binns: https://github.com/tsbinns

.. _Thomas Hartmann: https://github.com/thht

.. _Thomas Radman: https://github.com/tradman
Expand All @@ -500,6 +512,8 @@

.. _Tod Flak: https://github.com/todflak

.. _Tom Ma: https://github.com/myd7349

.. _Tommy Clausner: https://github.com/TommyClausner

.. _Toomas Erik Anijärv: http://www.toomaserikanijarv.com/
Expand All @@ -523,15 +537,3 @@
.. _Yu-Han Luo: https://github.com/yh-luo

.. _Zhi Zhang: https://github.com/tczhangzhi/

.. _Dinara Issagaliyeva: https://github.com/dissagaliyeva

.. _Jennifer Behnke: https://github.com/JKBehnke

.. _Hakimeh Pourakbari: https://github.com/Hpakbari

.. _Pavel Navratil: https://github.com/navrpa13

.. _Tom Ma: https://github.com/myd7349

.. _Thomas Binns: https://github.com/tsbinns
4 changes: 2 additions & 2 deletions mne/channels/montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ def __repr__(self):

@copy_function_doc_to_method_doc(plot_montage)
def plot(self, scale_factor=20, show_names=True, kind='topomap', show=True,
sphere=None, verbose=None):
sphere=None, *, axes=None, verbose=None):
return plot_montage(self, scale_factor=scale_factor,
show_names=show_names, kind=kind, show=show,
sphere=sphere)
sphere=sphere, axes=axes)

@fill_doc
def rename_channels(self, mapping, allow_duplicates=False):
Expand Down
11 changes: 11 additions & 0 deletions mne/channels/tests/test_montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,17 @@ def test_plot_montage():
montage.plot()
plt.close('all')

f, ax = plt.subplots(1, 1)
montage.plot(axes=ax)
mscheltienne marked this conversation as resolved.
Show resolved Hide resolved
plt.close("all")

with pytest.raises(TypeError, match="must be an instance of Axes"):
montage.plot(axes=101)
with pytest.raises(TypeError, match="when 'kind' is '3d'"):
montage.plot(axes=ax, kind="3d")
with pytest.raises(TypeError, match="when 'kind' is '3d'"):
montage.plot(axes=101, kind="3d")


def test_montage_equality():
"""Test montage equality."""
Expand Down
4 changes: 4 additions & 0 deletions mne/utils/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
docdict['axes_evoked_plot_topomap'] = _axes_list.format(
'axes',
'match the number of ``times`` provided (unless ``times`` is ``None``)')
docdict['axes_montage'] = """
axes : instance of Axes | instance of Axes3D | None
Axes to draw the sensors to. If ``kind='3d'``, axes must be an instance
of Axes3D. If None (default), a new axes will be created."""
docdict['axes_plot_projs_topomap'] = _axes_list.format(
'axes', 'match the number of projectors')
docdict['axes_plot_topomap'] = _axes_base.format('axes', '', '', '')
Expand Down
12 changes: 10 additions & 2 deletions mne/viz/montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

@verbose
def plot_montage(montage, scale_factor=20, show_names=True, kind='topomap',
show=True, sphere=None, verbose=None):
show=True, sphere=None, *, axes=None, verbose=None):
"""Plot a montage.

Parameters
Expand All @@ -25,7 +25,15 @@ def plot_montage(montage, scale_factor=20, show_names=True, kind='topomap',
show : bool
Show figure if True.
%(sphere_topomap_auto)s
%(axes_montage)s

.. versionadded:: 1.4
%(verbose)s
axes : instance of Axes | instance of Axes3D | None
Axes to draw the sensors to. If ``kind='3d'``, axes must be an instance
of Axes3D. If None (default), a new axes will be created.

.. versionadded:: 1.4.0
larsoner marked this conversation as resolved.
Show resolved Hide resolved

Returns
-------
Expand Down Expand Up @@ -69,7 +77,7 @@ def plot_montage(montage, scale_factor=20, show_names=True, kind='topomap',
info = create_info(ch_names, sfreq=256, ch_types="eeg")
info.set_montage(montage, on_missing='ignore')
fig = plot_sensors(info, kind=kind, show_names=show_names, show=show,
title=title, sphere=sphere)
title=title, sphere=sphere, axes=axes)
collection = fig.axes[0].collections[0]
collection.set_sizes([scale_factor])
return fig
52 changes: 34 additions & 18 deletions mne/viz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,16 +908,17 @@ def plot_sensors(info, kind='topomap', ch_type=None, title=None,
%(info_not_none)s
kind : str
Whether to plot the sensors as 3d, topomap or as an interactive
sensor selection dialog. Available options 'topomap', '3d', 'select'.
If 'select', a set of channels can be selected interactively by using
lasso selector or clicking while holding control key. The selected
channels are returned along with the figure instance. Defaults to
'topomap'.
sensor selection dialog. Available options ``'topomap'``, ``'3d'``,
``'select'``. If ``'select'``, a set of channels can be selected
interactively by using lasso selector or clicking while holding control
key. The selected channels are returned along with the figure instance.
Defaults to ``'topomap'``.
ch_type : None | str
The channel type to plot. Available options 'mag', 'grad', 'eeg',
'seeg', 'dbs', 'ecog', 'all'. If ``'all'``, all the available mag,
grad, eeg, seeg, dbs and ecog channels are plotted. If None (default),
then channels are chosen in the order given above.
The channel type to plot. Available options ``'mag'``, ``'grad'``,
``'eeg'``, ``'seeg'``, ``'dbs'``, ``'ecog'``, ``'all'``. If ``'all'``,
all the available mag, grad, eeg, seeg, dbs and ecog channels are
plotted. If None (default), then channels are chosen in the order given
above.
title : str | None
Title for the figure. If None (default), equals to
``'Sensor positions (%%s)' %% ch_type``.
Expand All @@ -936,12 +937,10 @@ def plot_sensors(info, kind='topomap', ch_type=None, title=None,
to_sphere : bool
Whether to project the 3d locations to a sphere. When False, the
sensor array appears similar as to looking downwards straight above the
subject's head. Has no effect when kind='3d'. Defaults to True.
subject's head. Has no effect when ``kind='3d'``. Defaults to True.

.. versionadded:: 0.14.0
axes : instance of Axes | instance of Axes3D | None
Axes to draw the sensors to. If ``kind='3d'``, axes must be an instance
of Axes3D. If None (default), a new axes will be created.
%(axes_montage)s

.. versionadded:: 0.13.0
block : bool
Expand All @@ -953,10 +952,10 @@ def plot_sensors(info, kind='topomap', ch_type=None, title=None,
Show figure if True. Defaults to True.
%(sphere_topomap_auto)s
pointsize : float | None
The size of the points. If None (default), will bet set to 75 if
``kind='3d'``, or 25 otherwise.
The size of the points. If None (default), will bet set to ``75`` if
``kind='3d'``, or ``25`` otherwise.
linewidth : float
The width of the outline. If 0, the outline will not be drawn.
The width of the outline. If ``0``, the outline will not be drawn.
%(verbose)s

Returns
Expand All @@ -980,8 +979,25 @@ def plot_sensors(info, kind='topomap', ch_type=None, title=None,
"""
from .evoked import _rgb
_check_option('kind', kind, ['topomap', '3d', 'select'])
if not isinstance(info, Info):
raise TypeError(f'info must be an instance of Info not {type(info)}')
if axes is not None:
from matplotlib.axes import Axes
from mpl_toolkits.mplot3d.axes3d import Axes3D

if kind == "3d":
_validate_type(axes, Axes3D, "axes", extra="when 'kind' is '3d'")
elif kind in ("topomap", "select"):
_validate_type(
axes,
Axes,
"axes",
extra="when 'kind' is 'topomap' or 'select'"
)
if isinstance(axes, Axes3D):
raise TypeError(
"axes must be an instance of Axes when 'kind' is "
f"'topomap' or 'select', got {type(axes)} instead."
)
_validate_type(info, Info, "info")
ch_indices = channel_indices_by_type(info)
allowed_types = _DATA_CH_TYPES_SPLIT
if ch_type is None:
Expand Down