Skip to content

Commit

Permalink
Update to newly renamed ipyvtklink (#1267)
Browse files Browse the repository at this point in the history
* Update to use renamed ipyvtklink

* Add deprecation notice

* Update ipyvtklink versions

* Formatting

* Fix typo

* Bump ipyvtklink version

* Set ipyvtklink as jupyter backend by default in example notebooks

* Set default notebook backend to ipyvtklink

* Always fallback to static notebook output

* Use conda-forge ipyvtklink

* ipyvtklink works on Jupyterlab 3
  • Loading branch information
banesullivan committed Apr 15, 2021
1 parent 8af2c4a commit 6201fc1
Show file tree
Hide file tree
Showing 17 changed files with 71 additions and 58 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ Overview of Features

* Extensive gallery of examples (see `Quick Examples`_)
* Interactive plotting in Jupyter Notebooks using server-side rendering
with `ipyvtk_simple`_ or client-side rendering with ``panel`` or ``ipygany``.
with `ipyvtklink`_ or client-side rendering with ``panel`` or ``ipygany``.
* Filtering/plotting tools built for interactivity (see `Widgets`_)
* Direct access to mesh analysis and transformation routines (see Filters_)
* Intuitive plotting routines with ``matplotlib`` similar syntax (see Plotting_)
* Import meshes from many common formats (use ``pyvista.read()``). Support for all formats handled by `meshio`_ is built-in!
* Export meshes as VTK, STL, OBJ, or PLY (``mesh.save()``) file types or any formats supported by meshio_ (``pyvista.save_meshio()``)

.. _ipyvtk_simple: https://github.com/Kitware/ipyvtk-simple
.. _ipyvtklink: https://github.com/Kitware/ipyvtklink
.. _Widgets: https://docs.pyvista.org/plotting/widgets.html
.. _Filters: https://docs.pyvista.org/core/filters.html
.. _Plotting: https://docs.pyvista.org/plotting/index.html
Expand Down
4 changes: 2 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ RUN conda env update --name base --file /tmp/environment.yml
RUN conda run conda install -y nodejs
RUN conda run jupyter labextension install $(cat /tmp/labextensions.txt)

RUN pip install ipyvtk-simple==0.1.2
RUN pip install ipyvtklink==0.2.1

# allow jupyterlab for ipyvtk
ENV DISPLAY=:99.0
ENV JUPYTER_ENABLE_LAB=yes
ENV PYVISTA_USE_IPYVTK=true

# modify the CMD and start a background server first
CMD /bin/bash -c "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" && start-notebook.sh
CMD /bin/bash -c "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" && start-notebook.sh
4 changes: 2 additions & 2 deletions docker_dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN conda env update --name base --file /tmp/environment.yml
RUN conda run conda install -y nodejs
RUN conda run jupyter labextension install $(cat /tmp/labextensions.txt)

RUN pip install ipyvtk-simple==0.1.2
RUN pip install ipyvtklink==0.2.1

# COPY vtk-9.0.20201105-cp38-cp38-linux_x86_64.whl /tmp/
# RUN pip install /tmp/vtk-9.0.20201105-cp38-cp38-linux_x86_64.whl
Expand All @@ -39,4 +39,4 @@ ENV JUPYTER_ENABLE_LAB=yes
ENV PYVISTA_USE_IPYVTK=true

# modify the CMD and start a background server first
CMD /bin/bash -c "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" && start-notebook.sh
CMD /bin/bash -c "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" && start-notebook.sh
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
"image_scrapers": ('pyvista', 'matplotlib'),
'first_notebook_cell': ("%matplotlib inline\n"
"from pyvista import set_plot_theme\n"
"set_plot_theme('document')"),
"set_plot_theme('document')\n"),
}


Expand Down Expand Up @@ -207,7 +207,7 @@
# -- Options for gettext output -------------------------------------------

# To specify names to enable gettext extracting and translation applying for i18n additionally. You can specify below names:
gettext_additional_targets = ['raw']
gettext_additional_targets = ['raw']

