stpyvista
stpyvista copied to clipboard
Problem with PolyData and add_point_labels
Hi everyone,
I'm attempting to integrate some three-dimensional visualization examples using PyVista into a Streamlit application. I'm encountering difficulties with two specific examples:
-
Creating a truss (https://docs.pyvista.org/version/stable/examples/00-load/create-truss#sphx-glr-examples-00-load-create-truss-py) I'm trying to adapt this example to display a truss in a Streamlit application. I have problem with visualization with using
PolyData
. -
Calculating distance along a spline (https://docs.pyvista.org/version/stable/examples/02-plot/distance-along-spline#sphx-glr-examples-02-plot-distance-along-spline-py) I have problem with visualization when use the
add_point_labels
function to label points along a spline.
I would appreciate if someone could offer some advice on resolving these issues and making the examples work in Streamlit. Thank you in advance for your help!
Domenico
Hi @DomenicoGaudioso, iirc, rendering lines as tubes and points as spheres are limitations from vtk-js, the library used to bring PyVista plotters to the browser: https://github.com/pyvista/pyvista/issues/5444
For example 1, my alternative would be to draw individual lines and points in the plotter:
Code:
import numpy as np
import pyvista as pv
import streamlit as st
from stpyvista import stpyvista
from matplotlib.cm import get_cmap
## Define geometry
nodes = [
[0.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[4.0, 3.0, 0.0],
[4.0, 0.0, 0.0],
[0.0, 1.0, 2.0],
[4.0, 1.0, 2.0],
[4.0, 3.0, 2.0],
]
edges = [
[0, 4],
[1, 4],
[3, 4],
[5, 4],
[6, 4],
[3, 5],
[2, 5],
[5, 6],
[2, 6],
]
## Generate colors for edges
cmap = get_cmap("hsv")
colors = map(cmap, np.linspace(0, 1, len(edges)))
## Create Plotter
plotter = pv.Plotter(window_size=(300, 300))
plotter.background_color = "salmon"
## Add nodes as points
plotter.add_points(np.array(nodes), point_size=20, color="purple")
## Add edges as lines
for edge, color in zip(edges, colors):
i, j = edge
line = np.array([nodes[i], nodes[j]])
plotter.add_lines(line, color=color, width=10)
plotter.view_isometric()
## Send to streamlit
st.title("Truss")
stpyvista(
plotter,
panel_kwargs=dict(
orientation_widget=True,
),
)
Thanks for the reply, I am also using this alternative but I noticed that it is heavier (slowness in image processing). Thank you for the feedback
Perhaps it's because I was looping through each edge element and adding it to the pyvista Plotter. We could try a couple things to improve performance:
- Decorate with
st.cache_resource
a function in charge of generating the Plotter - Assembling a single array of edges/coordinates to pass to
Plotter.add_lines
- Pass a key to
stpyvista
to avoid re-rendering of the 3D view at each interaction with the web-app
Code:
import numpy as np
import pyvista as pv
import streamlit as st
from stpyvista import stpyvista
@st.cache_resource
def mesh_to_plotter(nodes: list[list[float]], edges: list[list[int]]):
## Create Plotter
plotter = pv.Plotter(window_size=(300, 300))
plotter.background_color = "salmon"
## Add nodes as points
plotter.add_points(np.array(nodes), point_size=20, color="purple")
## Assemble edges as single array
coord_edges = (
np.array([[nodes[i], nodes[j]] for (i, j) in edges])
.flatten()
.reshape((2 * len(edges), 3))
)
plotter.add_lines(coord_edges, color="k", width=10)
plotter.view_isometric()
return plotter
def main():
## Define geometry
nodes = [
[0.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[4.0, 3.0, 0.0],
[4.0, 0.0, 0.0],
[0.0, 1.0, 2.0],
[4.0, 1.0, 2.0],
[4.0, 3.0, 2.0],
]
edges = [
[0, 4],
[1, 4],
[3, 4],
[5, 4],
[6, 4],
[3, 5],
[2, 5],
[5, 6],
[2, 6],
]
## Create plotter
plotter = mesh_to_plotter(nodes, edges)
## Send to streamlit
st.title("Truss")
stpyvista(
plotter,
panel_kwargs=dict(
orientation_widget=True,
),
key="stpv_truss",
)
if __name__ == "__main__":
main()
Great idea. One question: How can I set the color of the line based on, say, the 'Z' values of the points? In this example, they use 'cmap'. https://docs.pyvista.org/version/stable/examples/00-load/create-truss#sphx-glr-examples-00-load-create-truss-py
Is it possible to add a list of colors in color? I tried but with no success.
Error: Must be a string, rgb(a) sequence, or hex color string. For example:
color='white'
color='w'
color=[1.0, 1.0, 1.0]
color=[255, 255, 255]
color='#FFFFFF'
I don't think that will be possible because a single lines actor is generated from a single pv.Plotter.add_lines
call.