Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with PolyData and add_point_labels #23

Open
DomenicoGaudioso opened this issue May 6, 2024 · 6 comments
Open

Problem with PolyData and add_point_labels #23

DomenicoGaudioso opened this issue May 6, 2024 · 6 comments

Comments

@DomenicoGaudioso
Copy link

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:

  1. 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.

  2. 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

@edsaac
Copy link
Owner

edsaac commented May 10, 2024

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: pyvista/pyvista#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,
    ),
)

@DomenicoGaudioso
Copy link
Author

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

@edsaac
Copy link
Owner

edsaac commented May 10, 2024

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()

@DomenicoGaudioso
Copy link
Author

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

@DomenicoGaudioso
Copy link
Author

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'

@edsaac
Copy link
Owner

edsaac commented May 17, 2024

I don't think that will be possible because a single lines actor is generated from a single pv.Plotter.add_lines call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants