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.
For use with PyVista, simply install with pip
or conda
:
pip install ipyvtklink
or
conda install -c conda-forge ipyvtklink
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
You may have to build jupyter lab extensions for this to work in Lab. This is known to work well in Notebook.
PyVista has fully implemented downstream support for ipyvtklink
. See PyVista's Documentation
See the pyvista.ipynb
for an original proof of concept.
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
cylinder = vtk.vtkCylinderSource() cylinder.SetResolution(8) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(cylinder.GetOutputPort()) actor = vtk.vtkActor() actor.SetMapper(mapper)
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)
ren.AddActor(actor) ren.ResetCamera()
ViewInteractiveWidget(ren_win) ```
See instructions above for running ParaView in a Docker container.
```py import paraview.simple as pvs from ipyvtklink.viewer import ViewInteractiveWidget
wavelet = pvs.Wavelet() contour = pvs.Contour(Input=wavelet) contour.ContourBy = ['POINTS', 'RTData'] contour.Isosurfaces = [63, 143, 170, 197, 276]
pvs.Show(contour)
view = pvs.GetActiveView() pvs.Render(view)
ren_win = view.GetClientSideObject().GetRenderWindow()
ViewInteractiveWidget(ren_win) ```
This package currently requires ipywidgets <8. However, versions 8.0.0 - 8.0.2 are available.
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 develops software for web visualization, data storage, build system generation, infovis, media analysis, biomedical inquiry, cloud computing and more.
GitHub Repositoryvtk ipywidgets 3d plotting jupyter paraview pyvista python