# -- Options for manual page output ---------------------------------------

Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ The following are a list of optional dependencies and their purpose:
+-----------------------------------+-----------------------------------------+
| ``itkwidgets`` | Interactive notebook rendering |
+-----------------------------------+-----------------------------------------+
| ``ipyvtk_simple`` | Interactive notebook rendering |
| ``ipyvtklink`` | Interactive notebook rendering |
+-----------------------------------+-----------------------------------------+
| ``sphinx_gallery`` | Capturing PyVista output for docs |
+-----------------------------------+-----------------------------------------+
Expand Down Expand Up @@ -201,7 +201,7 @@ After logging into the remote server, install Miniconda and related packages:
conda create --name vtk_env python=3.7
conda activate vtk_env
conda install nodejs # required when importing pyvista in Jupyter
pip install jupyter pyvista ipyvtk_simple
pip install jupyter pyvista ipyvtklink
# To avoid "ModuleNotFoundError: No module named 'vtkOpenGLKitPython' " when importing vtk
# https://stackoverflow.com/q/32389599
Expand Down
6 changes: 3 additions & 3 deletions docs/jupyter/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The PyVista module supports a variety of backends when plotting within
a jupyter notebook:

* Server-side rendering with PyVista streaming to the notebook through
`ipyvtk-simple <https://github.com/Kitware/ipyvtk-simple/>`_
`ipyvtklink <https://github.com/Kitware/ipyvtklink/>`_
* Client-side rendering with `ipygany <https://github.com/QuantStack/ipygany>`_ using ``threejs``.
* Client-side rendering using `panel <https://github.com/holoviz/panel>`_ using ``vtk.js``.
* Client-side rendering with `itkwidgets <https://github.com/InsightSoftwareConsortium/itkwidgets>`_ using ``itk.js`` and ``vtk.js``.
Expand Down Expand Up @@ -97,12 +97,12 @@ jupyter notebook plotting modules:
+---------------+--------------+--------------------+---------+----------------------+
| ipygany | Yes | Client | threejs | No |
+---------------+--------------+--------------------+---------+----------------------+
| ipyvtk_simple | No | Server | vtk | Yes |
| ipyvtklink | Yes | Server | vtk | Yes |
+---------------+--------------+--------------------+---------+----------------------+
| itkwidgets | No | Client | vtk.js | Yes |
+---------------+--------------+--------------------+---------+----------------------+

At the moment, ``itkwidgets`` and ``ipyvtk_simple`` are incompatible
At the moment, ``itkwidgets`` and ``ipyvtklink`` are incompatible
with Jupyterlab 3, and will result in a "Error displaying widget:
model not found" message from juptyer. Additionally, all the modules
other than ``ipygany`` require a framebuffer, which can be setup on a
Expand Down
6 changes: 3 additions & 3 deletions docs/jupyter/ipyvtk_plotting.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
.. _ipyvtk_plotting:

Using ``ipyvtk-simple`` with PyVista
Using ``ipyvtklink`` with PyVista
------------------------------------

.. note::
As of version ``0.1.4``, ``ipyvtk-simple`` does not support
As of version ``0.1.4``, ``ipyvtklink`` does not support
Jupyterlab 3. Attempting to run the following will return a
``Model not found`` error within jupyterlab.

``pyvista`` has the ability to display fully featured plots within a
JupyterLab environment using ``ipyvtk-simple``. This feature works by
JupyterLab environment using ``ipyvtklink``. This feature works by
streaming the current render window to a canvas within JupyterLab and
then passing any user actions from the canvas back to the VTK render
window.
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ dependencies:
- pyembree
- panel
- ipygany
- ipyvtklink
- pip:
- pytest-memprof
- ipyvtk-simple>=0.1.2
25 changes: 17 additions & 8 deletions pyvista/jupyter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .. import rcParams
from .itkplotter import PlotterITK

ALLOWED_BACKENDS = ['ipyvtk_simple', 'panel', 'ipygany', 'static', 'none']
ALLOWED_BACKENDS = ['ipyvtklink', 'panel', 'ipygany', 'static', 'none']


def check_backend_env_var():
Expand All @@ -21,11 +21,11 @@ def set_jupyter_backend(backend):
backend : str
Jupyter backend to use when plotting. Must be one of the following:
* ``'ipyvtk_simple'`` : Render remotely and stream the
* ``'ipyvtklink'`` : Render remotely and stream the
resulting VTK images back to the client. Supports all VTK
methods, but suffers from lag due to remote rendering.
Requires that a virtual framebuffer be setup when displaying
on a headless server. Must have ``ipyvtk_simple`` installed.
on a headless server. Must have ``ipyvtklink`` installed.
* ``'panel'`` : Convert the VTK render window to a vtkjs
object and then visualize that within jupyterlab. Supports
Expand Down Expand Up @@ -60,9 +60,9 @@ def set_jupyter_backend(backend):
>>> pv.set_jupyter_backend('panel')
Enable the ipyvtk_simple backend.
Enable the ipyvtklink backend.
>>> pv.set_jupyter_backend('ipyvtk_simple')
>>> pv.set_jupyter_backend('ipyvtklink')
Just show static images.
Expand All @@ -84,17 +84,26 @@ def set_jupyter_backend(backend):
except ImportError: # pragma: no cover
raise ImportError('Install IPython to display with pyvista in a notebook.')

if backend == 'ipyvtk_simple':
try:
import ipyvtklink
except ImportError:
raise ImportError('Please install `ipyvtklink`. `ipyvtk_simple` '
'is deprecated.')
else:
backend = 'ipyvtklink'

if backend not in ALLOWED_BACKENDS:
backend_list_str = ', '.join([f'"{item}"' for item in ALLOWED_BACKENDS])
raise ValueError(f'Invalid Jupyter notebook plotting backend "{backend}".\n'
f'Use one of the following:\n{backend_list_str}')

# verify required packages are installed
if backend == 'ipyvtk_simple':
if backend == 'ipyvtklink':
try:
import ipyvtk_simple
import ipyvtklink
except ImportError: # pragma: no cover
raise ImportError('Please install `ipyvtk-simple` to use this feature')
raise ImportError('Please install `ipyvtklink` to use this feature')

if backend == 'panel':
try:
Expand Down
32 changes: 18 additions & 14 deletions pyvista/jupyter/notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
Includes:
* ``ipyvtk_simple``
* ``ipyvtklink``
* ``panel``
* ``ipyvtk_simple``
"""
import warnings
Expand Down Expand Up @@ -44,13 +43,18 @@ def handle_plotter(plotter, backend=None, screenshot=None,
"""
if screenshot is False:
screenshot = None
if backend == 'ipyvtk_simple':
return show_ipyvtk(plotter, return_viewer)
if backend == 'panel':
return show_panel(plotter, return_viewer)
if backend == 'ipygany':
from pyvista.jupyter.pv_ipygany import show_ipygany
return show_ipygany(plotter, return_viewer, **kwargs)

try:
if backend == 'ipyvtklink':
return show_ipyvtk(plotter, return_viewer)
if backend == 'panel':
return show_panel(plotter, return_viewer)
if backend == 'ipygany':
from pyvista.jupyter.pv_ipygany import show_ipygany
return show_ipygany(plotter, return_viewer, **kwargs)
except ImportError as e:
warnings.warn(f'Failed to use notebook backend: \n\n{e}\n\n'
'Falling back to a static output.')

return show_static_image(plotter, screenshot, return_viewer)

Expand All @@ -69,26 +73,26 @@ def show_static_image(plotter, screenshot, return_viewer):
# point to keeping the plotter around.
plotter.close()

# Simply display the result: either ipyvtk_simple object or image display
# Simply display the result: either ipyvtklink object or image display
if return_viewer:
return image
else:
display.display(image)


def show_ipyvtk(plotter, return_viewer):
"""Display an interactive viewer widget using ``ipyvtk_simple``."""
"""Display an interactive viewer widget using ``ipyvtklink``."""
if any('SPYDER' in name for name in os.environ):
warnings.warn('``use_ipyvtk`` is incompatible with Spyder.\n'
'Use notebook=False for interactive '
'plotting within spyder or disable it globally with:\n'
'pyvista.set_jupyter_backend(None)')

try:
from ipyvtk_simple.viewer import ViewInteractiveWidget
from ipyvtklink.viewer import ViewInteractiveWidget
except ImportError: # pragma: no cover
raise ImportError('Please install `ipyvtk_simple` to use this feature:'
'\thttps://github.com/Kitware/ipyvtk-simple')
raise ImportError('Please install `ipyvtklink` to use this feature: '
'https://github.com/Kitware/ipyvtklink')

