🔗 minimalist ipywidget to interface with any Python vtkRenderWindow

Kitware, updated 🕥 2022-09-30 14:47:15

ipyvtklink

Binder PyPI conda

An ipywidget for vtkRenderWindow (formerly ipyvtk-simple)

This is an early prototype of creating a Jupyter interface to VTK. This toolkit is a proof of concept and a more polished tool will be available as ipyvtk in the future.

The code here was implemented from the work done by Andras Lasso under an MIT License (see the source).

The goal is to enable this widget to work with any server side vtkRenderWindow This render window could be from VTK Python, ParaView, or PyVista.

Please note that vtk is not listed as a requirement for this package to simplify its installation in virtual environments where VTK may be built from source or bundled with ParaView and we do not want to install the wheels from PyPI.

Installation

For use with PyVista, simply install with pip or conda:

pip install ipyvtklink

or conda install -c conda-forge ipyvtklink

Run in Docker

A Docker image is prebuilt and hosted in the ipyvtklink repository's packages.

To run in Docker:

docker pull ghcr.io/kitware/ipyvtklink:latest docker run -p 8888:8888 ghcr.io/kitware/ipyvtklink:latest

and open the vtk.ipynb notebook.

Additionally, this can be used with ParaView. An example is given in paraview.ipynb which can be run via:

docker pull ghcr.io/kitware/ipyvtklink-paraview:latest docker run -p 8878:8878 ghcr.io/kitware/ipyvtklink-paraview:latest

Examples

You may have to build jupyter lab extensions for this to work in Lab. This is known to work well in Notebook.

PyVista

PyVista has fully implemented downstream support for ipyvtklink. See PyVista's Documentation

See the pyvista.ipynb for an original proof of concept.

demo-1

demo-2

Python VTK

The widget here can be used with VTK. Here is a minimal example showing how to pass any vtkRenderWindow to the ViewInteractiveWidget:

```py import vtk from ipyvtklink.viewer import ViewInteractiveWidget

Create some data

cylinder = vtk.vtkCylinderSource() cylinder.SetResolution(8) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(cylinder.GetOutputPort()) actor = vtk.vtkActor() actor.SetMapper(mapper)

Set up render window

ren = vtk.vtkRenderer() ren_win = vtk.vtkRenderWindow() ren_win.SetOffScreenRendering(1) ren_win.SetSize(600, 600) ren_win.AddRenderer(ren) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) style = vtk.vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style)

Add actor to scene

ren.AddActor(actor) ren.ResetCamera()

Display

ViewInteractiveWidget(ren_win) ```

demo-3

ParaView Python

See instructions above for running ParaView in a Docker container.

```py import paraview.simple as pvs from ipyvtklink.viewer import ViewInteractiveWidget

Create data on the pipeline

wavelet = pvs.Wavelet() contour = pvs.Contour(Input=wavelet) contour.ContourBy = ['POINTS', 'RTData'] contour.Isosurfaces = [63, 143, 170, 197, 276]

Set the data as visible

pvs.Show(contour)

Fetch the view and render the scene

view = pvs.GetActiveView() pvs.Render(view)

Fetch the RenderWindow

ren_win = view.GetClientSideObject().GetRenderWindow()

Display the RenderWindow with the widget

ViewInteractiveWidget(ren_win) ```

demo-4

Issues

Support ipywidgets >=8

opened on 2022-11-09 18:00:09 by DManowitz

This package currently requires ipywidgets <8. However, versions 8.0.0 - 8.0.2 are available.

How to get the correct event position when object_fit='contain'?

opened on 2022-02-08 15:24:43 by GuillaumeFavelier

In mne-python, we rely on ipywidgets and ipyvtklink to design apps for MEG and EEG processing and visualization.

AFAIK, ipyvtklink uses ipyevents to get the mouse event locations. Then it does a little bit of offset computation to adjust the given coordinates from the canvas size (which depends on the notebook) to the render window size (which is fixed by the Renderer at init), correct?

Well, in our last application, we embed the ViewInteractiveWidget in a HBox for a new design:

https://user-images.githubusercontent.com/18143289/152566076-9115d8d3-ba8f-44b5-b2c6-e1151c5b25c8.mp4

What happens when all the group boxes are folded, the values given by ipyevents for boundingRectHeight and boundingRectTop used for offset calculation are correct because the image and its bounding box have the same size.

But we use viewer.layout.object_fit='contain' to preserve the aspect ratio and when the group boxes are unfolded, the bounding box of the image is stretched with the accordion and now, I think the sizes sent by ipyevents do not match anymore.

This is a problem for us because we need the correct position of the event for picking:

https://user-images.githubusercontent.com/18143289/153018183-dc8a8950-4eb0-4489-8022-e65b6e0813d1.mp4

Is there a way to update the offset calculation so that GetEventPosition() returns the correct value when object_fit='contain'?

Kitware, Inc.

Kitware develops software for web visualization, data storage, build system generation, infovis, media analysis, biomedical inquiry, cloud computing and more.

GitHub Repository

vtk ipywidgets 3d plotting jupyter paraview pyvista python