The overall construct is an FastAPI Webserver to which a GemPy Model is send. This is then plotted as a 3D Model. From this I can extract the Layers as PyVista/VTK PolyData Objects. Until this point is works fine, however these Objects should idealy send back to the client as a useable file which isn´t just practicle in PYthon (e.g. .glb/.vtk/.ply). I know technically how to do that, however for the Server side i tried to save the file into a buffer, which seems impossible to implement with pyvista.PolyData.save() or vtk.vtkWriter.
My Code looks like this
# this just creates an object from which the layers can be extracted as polydata
gpv = gp.plot_3d(geo_model)
# here an examples how to get polydata or an unstructuredgrid
poly = gpv.surface_poly['Sandstone_2']
grid = pv.UnstructuredGrid(poly)
from this i´d like to ether save it with pyvista
poly.save("filename.ply")
or alternativley with vtk
def write_grid_to_vtk(grid, filename):
writer = vtk.vtkUnstructuredGridWriter()
writer.SetFileName(filename)
writer.SetInputData(grid)
#writer.SetFileTypeToBinary()
writer.Write()
buf = io.BytesIO()
write_grid_to_vtk(grid, buf)
buf.close()
in the vtk example you can see, how i tried to implement the buffer. This Throws an TypeError: SetFileName argument %Id: %V
Does anyone know how to implement this ?
It sounds like what you're looking for is serialization. PyVista meshes already support serialization via the pickle protocol, which would be as simple as pickle.dumps(poly)
and on the other side pickle.loads(b)
. But pickle
is known to be insecure against malicious pickle files, so you might want to avoid exposing your users to that mechanics.
Instead you can look at how PyVista implements the __getstate__()
and __setstate__()
methods used for pickling (in particular the newer, 'xml'
code path).
Here's a stripped-down example geared at PolyData
:
import pyvista as pv
from vtkmodules.vtkIOXML import vtkXMLPolyDataReader, vtkXMLPolyDataWriter
def poly_to_bytes(mesh):
"""Serialize a PolyData to bytes."""
writer = vtkXMLPolyDataWriter()
writer.SetInputDataObject(mesh)
writer.SetWriteToOutputString(True)
writer.SetDataModeToBinary()
writer.SetCompressorTypeToNone()
# or perhaps SetCompressorTypeToZLib() etc.
writer.Write()
return writer.GetOutputString()
def bytes_to_poly(bs):
"""Unserialize a bytes to pyvista.PolyData."""
reader = vtkXMLPolyDataReader()
reader.ReadFromInputStringOn()
reader.SetInputString(bs)
reader.Update()
return pv.wrap(reader.GetOutput())
# example polydata
poly = pv.Dodecahedron()
# serialize
bs = poly_to_bytes(poly)
# ... imagine sending this to the client
# unserialize
poly_after = bytes_to_poly(bs)
print(poly == poly_after) # True
You can also choose from a handful of compressors, the options can be found in the documentation of vtkXMLWriterBase
. I tried the None
and ZLib
cases in the above snippet, and compression takes down the bytestring from 3376 bytes to 2699 bytes. You'll want to consider the tradeoff between compression time/effort and reduced network traffic.