# Have to leave the Plotter open for the widget to use
disp = ViewInteractiveWidget(plotter.ren_win, on_close=plotter.close,
Expand Down
4 changes: 2 additions & 2 deletions pyvista/plotting/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ def plot(var_item, off_screen=None, full_screen=False, screenshot=None,
use_ipyvtk : bool, optional
Deprecated. Instead, set the backend either globally with
``pyvista.set_jupyter_backend('ipyvtk_simple')`` or with
``backend='ipyvtk_simple'``.
``pyvista.set_jupyter_backend('ipyvtklink')`` or with
``backend='ipyvtklink'``.
jupyter_backend : str, optional
Jupyter notebook plotting backend to use. One of the
Expand Down
8 changes: 4 additions & 4 deletions pyvista/plotting/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3786,8 +3786,8 @@ def show(self, title=None, window_size=None, interactive=True,
use_ipyvtk : bool, optional
Deprecated. Instead, set the backend either globally with
``pyvista.set_jupyter_backend('ipyvtk_simple')`` or with
``backend='ipyvtk_simple'``.
``pyvista.set_jupyter_backend('ipyvtklink')`` or with
``backend='ipyvtklink'``.
jupyter_backend : str, optional
Jupyter notebook plotting backend to use. One of the
Expand Down Expand Up @@ -3857,8 +3857,8 @@ def show(self, title=None, window_size=None, interactive=True,
if use_ipyvtk:
txt = textwrap.dedent("""\
use_ipyvtk is deprecated. Set the backend
globally with ``pyvista.set_jupyter_backend("ipyvtk_simple"
or with ``backend="ipyvtk_simple"``)
globally with ``pyvista.set_jupyter_backend("ipyvtklink"
or with ``backend="ipyvtklink"``)
""")
from pyvista.core.errors import DeprecationError
raise DeprecationError(txt)
Expand Down
2 changes: 1 addition & 1 deletion pyvista/plotting/theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
'times': _vtk.VTK_TIMES}

rcParams = {
'jupyter_backend': 'static',
'jupyter_backend': 'ipyvtklink',
'auto_close': True, # DANGER: set to False with extreme caution
'background': [0.3, 0.3, 0.3],
'full_screen': False,
Expand Down
2 changes: 1 addition & 1 deletion pyvista/utilities/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def __init__(self, additional=None, ncol=3, text_width=80, sort=False,

# Optional packages.
optional = ['matplotlib', 'pyvistaqt', 'PyQt5', 'IPython', 'colorcet',
'cmocean', 'ipyvtk_simple', 'scipy', 'itkwidgets', 'tqdm']
'cmocean', 'ipyvtklink', 'scipy', 'itkwidgets', 'tqdm']

# Information about the GPU - bare except in case there is a rendering
# bug that the user is trying to report.
Expand Down
2 changes: 1 addition & 1 deletion requirements_docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jupyter_sphinx==0.3.2
jupyterlab>=3.0.12
ipygany
panel
ipyvtk-simple
ipyvtklink
2 changes: 1 addition & 1 deletion requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ tqdm
hypothesis>=6.0.3
sphinx_gallery
trimesh
ipyvtk-simple>=0.1.2
ipyvtklink>=0.2.1
panel
ipygany
18 changes: 9 additions & 9 deletions tests/jupyter/test_ipyvtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@
import pyvista as pv


has_ipyvtk_simple = True
has_ipyvtklink = True
try:
from ipyvtk_simple.viewer import ViewInteractiveWidget
from ipyvtklink.viewer import ViewInteractiveWidget
except:
has_ipyvtk_simple = False
has_ipyvtklink = False


skip_no_ipyvtk = pytest.mark.skipif(not has_ipyvtk_simple,
skip_no_ipyvtk = pytest.mark.skipif(not has_ipyvtklink,
reason="Requires IPython package")

@skip_no_ipyvtk
def test_set_jupyter_backend_ipyvtk_simple():
pv.set_jupyter_backend('ipyvtk_simple')
assert pv.rcParams['jupyter_backend'] == 'ipyvtk_simple'
def test_set_jupyter_backend_ipyvtklink():
pv.set_jupyter_backend('ipyvtklink')
assert pv.rcParams['jupyter_backend'] == 'ipyvtklink'
pv.set_jupyter_backend(None)


@skip_no_ipyvtk
def test_ipyvtk(sphere):
pl = pv.Plotter(notebook=True)
pl.add_mesh(sphere)
viewer = pl.show(jupyter_backend='ipyvtk_simple',
viewer = pl.show(jupyter_backend='ipyvtklink',
return_viewer=True)
assert isinstance(viewer, ViewInteractiveWidget)

Expand All @@ -35,5 +35,5 @@ def test_ipyvtk(sphere):
def test_ipyvtk_warn(sphere):
os.environ['SPYDER'] = 'exists'
with pytest.warns(UserWarning, match='incompatible with Spyder'):
sphere.plot(notebook=True, jupyter_backend='ipyvtk_simple')
sphere.plot(notebook=True, jupyter_backend='ipyvtklink')
del os.environ['SPYDER']

0 comments on commit 6201fc1

Please sign in to comment.