Repository: mne-tools/mne-python

Issue:
'matplotlib' backend for stc.plot is broken
#### Describe the bug

Missing

```python
from mpl_toolkits.mplot3d import Axes3
```

in `mne.viz._3d._plot_mpl_stc`

#### Steps to reproduce

Generic to any example

```python
data_path = somato.data_path()
subject = '01'
task = 'somato'
...
stc_mne = apply_inverse(evoked, inv, lambda2, method='MNE', pick_ori="normal",
                        return_residual=False, verbose=True)

brain = stc_mne.plot(subjects_dir=subjects_dir, hemi='rh', surface='inflated',
                     smoothing_steps='nearest', view_layout='vertical',
                     backend='matplotlib')
```

#### Expected results

A static plot using the `matplotlib` backend showing a 3D rendering of a surface.

#### Actual results

```python
Using control points [6.56993144e-11 7.80732925e-11 1.82440323e-10]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/projections/__init__.py in get_projection_class(projection)
     57     try:
---> 58         return projection_registry.get_projection_class(projection)
     59     except KeyError:

~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/projections/__init__.py in get_projection_class(self, name)
     24         """
---> 25         return self._all_projection_types[name]
     26 

KeyError: '3d'

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
~/src/git/hnn-core/examples/plot_simulate_somato.py in <module>
----> 1 stc_mne.plot(backend='matplotlib')

~/src/git/mne-python/mne/source_estimate.py in plot(self, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
    662             src=src, volume_options=volume_options, view_layout=view_layout,
    663             add_data_kwargs=add_data_kwargs, brain_kwargs=brain_kwargs,
--> 664             verbose=verbose)
    665         return brain
    666 

<decorator-gen-142> in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)

~/src/git/mne-python/mne/viz/_3d.py in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
   1826         transparent=transparent)
   1827     if plot_mpl:
-> 1828         return _plot_mpl_stc(stc, spacing=spacing, **kwargs)
   1829     return _plot_stc(
   1830         stc, overlay_alpha=alpha, brain_alpha=alpha, vector_alpha=alpha,

~/src/git/mne-python/mne/viz/_3d.py in _plot_mpl_stc(***failed resolving arguments***)
   1524     time_label, times = _handle_time(time_label, time_unit, stc.times)
   1525     fig = plt.figure(figsize=(6, 6)) if figure is None else figure
-> 1526     ax = fig.gca(projection='3d')
   1527     hemi_idx = 0 if hemi == 'lh' else 1
   1528     surf = op.join(subjects_dir, subject, 'surf', '%s.%s' % (hemi, surface))

~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/figure.py in gca(self, **kwargs)
   1930 
   1931         # no axes found, so create one which spans the figure
-> 1932         return self.add_subplot(1, 1, 1, **kwargs)
   1933 
   1934     def sca(self, a):

~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/figure.py in add_subplot(self, *args, **kwargs)
   1394         else:
   1395             projection_class, kwargs, key = \
-> 1396                 self._process_projection_requirements(*args, **kwargs)
   1397 
   1398             # try to find the axes with this key in the stack

~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/figure.py in _process_projection_requirements(self, polar, projection, *args, **kwargs)
   1118 
   1119         if isinstance(projection, str) or projection is None:
-> 1120             projection_class = projections.get_projection_class(projection)
   1121         elif hasattr(projection, '_as_mpl_axes'):
   1122             projection_class, extra_kwargs = projection._as_mpl_axes()

~/miniconda3/envs/hnn_dev/lib/python3.7/site-packages/matplotlib/projections/__init__.py in get_projection_class(projection)
     58         return projection_registry.get_projection_class(projection)
     59     except KeyError:
---> 60         raise ValueError("Unknown projection %r" % projection)
     61 
     62 

ValueError: Unknown projection '3d'
```

#### Additional information

PR will follow...


Discussion:

Resolving patch:
diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py
--- a/mne/viz/_3d.py
+++ b/mne/viz/_3d.py
@@ -245,7 +245,7 @@ def plot_head_positions(pos, mode='traces', cmap='viridis', direction='z',
     else:  # mode == 'field':
         from matplotlib.colors import Normalize
         from mpl_toolkits.mplot3d.art3d import Line3DCollection
-        from mpl_toolkits.mplot3d import axes3d  # noqa: F401, analysis:ignore
+        from mpl_toolkits.mplot3d import Axes3D  # noqa: F401, analysis:ignore
         fig, ax = plt.subplots(1, subplot_kw=dict(projection='3d'))
 
         # First plot the trajectory as a colormap:
@@ -1488,6 +1488,7 @@ def _plot_mpl_stc(stc, subject=None, surface='inflated', hemi='lh',
                   transparent=True):
     """Plot source estimate using mpl."""
     import matplotlib.pyplot as plt
+    from mpl_toolkits.mplot3d import Axes3D  # noqa: F401, analysis:ignore
     from matplotlib import cm
     from matplotlib.widgets import Slider
     import nibabel as nib


Test patch: