diff --git a/doc/changes/devel/13298.bugfix.rst b/doc/changes/devel/13298.bugfix.rst new file mode 100644 index 00000000000..70ff289a0b7 --- /dev/null +++ b/doc/changes/devel/13298.bugfix.rst @@ -0,0 +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`_. \ No newline at end of file diff --git a/mne/utils/docs.py b/mne/utils/docs.py index e6df37a01d2..388aa1e0ce1 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1013,7 +1013,7 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): _dB = """ dB : bool - Whether to plot on a decibel-like scale. If ``True``, plots + Whether to plot on a decibel scale. If ``True``, plots 10 × log₁₀({quantity}){caveat}.{extra} """ _ignored_if_normalize = " Ignored if ``normalize=True``." @@ -1021,13 +1021,12 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): docdict["dB_plot_psd"] = """\ dB : bool - Plot Power Spectral Density (PSD), in units (amplitude**2/Hz (dB)) if - ``dB=True``, and ``estimate='power'`` or ``estimate='auto'``. Plot PSD - in units (amplitude**2/Hz) if ``dB=False`` and, - ``estimate='power'``. Plot Amplitude Spectral Density (ASD), in units - (amplitude/sqrt(Hz)), if ``dB=False`` and ``estimate='amplitude'`` or - ``estimate='auto'``. Plot ASD, in units (amplitude/sqrt(Hz) (dB)), if - ``dB=True`` and ``estimate='amplitude'``. + Plot power spectral density (PSD) in units (dB/Hz) if ``dB=True`` and + ``estimate='power'`` or ``estimate='auto'``. Plot PSD in units (amplitude**2/Hz) if + ``dB=False`` and ``estimate='power'``. Plot amplitude spectral density (ASD) in + units (amplitude/sqrt(Hz)) if ``dB=False`` and ``estimate='amplitude'`` or + ``estimate='auto'``. Plot ASD in units (dB/sqrt(Hz)) if ``dB=True`` and + ``estimate='amplitude'``. """ docdict["dB_plot_topomap"] = _dB.format( quantity=_psd, diff --git a/mne/viz/tests/test_raw.py b/mne/viz/tests/test_raw.py index d8c0caea477..e3ad81132bd 100644 --- a/mne/viz/tests/test_raw.py +++ b/mne/viz/tests/test_raw.py @@ -987,6 +987,19 @@ def test_plot_raw_filtered(filtorder, raw, browser_backend): RawArray(np.zeros((1, 100)), create_info(1, 20.0, "stim")).plot(lowpass=5) +def _check_ylabel_psd(ylabel, amplitude, dB, unit): + """Check that the ylabel is correct.""" + if amplitude: + assert r"\sqrt{Hz}" in ylabel + else: + assert "Hz" in ylabel and r"\sqrt{Hz}" not in ylabel + if dB: + assert "dB" in ylabel + else: + assert unit in ylabel, ylabel + assert "dB" not in ylabel + + def test_plot_raw_psd(raw, raw_orig): """Test plotting of raw psds.""" raw_unchanged = raw.copy() @@ -1045,17 +1058,13 @@ def test_plot_raw_psd(raw, raw_orig): ylabel = fig.axes[0].get_ylabel() unit = r"fT/cm/\sqrt{Hz}" if amplitude else "(fT/cm)²/Hz" assert title == "Gradiometers", title - assert unit in ylabel, ylabel - if dB: - assert "dB" in ylabel - else: - assert "dB" not in ylabel + _check_ylabel_psd(ylabel, amplitude, dB, unit) # check mag axes title = fig.axes[1].get_title() ylabel = fig.axes[1].get_ylabel() unit = r"fT/\sqrt{Hz}" if amplitude else "fT²/Hz" assert title == "Magnetometers", title - assert unit in ylabel, ylabel + _check_ylabel_psd(ylabel, amplitude, dB, unit) # test xscale value checking raw = raw_unchanged diff --git a/mne/viz/utils.py b/mne/viz/utils.py index fe7e2a48714..d8298461e61 100644 --- a/mne/viz/utils.py +++ b/mne/viz/utils.py @@ -2445,7 +2445,10 @@ def _convert_psds( if dB: np.log10(np.maximum(psds, np.finfo(float).tiny), out=psds) psds *= coef - ylabel = r"$\mathrm{dB}\ $" + ylabel + if estimate == "amplitude": + ylabel = r"$\mathrm{dB/\sqrt{Hz}}$" + else: + ylabel = r"$\mathrm{dB/Hz}$" ylabel = "Power (" + ylabel if estimate == "power" else "Amplitude (" + ylabel ylabel += ")"