Hi,
I am running a python web-server which is calculating the new geometry of a model to then send back to the website visualiser using vtk.js to visualise the information. I would like to send the updated geometry using JSON via the following process “vtkJSONDataSetWriter”. On the python side I generate some geometry using Pyvista as this is convenient wrapper for generating the coloured mesh, however I am not sure how to translate this into a JSON object to send back to website. A pseudo example below:
# Pseudo code on the python web server
from pyvista import examples
import pyvista as pv
import vtk
# Request comes from the client website via AJAX request, then new geometry is calculated...
# ...in this simple example I just include a stock example
mesh = examples.download_st_helens().warp_by_scalar()
# Add scalar array with range (0, 100) that correlates with elevation
mesh['values'] = pv.plotting.normalize(mesh['Elevation']) * 100
# Not sure how to use the function below to write to a JSON object
vtkDcmWriter = vtk.vtkJSONDataSetWriter()
json_object = vtkDcmWriter.Write(actor)
# Return the JSON object to the javascript
return json_object
On the Client side the following pseudo code
# Receive JSON object from server side... not pass the json_object to the reader
const reader = vtkHttpDataSetReader.newInstance(json_object)
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(reader.getOutputPort());
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
renderer.addActor(actor);
// Then update the actor in my website with Javascript, however not completely sure how to achieve this.
Any help on this would be much appreciated - struggling to find any examples of the server side needed to send to the client. Thanks.
Thanks Sebastien… realised I may be attempting the impossible / hitting my head against a brick wall. Ultimately I’m try to generate a web app that takes a user input runs a calculation on the server side, and then plots the vtk render of the results in my website. I also want to use vtk.js because it has useful cell and point picker which I want to integrate as a feature in my plots. The plot I am trying to achieve is a mesh, however the color scalar values are calculated based on the input on the client web side.
Perhaps the best solution is to send the calculated geometry and color scalar data (i.e xyz coords, cell connectivity and color scalar values for the nodes) from the server side back as JSON to the JavaScript on the client side which loops through the raw data generating the plot?
I had a look at panel, however it didn’t allow me to readily customise callbacks such as point or cell picker functions which would be required for my web app. If you have any advice on this as a route would greatly appreciate it.
Great - many thanks for this… I had a go and managed to send the xml and render the image… I created a super simple polyline file with some scalar colors to send as the “polydata_xml” file. The java script side loads the geometry information correctly, however does not display the scalar color information as expected. The blue entire polyline is blue and not as the example I am trying to render, I am not sure if it is an error in the encoding of the xml or the mapping of the scalar values to colors?
# Example python server side info using pyvista to generate the vtk file and color scalars
def make_points():
"""Helper to make XYZ points"""
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z ** 2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
return np.column_stack((x, y, z))
points = make_points()
points[0:5, :]
def polyline_from_points(points):
poly = pv.PolyData()
poly.points = points
the_cell = np.arange(0, len(points), dtype=np.int_)
the_cell = np.insert(the_cell, 0, len(points))
poly.lines = the_cell
return poly
polyline = polyline_from_points(points)
print(np.arange(polyline.n_points))
polyline["scalars"] = np.arange(polyline.n_points)
print(polyline)
filename = "temp/vtk_test.vtp"
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName(filename)
writer.SetInputData(polyline)
writer.Write()
with open(filename) as f:
polydata_xml = f.read()
return polydata_xml
This is the javascript function invoked when the xml is returned:
// Callback function for when request completes
request.onload = () => {
var data = request.responseText;
var writerReader = vtk.IO.XML.vtkXMLPolyDataReader.newInstance()
const textEncoder = new TextEncoder();
writerReader.parseAsArrayBuffer(textEncoder.encode(data))
console.log(textEncoder.encode(data))
const mapper = vtk.Rendering.Core.vtkMapper.newInstance();
mapper.setInputConnection(writerReader.getOutputPort());
const actor = vtk.Rendering.Core.vtkActor.newInstance();
actor.setMapper(mapper);
// ----------------------------------------------------------------------------
// Add the actor to the renderer and set the camera based on it
// ----------------------------------------------------------------------------
const renderWindow = vtk.Rendering.Core.vtkRenderWindow.newInstance();
const renderer = vtk.Rendering.Core.vtkRenderer.newInstance({ background: [0.2, 0.3, 0.4] });
renderWindow.addRenderer(renderer);
renderer.addActor(actor);
renderer.resetCamera();
// ----------------------------------------------------------------------------
// Use OpenGL as the backend to view the all this
// ----------------------------------------------------------------------------
const openglRenderWindow = vtk.Rendering.OpenGL.vtkRenderWindow.newInstance();
renderWindow.addView(openglRenderWindow);
// ----------------------------------------------------------------------------
// Create a div section to put this into
// ----------------------------------------------------------------------------
const container = document.querySelector('#vtk_render')
openglRenderWindow.setContainer(container);
openglRenderWindow.setSize(500, 500);
// ----------------------------------------------------------------------------
// Setup an interactor to handle mouse events
// ----------------------------------------------------------------------------
const interactor = vtk.Rendering.Core.vtkRenderWindowInteractor.newInstance();
interactor.setView(openglRenderWindow);
interactor.initialize();
interactor.bindEvents(container);
// ----------------------------------------------------------------------------
// Setup interactor style to use
// ----------------------------------------------------------------------------
const trackball_camera = vtk.Interaction.Style.vtkInteractorStyleTrackballCamera.newInstance()
interactor.setInteractorStyle(trackball_camera);