Skip to content

Commit 36bcfd3

Browse files
MAINT: register the vtk.js renderer as a 3D backend
Replaces the _activate monkeypatching with a real "jupyterlite" backend so it works with the pytest renderer fixtures. Also fixes the glyph templates, which drew spheres at twice their size and EEG cylinders off their own axis.
1 parent 6e68585 commit 36bcfd3

10 files changed

Lines changed: 839 additions & 597 deletions

File tree

doc/changes/dev/14144.other.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Add a vtk.js drawing backend for MNE's 3D renderer in ``mne/viz/backends/_lite.py``, used by the JupyterLite documentation where VTK cannot load, by `Natneal B`_.
1+
Add a vtk.js drawing backend for MNE's 3D renderer, selected with ``mne.viz.set_3d_backend("jupyterlite")`` and used by the JupyterLite documentation where VTK cannot load, by `Natneal B`_.

doc/sphinxext/jupyterlite_lite_renderer.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
# Copyright the MNE-Python contributors.
1313

1414
LITE_RENDERER_CELL = """
15-
# Using pyvista-js (vtk.js) to draw MNE's 3D rendering in JupyterLite.
15+
# Draw MNE's 3D figures with pyvista-js (vtk.js): VTK has no WebAssembly build.
1616
# See mne/viz/backends/_lite.py for more details.
1717
try:
18-
from mne.viz.backends._lite import _activate as _mne_activate_lite_renderer
18+
import mne.viz
1919
20-
_mne_activate_lite_renderer()
20+
mne.viz.set_3d_backend("jupyterlite")
2121
except Exception as _e:
22-
print("[JupyterLite] could not install the pyvista-js renderer: " + repr(_e))
22+
print("[JupyterLite] could not select the pyvista-js renderer: " + repr(_e))
2323
"""

mne/conftest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,22 @@ def renderer_notebook(request, options_3d):
755755
yield renderer
756756

757757

758+
@pytest.fixture(params=[pytest.param("jupyterlite", marks=pytest.mark.pvtest)])
759+
def renderer_lite(request, options_3d):
760+
"""Yield the JupyterLite (vtk.js) renderer."""
761+
from mne.viz.backends import renderer as renderer_module
762+
763+
# use_3d_backend only puts a backend back if one was already selected, and
764+
# this one draws for a browser, so make sure it is never what a later test
765+
# inherits
766+
was = (renderer_module.MNE_3D_BACKEND, renderer_module.backend)
767+
try:
768+
with _use_backend(request.param, interactive=False) as renderer:
769+
yield renderer
770+
finally:
771+
renderer_module.MNE_3D_BACKEND, renderer_module.backend = was
772+
773+
758774
@pytest.fixture(params=[pytest.param("pyvistaqt", marks=pytest.mark.pvtest)])
759775
def renderer_interactive_pyvistaqt(request, options_3d, qt_windows_closed):
760776
"""Yield the interactive PyVista backend."""
@@ -798,6 +814,10 @@ def _use_backend(backend_name, interactive):
798814
def _check_skip_backend(name):
799815
from mne.viz.backends._utils import _notebook_vtk_works
800816

817+
if name == "jupyterlite":
818+
# draws with vtk.js in a browser: no VTK, no Qt, no ffmpeg
819+
pytest.importorskip("pyvista_js")
820+
return
801821
pytest.importorskip("pyvista")
802822
pytest.importorskip("imageio_ffmpeg")
803823
if name == "pyvistaqt":

mne/viz/_3d.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ def plot_alignment(
841841

842842
# initialize figure
843843
renderer = _get_renderer(
844-
fig,
844+
fig=fig,
845845
name=f"Sensor alignment: {subject}",
846846
bgcolor=(0.5, 0.5, 0.5),
847847
size=(800, 800),
@@ -3931,7 +3931,7 @@ def snapshot_brain_montage(fig, montage, hide_sensors=True):
39313931
)
39323932

39333933
# initialize figure
3934-
renderer = _get_renderer(fig, show=True)
3934+
renderer = _get_renderer(fig=fig, show=True)
39353935

39363936
xyz = np.vstack(xyz)
39373937
proj = renderer.project(xyz=xyz, ch_names=ch_names)

0 commit comments

Comments
 (0)