Repository: mne-tools/mne-python

Issue:
plot_psd(xscale='log') does not work in jupyter notebook
Steps to reproduce:

```py
%matplotlib inline
import mne
from mne.datasets import sample

data_path = sample.data_path()
fname = data_path + '/MEG/sample/sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(fname)
raw.plot_psd(xscale='log')
```

you'll get an error like this:

```py
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/anaconda3/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
    242 
    243     if 'png' in formats:
--> 244         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    245     if 'retina' in formats or 'png2x' in formats:
    246         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
    126 
    127     bytes_io = BytesIO()
--> 128     fig.canvas.print_figure(bytes_io, **kw)
    129     data = bytes_io.getvalue()
    130     if fmt == 'svg':

~/anaconda3/lib/python3.7/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
   2080                     orientation=orientation,
   2081                     bbox_inches_restore=_bbox_inches_restore,
-> 2082                     **kwargs)
   2083             finally:
   2084                 if bbox_inches and restore_bbox:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args, **kwargs)
    525 
    526         else:
--> 527             FigureCanvasAgg.draw(self)
    528             renderer = self.get_renderer()
    529             with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in draw(self)
    384         Draw the figure using the renderer.
    385         """
--> 386         self.renderer = self.get_renderer(cleared=True)
    387         with RendererAgg.lock:
    388             self.figure.draw(self.renderer)

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in get_renderer(self, cleared)
    397                           and getattr(self, "_lastKey", None) == key)
    398         if not reuse_renderer:
--> 399             self.renderer = RendererAgg(w, h, self.figure.dpi)
    400             self._lastKey = key
    401         elif cleared:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in __init__(self, width, height, dpi)
     84         self.width = width
     85         self.height = height
---> 86         self._renderer = _RendererAgg(int(width), int(height), dpi)
     87         self._filter_renderers = []
     88 

ValueError: Image size of 115104x291 pixels is too large. It must be less than 2^16 in each direction.

<Figure size 432x288 with 6 Axes>

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/anaconda3/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
    242 
    243     if 'png' in formats:
--> 244         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    245     if 'retina' in formats or 'png2x' in formats:
    246         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
    126 
    127     bytes_io = BytesIO()
--> 128     fig.canvas.print_figure(bytes_io, **kw)
    129     data = bytes_io.getvalue()
    130     if fmt == 'svg':

~/anaconda3/lib/python3.7/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
   2080                     orientation=orientation,
   2081                     bbox_inches_restore=_bbox_inches_restore,
-> 2082                     **kwargs)
   2083             finally:
   2084                 if bbox_inches and restore_bbox:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args, **kwargs)
    525 
    526         else:
--> 527             FigureCanvasAgg.draw(self)
    528             renderer = self.get_renderer()
    529             with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in draw(self)
    384         Draw the figure using the renderer.
    385         """
--> 386         self.renderer = self.get_renderer(cleared=True)
    387         with RendererAgg.lock:
    388             self.figure.draw(self.renderer)

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in get_renderer(self, cleared)
    397                           and getattr(self, "_lastKey", None) == key)
    398         if not reuse_renderer:
--> 399             self.renderer = RendererAgg(w, h, self.figure.dpi)
    400             self._lastKey = key
    401         elif cleared:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in __init__(self, width, height, dpi)
     84         self.width = width
     85         self.height = height
---> 86         self._renderer = _RendererAgg(int(width), int(height), dpi)
     87         self._filter_renderers = []
     88 

ValueError: Image size of 115104x291 pixels is too large. It must be less than 2^16 in each direction.
```

also the validation of inputs is not proper. If I use `xscale='blah'`, it does not crash


Discussion:

Resolving patch:
diff --git a/mne/viz/evoked.py b/mne/viz/evoked.py
--- a/mne/viz/evoked.py
+++ b/mne/viz/evoked.py
@@ -489,7 +489,8 @@ def _plot_lines(data, info, picks, fig, axes, spatial_colors, unit, units,
             texts.append(ax.text(0, 0, 'blank', zorder=3,
                                  verticalalignment='baseline',
                                  horizontalalignment='left',
-                                 fontweight='bold', alpha=0))
+                                 fontweight='bold', alpha=0,
+                                 clip_on=True))
 
             if xlim is not None:
                 if xlim == 'tight':
diff --git a/mne/viz/utils.py b/mne/viz/utils.py
--- a/mne/viz/utils.py
+++ b/mne/viz/utils.py
@@ -3025,15 +3025,9 @@ def _set_psd_plot_params(info, proj, picks, ax, area_mode):
 
     fig = None
     if ax is None:
-        fig = plt.figure()
-        ax_list = list()
-        for ii in range(len(picks_list)):
-            # Make x-axes change together
-            if ii > 0:
-                ax_list.append(plt.subplot(len(picks_list), 1, ii + 1,
-                                           sharex=ax_list[0]))
-            else:
-                ax_list.append(plt.subplot(len(picks_list), 1, ii + 1))
+        fig, ax_list = plt.subplots(len(picks_list), 1, sharex=True,
+                                    squeeze=False)
+        ax_list = list(ax_list[:, 0])
         make_label = True
     else:
         fig = ax_list[0].get_figure()
@@ -3120,6 +3114,7 @@ def _plot_psd(inst, fig, freqs, psd_list, picks_list, titles_list,
     from matplotlib.ticker import ScalarFormatter
     from .evoked import _plot_lines
     sphere = _check_sphere(sphere, inst.info)
+    _check_option('xscale', xscale, ('log', 'linear'))
 
     for key, ls in zip(['lowpass', 'highpass', 'line_freq'],
                        ['--', '--', '-.']):
@@ -3194,7 +3189,7 @@ def _plot_psd(inst, fig, freqs, psd_list, picks_list, titles_list,
             ax.set(xscale='log')
             ax.set(xlim=[freqs[1] if freqs[0] == 0 else freqs[0], freqs[-1]])
             ax.get_xaxis().set_major_formatter(ScalarFormatter())
-        else:
+        else:  # xscale == 'linear'
             ax.set(xlim=(freqs[0], freqs[-1]))
         if make_label:
             if ii == len(picks_list) - 1:


Test patch:
diff --git a/mne/viz/tests/test_raw.py b/mne/viz/tests/test_raw.py
--- a/mne/viz/tests/test_raw.py
+++ b/mne/viz/tests/test_raw.py
@@ -415,6 +415,10 @@ def test_plot_raw_psd():
     with pytest.raises(ValueError, match='not exceed one half the sampling'):
         raw.plot_psd(fmax=50000)
 
+    # test xscale value checking
+    with pytest.raises(ValueError, match="Invalid value for the 'xscale'"):
+        raw.plot_psd(xscale='blah')
+
     # gh-5046
     raw = read_raw_fif(raw_fname, preload=True).crop(0, 1)
     picks = pick_types(raw.info)