1

I am trying to plot/visualize an off plot using python. Currently, I am trying to use the Plotly mesh plots for the same.
This is the mesh I am trying to plot: enter image description here

First, I am trying to read the OFF file and extract all the vertices from it, and then giving the x y and z coordinates of these vertices to plotly mesh3d function as shown in the reference. However, that results in a plot that is nowhere similar to the orginal mesh. This is what the result looks like: enter image description here

Here is my code for the same:

import plotly.graph_objects as go
import numpy as np

# loading the mesh and getting the vertices
def ExtractRawData(filepath):
    # read the file path
    with open(filepath) as file:
        if 'OFF' != file.readline().strip():
            raise('Not a valid OFF header')
        n_verts, n_faces, n_dontknow = tuple([int(s) for s in file.readline().strip().split(' ')])
        verts = [[float(s) for s in file.readline().strip().split(' ')] for i_vert in range(n_verts)]
        faces = [[int(s) for s in file.readline().strip().split(' ')][1:] for i_face in range(n_faces)]
        return np.array(verts), np.array(faces)

# extracting the vertices from the off file 
verts, faces = ExtractRawData('Turbine blade.off')
# getting the x, y and z coordinates from the vertices
x = verts[:,0]
y = verts[:,1]
z = verts[:,2]

# plotting the mesh
fig = go.Figure(data=[go.Mesh3d(x=x, y=y, z=z)])
fig.show()

Is there anything wrong with my code? How do I get the right plot?

1 Answer 1

1

I had a similar issue with my .off model and the solution was to state the x,y,z coordinates of the triangles used to build the mesh (=faces in .off) explicitly by including i,j,k parameters in the Mesh3d call:

Mesh3d(
  ...
  i=..., # list of all x coordinates of faces
  j=..., # list of all y coordinates of faces
  k=..., # list of all z coordinates of faces
  ...
)

Here's my full code:

# read_off reads all vertices and faces as numpy arrays
vertices, faces = read_off("ex03/model.off")
x, y, z = vertices[:,0], vertices[:,1], vertices[:,2]
i, j, k = faces[:,0], faces[:,1], faces[:,2]

# Just to make sure I've read everything correctly
print(f"x:\n{x}\ny:\n{y}\nz:\n{z}\nfaces:\n{faces}")

fig = go.Figure(data=[go.Mesh3d(
        # 8 vertices of a cube
        x=x,
        y=y,
        z=z,
        colorbar_title='z',
        colorscale=[[0, 'gold'],
                    [0.5, 'mediumturquoise'],
                    [1, 'magenta']],
        # Intensity of each vertex, which will be interpolated and color-coded
        intensity = np.linspace(0, 1, 8, endpoint=True),
        # i, j and k give the vertices of triangles
        i = i,
        j = j,
        k = k,
        name='y',
        showscale=True
    )])
fig.show()

My result after this fix

Also, here's my corresponding read_off(...) using pandas and numpy (mine might differ from yours?):

def read_off(filename):
    """TODO: explain"""
    with open(filename) as off:
        # (1) parse header
        first_line = off.readline()
        if "OFF" not in first_line:
            raise ValueError('The file does not start whith the word OFF')
        color = True if "C" in first_line else False

        count = 1
        for line in off:
            count += 1
            # (2) ignore comments
            if line.startswith("#"):
                continue
            # (3) extract metadata
            line = line.strip().split()
            if len(line) > 1:
                n_vertices = int(line[0])
                n_faces = int(line[1])
                break

        # (4) load data
        data = {}
        point_names = ["x", "y", "z"]
        if color:
            point_names.extend(["red", "green", "blue"])

        data["vertices"] = pd.read_csv(filename, sep=" ", header=None, engine="python",
                                     skiprows=count, skipfooter=n_faces,
                                     names=point_names, index_col=False)
        for n in ["x", "y", "z"]:
            data["vertices"][n] = data["vertices"][n].astype(np.float32)

        if color:
            for n in ["red", "green", "blue"]:
                data["vertices"][n] = data["vertices"][n].astype(np.uint8)

        data["faces"] = pd.read_csv(filename, sep=" ", header=None, engine="python",
                                   skiprows=(count + n_vertices), usecols=[1, 2, 3],
                                   names=["v1", "v2", "v3"])

        return pd.DataFrame.to_numpy(data["vertices"]), pd.DataFrame.to_numpy(data["faces"])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.