Repository: mne-tools/mne-python

Issue:
Rotation axes are different between plot_alignment() and plot_field() 3D objects
`plot_alignment()` is IMHO doing the right thing, and `plot_field()` is just bein drunk 🥴



https://user-images.githubusercontent.com/2046265/174497954-c2f37a82-a9bf-4399-86e5-8eb36fb1d7ee.mov



MWE:
```python
# %%
import mne

sample_dir = mne.datasets.sample.data_path()
sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'
trans_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw-trans.fif'
fs_subjects_dir = sample_dir / 'subjects'
fs_subject = 'sample'

raw = mne.io.read_raw_fif(sample_fname)
raw.crop(tmax=60)

events = mne.find_events(raw, stim_channel='STI 014')
event_id = {'auditory/left': 1, 'auditory/right': 2, 'visual/left': 3,
            'visual/right': 4, 'face': 5, 'buttonpress': 32}

epochs = mne.Epochs(raw, events=events, event_id=event_id,
                    tmin=-0.2, tmax=0.5, baseline=(None, 0),
                    preload=True)
evoked = epochs.average()
evoked.pick_types(eeg=True)

trans = mne.read_trans(trans_fname)

field_maps = mne.make_field_map(
    evoked=evoked,
    trans=trans,
    subject=fs_subject,
    subjects_dir=fs_subjects_dir,
)

evoked.plot_field(
    surf_maps=field_maps
)
mne.viz.plot_alignment(
    info=evoked.info,
    trans=trans,
    subject=fs_subject,
    subjects_dir=fs_subjects_dir,
    surfaces=['head']
)


Discussion:
This is "just" the difference between an arcball interaction and a terrain one. I agree anything with a well defined/meaningful "up" / Z should use terrain. Feel free to make this change (it should be one line I think?) and document it as a bugfix

Resolving patch:
diff --git a/mne/evoked.py b/mne/evoked.py
--- a/mne/evoked.py
+++ b/mne/evoked.py
@@ -528,11 +528,11 @@ def plot_topomap(self, times="auto", ch_type=None, vmin=None,
     @copy_function_doc_to_method_doc(plot_evoked_field)
     def plot_field(self, surf_maps, time=None, time_label='t = %0.0f ms',
                    n_jobs=None, fig=None, vmax=None, n_contours=21,
-                   verbose=None):
+                   *, interaction='terrain', verbose=None):
         return plot_evoked_field(self, surf_maps, time=time,
                                  time_label=time_label, n_jobs=n_jobs,
                                  fig=fig, vmax=vmax, n_contours=n_contours,
-                                 verbose=verbose)
+                                 interaction=interaction, verbose=verbose)
 
     @copy_function_doc_to_method_doc(plot_evoked_white)
     def plot_white(self, noise_cov, show=True, rank=None, time_unit='s',
diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py
--- a/mne/viz/_3d.py
+++ b/mne/viz/_3d.py
@@ -306,7 +306,7 @@ def _set_aspect_equal(ax):
 @verbose
 def plot_evoked_field(evoked, surf_maps, time=None, time_label='t = %0.0f ms',
                       n_jobs=None, fig=None, vmax=None, n_contours=21,
-                      verbose=None):
+                      *, interaction='terrain', verbose=None):
     """Plot MEG/EEG fields on head surface and helmet in 3D.
 
     Parameters
@@ -334,6 +334,10 @@ def plot_evoked_field(evoked, surf_maps, time=None, time_label='t = %0.0f ms',
         The number of contours.
 
         .. versionadded:: 0.21
+    %(interaction_scene)s
+        Defaults to ``'terrain'``.
+
+        .. versionadded:: 1.1
     %(verbose)s
 
     Returns
@@ -346,6 +350,7 @@ def plot_evoked_field(evoked, surf_maps, time=None, time_label='t = %0.0f ms',
     types = [t for t in ['eeg', 'grad', 'mag'] if t in evoked]
     _validate_type(vmax, (None, 'numeric'), 'vmax')
     n_contours = _ensure_int(n_contours, 'n_contours')
+    _check_option('interaction', interaction, ['trackball', 'terrain'])
 
     time_idx = None
     if time is None:
@@ -365,6 +370,7 @@ def plot_evoked_field(evoked, surf_maps, time=None, time_label='t = %0.0f ms',
                                      np.tile([255., 0., 0., 255.], (127, 1))])
 
     renderer = _get_renderer(fig, bgcolor=(0.0, 0.0, 0.0), size=(600, 600))
+    renderer.set_interaction(interaction)
 
     for ii, this_map in enumerate(surf_maps):
         surf = this_map['surf']


Test patch: