0

I am trying to build a powerful analysis/visualization workflow with Paraview and and External Python environment. To summarize, paraview.simple package allows connection to a "paraview server", simultaneously a local paraview application gui connects to the same server.

Now, we can run things like this, directly from an external python environment, it doesn't even need to be on the same machine .

from paraview.simple import *
Connect("localhost")
c = Cone()
Show(c)

External ipython on left, paraview client on right both connected to pvserver running on a docker image

and everything works as expected. However, due to certain limitations of how client sessions are managed by pvserver, sending pure vtk objects to a pvserver is apparently a non-trivial task. For example an object produced in this way.

# Script
import SimpleITK as sitk
from glob import glob
import itk
import vtk
from vtk.util import numpy_support as vtknp
import numpy as np
from paraview.simple import *

def ReadCSAX3D(PATH, time):
    reader = sitk.ImageSeriesReader()
    sitk_image = sitk.ReadImage(reader.GetGDCMSeriesFileNames(PATH + '/time_' + str(time)))
    return sitk_image

# Based on notebook examples provided # https://github.com/NVIDIA/ipyparaview/blob/master/notebooks/Iso-Surfaces_with_RTX.ipynb
def SitkToVTK(sitk_image):
    voldims = np.asarray(sitk_image.GetSize())
    npvol = sitk.GetArrayFromImage(sitk_image).reshape(np.prod(voldims))
    vtkimg = vtk.vtkImageData()
    vtkimg.SetDimensions(voldims)
    vtkimg.SetExtent([0,voldims[0]-1, 0,voldims[1]-1, 0,voldims[2]-1])
    vtkimg.SetSpacing(np.asarray(sitk_image.GetSpacing()))
    vtkimg.SetOrigin(np.asarray(sitk_image.GetOrigin()))

    # Get a VTK wrapper around the numpy volume
    dataName = 'MRI_STACK'
    vtkarr = vtknp.numpy_to_vtk(npvol)
    vtkarr.SetName(dataName)
    vtkimg.GetPointData().AddArray(vtkarr)
    vtkimg.GetPointData().SetScalars(vtkarr)
    return vtkimg

sitk_image = ReadCSAX3D("/path/to/image_file", time_step)
vtk_image = SitkToVTK(sitk_image)
Connect("localhost")
tp = TrivialProducer()
tp.GetClientSideObject().SetOutput(vtk_image)
# GetClientSideObject() returns None in this configuration --
Show(tp)

more on this here As explained in one of the answers, the two sessions need to share the same memory space on the server

I figured an interesting workaround based on the Paraview Guide on using programmable sources and filters, which allows sources that have their input being python scripts. This approach worked perfectly provided that paraview python has all the dependencies. So, now we can inject python code directly from an external python environment like this for example.

ps = ProgrammableSource()
ps.Script = "print('Hello')"
Show(ps)

But now what would be the generic way to programmatically inject code from my codebase ?. In terms of : Best approach and maintainbility of the codebase later on (I am currently thinking of using inspect module to get source lines of defined functions as strings and sending them to the programmable source on the fly. However, how would I evaluate parts of the scripts being sent to allow for function parameters, I am worried that this would be very difficult to maintain in the long run.

More generally, what would be a good example of similar problems ? i.e Injecting small python scripts, that might need to change at runtime. Let's assume in anycase that any code that I can run in the external python environment, should also run in the paraview server I can make sure that the python environments/packages are identical.

M.K
  • 179
  • 1
  • 2
  • 10
  • 1
    For your info, having pvpython and paraview GUI connected at the same server may be deprecated in the future : see this discussion https://discourse.paraview.org/t/deprecating-multi-client-support/1439 – Nico Vuaille Jul 01 '20 at 08:37
  • Thanks for that, very important to know. I have linked this question on that thread and asked about that as well. – M.K Jul 01 '20 at 15:28

0 Answers0