Repository: mne-tools/mne-python

Issue:
BUG: raw.plot_psd(ax=ax) does not plot into ax
For me both of these are permitted but neither plots into the correct axes, both pop up a new figure:
```Python
>>> import mne
>>> import matplotlib.pyplot as plt
>>> raw = mne.io.read_raw_fif(mne.datasets.testing.data_path() / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif').pick('eeg')
>>> fig, ax = plt.subplots()
>>> raw.plot_psd(axes=ax)
<MNELineFigure size 1000x350 with 2 Axes>
>>> raw.plot_psd(ax=ax)
<MNELineFigure size 1000x350 with 2 Axes>
>>> print(len(plt.get_fignums()))
3
```
Based on the [1.0 docs](https://mne.tools/1.0/generated/mne.io.Raw.html#mne.io.Raw.plot_psd) for example `ax=ax` should plot into the existing `ax` and `axes=...` should raise for invalid keyword.

@drammock can you look?


Discussion:
```
import mne
import matplotlib.pyplot as plt

fname = mne.datasets.testing.data_path() / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif'
raw = mne.io.read_raw_fif(fname).pick('eeg')
fig, ax = plt.subplots()
raw.plot_psd(ax=ax)
```

For me, this one works correctly, and the keyword `axes` is not defined in `plot_psd` signature, I would not expect that one to work, but it does not raise.
> For me, this one works correctly

Okay I checked on another system of mine and this case was okay there. So maybe I'm on some `dev` version of matplotlib on my other machine or something... I'll investigate more but hopefully we can ignore this for now!

> the keyword axes is not defined in plot_psd signature, I would not expect that one to work, but it does not raise.

Indeed this part at least seems to be a bug. It's especially weird since it *does* raise for other options like `invalid_kwarg`, but not `axes`.
just a note that I can see why this is happening but haven't had a chance to implement the fix today, will do tomorrow.

Resolving patch:
diff --git a/mne/utils/spectrum.py b/mne/utils/spectrum.py
--- a/mne/utils/spectrum.py
+++ b/mne/utils/spectrum.py
@@ -1,4 +1,5 @@
 from inspect import currentframe, getargvalues, signature
+from ..utils import warn
 
 
 def _pop_with_fallback(mapping, key, fallback_fun):
@@ -15,13 +16,23 @@ def _update_old_psd_kwargs(kwargs):
     """
     from ..viz import plot_raw_psd as fallback_fun
 
-    kwargs["axes"] = _pop_with_fallback(kwargs, "ax", fallback_fun)
-    kwargs["alpha"] = _pop_with_fallback(kwargs, "line_alpha", fallback_fun)
-    kwargs["ci_alpha"] = _pop_with_fallback(kwargs, "area_alpha", fallback_fun)
+    may_change = ("axes", "alpha", "ci_alpha", "amplitude", "ci")
+    for kwarg in may_change:
+        if kwarg in kwargs:
+            warn(
+                "The legacy plot_psd() method got an unexpected keyword argument "
+                f"'{kwarg}', which is a parameter of Spectrum.plot(). Try rewriting as "
+                f"object.compute_psd(...).plot(..., {kwarg}=<whatever>)."
+            )
+    kwargs.setdefault("axes", _pop_with_fallback(kwargs, "ax", fallback_fun))
+    kwargs.setdefault("alpha", _pop_with_fallback(kwargs, "line_alpha", fallback_fun))
+    kwargs.setdefault(
+        "ci_alpha", _pop_with_fallback(kwargs, "area_alpha", fallback_fun)
+    )
     est = _pop_with_fallback(kwargs, "estimate", fallback_fun)
-    kwargs["amplitude"] = "auto" if est == "auto" else (est == "amplitude")
+    kwargs.setdefault("amplitude", "auto" if est == "auto" else (est == "amplitude"))
     area_mode = _pop_with_fallback(kwargs, "area_mode", fallback_fun)
-    kwargs["ci"] = "sd" if area_mode == "std" else area_mode
+    kwargs.setdefault("ci", "sd" if area_mode == "std" else area_mode)
 
 
 def _split_psd_kwargs(*, plot_fun=None, kwargs=None):


Test patch:
diff --git a/mne/time_frequency/tests/test_spectrum.py b/mne/time_frequency/tests/test_spectrum.py
--- a/mne/time_frequency/tests/test_spectrum.py
+++ b/mne/time_frequency/tests/test_spectrum.py
@@ -373,3 +373,16 @@ def test_spectrum_complex(method, average):
         coef = coef.mean(-1)  # over segments
     coef = coef.item()
     assert_allclose(np.angle(coef), phase, rtol=1e-4)
+
+
+def test_spectrum_kwarg_triaging(raw):
+    """Test kwarg triaging in legacy plot_psd() method."""
+    import matplotlib.pyplot as plt
+
+    regex = r"legacy plot_psd\(\) method.*unexpected keyword.*'axes'.*Try rewriting"
+    fig, axes = plt.subplots(1, 2)
+    # `axes` is the new param name: technically only valid for Spectrum.plot()
+    with pytest.warns(RuntimeWarning, match=regex):
+        raw.plot_psd(axes=axes)
+    # `ax` is the correct legacy param name
+    raw.plot_psd(ax=axes)