Skip to content

Commit 5009ee8

Browse files
cbrnrdrammock
andauthored
Tweak y-axis label (#13298)
Co-authored-by: Daniel McCloy <dan@mccloy.info>
1 parent 6ad8823 commit 5009ee8

File tree

7 files changed

+47
-40
lines changed

7 files changed

+47
-40
lines changed

doc/changes/devel/13298.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix y-axis label in PSD plot when ``dB=True`` to show a more conventional label (i.e., dB/Hz or dB/√Hz), by `Clemens Brunner`_.

mne/time_frequency/spectrum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,8 +606,8 @@ def plot(
606606
Whether to plot an amplitude spectrum (``True``) or power spectrum
607607
(``False``).
608608
609-
.. versionchanged:: 1.8
610-
In version 1.8, the default changed to ``amplitude=False``.
609+
.. versionchanged:: 1.8
610+
In version 1.8, the default changed to ``amplitude=False``.
611611
%(xscale_plot_psd)s
612612
ci : float | 'sd' | 'range' | None
613613
Type of confidence band drawn around the mean when ``average=True``. If

mne/time_frequency/tfr.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,7 +1960,7 @@ def plot(
19601960
19611961
How baseline is computed is determined by the ``mode`` parameter.
19621962
%(mode_tfr_plot)s
1963-
%(dB_spectrum_plot)s
1963+
%(dB_tfr_plot)s
19641964
%(combine_tfr_plot)s
19651965
19661966
.. versionchanged:: 1.3
@@ -2215,7 +2215,7 @@ def plot_joint(
22152215
22162216
How baseline is computed is determined by the ``mode`` parameter.
22172217
%(mode_tfr_plot)s
2218-
%(dB_tfr_plot_topo)s
2218+
%(dB_tfr_plot)s
22192219
%(yscale_tfr_plot)s
22202220
%(vlim_tfr_plot_joint)s
22212221
%(cnorm)s
@@ -2508,7 +2508,7 @@ def plot_topo(
25082508
%(layout_spectrum_plot_topo)s
25092509
%(cmap_tfr_plot_topo)s
25102510
%(title_none)s
2511-
%(dB_tfr_plot_topo)s
2511+
%(dB_tfr_plot)s
25122512
%(colorbar)s
25132513
%(layout_scale)s
25142514
%(show)s

mne/utils/docs.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,32 +1013,36 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
10131013

10141014
_dB = """
10151015
dB : bool
1016-
Whether to plot on a decibel-like scale. If ``True``, plots
1017-
10 × log₁₀({quantity}){caveat}.{extra}
1016+
Whether to plot on a decibel scale. If ``True``, plots
1017+
10 × log₁₀({quantity}){ampl}{caveat}.{extra}
10181018
"""
1019-
_ignored_if_normalize = " Ignored if ``normalize=True``."
1020-
_psd = "spectral power"
1019+
_psd = "spectral_power/Hz"
10211020

1021+
# for the legacy func/methods:
10221022
docdict["dB_plot_psd"] = """\
10231023
dB : bool
1024-
Plot Power Spectral Density (PSD), in units (amplitude**2/Hz (dB)) if
1025-
``dB=True``, and ``estimate='power'`` or ``estimate='auto'``. Plot PSD
1026-
in units (amplitude**2/Hz) if ``dB=False`` and,
1027-
``estimate='power'``. Plot Amplitude Spectral Density (ASD), in units
1028-
(amplitude/sqrt(Hz)), if ``dB=False`` and ``estimate='amplitude'`` or
1029-
``estimate='auto'``. Plot ASD, in units (amplitude/sqrt(Hz) (dB)), if
1030-
``dB=True`` and ``estimate='amplitude'``.
1024+
Plot power spectral density (PSD) in units (dB/Hz) if ``dB=True`` and
1025+
``estimate='power'``. Plot PSD in units (amplitude**2/Hz) if
1026+
``dB=False`` and ``estimate='power'``. Plot amplitude spectral density (ASD) in
1027+
units (amplitude/sqrt(Hz)) if ``dB=False`` and ``estimate='amplitude'``.
1028+
Plot ASD in units (dB/sqrt(Hz)) if ``dB=True`` and ``estimate='amplitude'``.
10311029
"""
10321030
docdict["dB_plot_topomap"] = _dB.format(
10331031
quantity=_psd,
1034-
caveat=" following the application of ``agg_fun``",
1035-
extra=_ignored_if_normalize,
1032+
ampl="",
1033+
caveat=", following the application of ``agg_fun``",
1034+
extra=" Ignored if ``normalize=True``.",
1035+
)
1036+
docdict["dB_spectrum_plot"] = _dB.format(
1037+
quantity=_psd,
1038+
ampl=", or 20 × log₁₀(spectral amplitude/√Hz) if ``amplitude=True``",
1039+
caveat="",
1040+
extra="",
10361041
)
1037-
docdict["dB_spectrum_plot"] = _dB.format(quantity=_psd, caveat="", extra="")
10381042
docdict["dB_spectrum_plot_topo"] = _dB.format(
1039-
quantity=_psd, caveat="", extra=_ignored_if_normalize
1043+
quantity=_psd, ampl="", caveat="", extra=""
10401044
)
1041-
docdict["dB_tfr_plot_topo"] = _dB.format(quantity="data", caveat="", extra="")
1045+
docdict["dB_tfr_plot"] = _dB.format(quantity="data", ampl="", caveat="", extra="")
10421046

10431047
_data_template = """
10441048
data : ndarray, shape ({})

mne/viz/tests/test_raw.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,15 @@ def test_plot_raw_filtered(filtorder, raw, browser_backend):
987987
RawArray(np.zeros((1, 100)), create_info(1, 20.0, "stim")).plot(lowpass=5)
988988

989989

990+
def _check_ylabel_psd(ylabel, amplitude, dB, unit):
991+
"""Check that the ylabel is correct."""
992+
numerator = "dB" if dB else unit
993+
denominator = r"\sqrt{\mathrm{Hz}}" if amplitude else r"\mathrm{Hz}"
994+
reference_val = rf"\ \mathrm{{re}}\ 1\ \mathrm{{{unit}}}" if dB else ""
995+
pattern = rf"\mathrm{{{numerator}}}/{denominator}{reference_val}"
996+
assert pattern in ylabel, ylabel
997+
998+
990999
def test_plot_raw_psd(raw, raw_orig):
9911000
"""Test plotting of raw psds."""
9921001
raw_unchanged = raw.copy()
@@ -1038,24 +1047,20 @@ def test_plot_raw_psd(raw, raw_orig):
10381047
with pytest.warns(UserWarning, match="[Infinite|Zero]"):
10391048
spectrum = raw.compute_psd()
10401049
for dB, amplitude in itertools.product((True, False), (True, False)):
1041-
with pytest.warns(UserWarning, match="[Infinite|Zero]"):
1050+
with pytest.warns(UserWarning, match="(Infinite|Zero)"):
10421051
fig = spectrum.plot(average=True, dB=dB, amplitude=amplitude)
10431052
# check grad axes
10441053
title = fig.axes[0].get_title()
10451054
ylabel = fig.axes[0].get_ylabel()
1046-
unit = r"fT/cm/\sqrt{Hz}" if amplitude else "(fT/cm)²/Hz"
1055+
unit = "fT/cm" if amplitude else "(fT/cm)^2"
10471056
assert title == "Gradiometers", title
1048-
assert unit in ylabel, ylabel
1049-
if dB:
1050-
assert "dB" in ylabel
1051-
else:
1052-
assert "dB" not in ylabel
1057+
_check_ylabel_psd(ylabel, amplitude, dB, unit)
10531058
# check mag axes
10541059
title = fig.axes[1].get_title()
10551060
ylabel = fig.axes[1].get_ylabel()
1056-
unit = r"fT/\sqrt{Hz}" if amplitude else "fT²/Hz"
1061+
unit = "fT" if amplitude else "fT^2"
10571062
assert title == "Magnetometers", title
1058-
assert unit in ylabel, ylabel
1063+
_check_ylabel_psd(ylabel, amplitude, dB, unit)
10591064

10601065
# test xscale value checking
10611066
raw = raw_unchanged

mne/viz/utils.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,25 +2431,22 @@ def _convert_psds(
24312431
warn(msg, UserWarning)
24322432

24332433
_check_option("estimate", estimate, ("power", "amplitude"))
2434+
psds *= scaling * scaling
2435+
denom = r"\sqrt{\mathrm{Hz}}" if estimate == "amplitude" else r"\mathrm{Hz}"
24342436
if estimate == "amplitude":
24352437
np.sqrt(psds, out=psds)
2436-
psds *= scaling
2437-
ylabel = rf"$\mathrm{{{unit}/\sqrt{{Hz}}}}$"
24382438
coef = 20
24392439
else:
2440-
psds *= scaling * scaling
24412440
if "/" in unit:
24422441
unit = f"({unit})"
2443-
ylabel = rf"$\mathrm{{{unit}²/Hz}}$"
2442+
unit = f"{unit}^2"
24442443
coef = 10
2444+
ylabel = rf"$\mathrm{{{unit}}}/{denom}$"
24452445
if dB:
24462446
np.log10(np.maximum(psds, np.finfo(float).tiny), out=psds)
24472447
psds *= coef
2448-
ylabel = r"$\mathrm{dB}\ $" + ylabel
2449-
ylabel = "Power (" + ylabel if estimate == "power" else "Amplitude (" + ylabel
2450-
ylabel += ")"
2451-
2452-
return ylabel
2448+
ylabel = rf"$\mathrm{{dB}}/{denom}\ \mathrm{{re}}\ 1\ \mathrm{{{unit}}}$"
2449+
return f"{'Power' if estimate == 'power' else 'Amplitude'} ({ylabel})"
24532450

24542451

24552452
def _plot_psd(

tutorials/time-freq/10_spectrum_class.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
# (interpolated scalp topography of power, in specific frequency bands). A few
124124
# plot options are demonstrated below; see the docstrings for full details.
125125

126-
evk_spectrum.plot(picks="data", exclude="bads", amplitude=False)
126+
evk_spectrum.plot(picks="data", exclude="bads")
127127
evk_spectrum.plot_topo(color="k", fig_facecolor="w", axis_facecolor="w")
128128

129129
# %%

0 commit comments

Comments
 (0)