user8270077
user8270077

Reputation: 5071

How to visualize polyhedrons defined by their vertices in 3D with matplotlib or/and plotly offline?

I would like to visualize 3 polyhedrons defined by 3 numpy arrays of shape (8, 3).

I am looking for something like that:

enter image description here

My data are the following:

A = np.array([[0.92523719, 0.26843252, 0.77794309],
       [0.73156748, 0.27794309, 0.57476281],
       [0.62113842, 0.37886158, 0.87886158],
       [0.72205691, 0.07476281, 0.76843252],
       [0.57476281, 0.23156748, 0.72205691],
       [0.77794309, 0.42523719, 0.73156748],
       [0.87886158, 0.12113842, 0.62113842],
       [0.76843252, 0.22205691, 0.92523719]])

B = np.array([[0.23156748, 0.72205691, 0.57476281],
       [0.26843252, 0.77794309, 0.92523719],
       [0.12113842, 0.62113842, 0.87886158],
       [0.22205691, 0.92523719, 0.76843252],
       [0.27794309, 0.57476281, 0.73156748],
       [0.37886158, 0.87886158, 0.62113842],
       [0.07476281, 0.76843252, 0.72205691],
       [0.42523719, 0.73156748, 0.77794309]])

C = np.array([[0.73156748, 0.77794309, 0.42523719],
       [0.62113842, 0.87886158, 0.12113842],
       [0.77794309, 0.92523719, 0.26843252],
       [0.57476281, 0.73156748, 0.27794309],
       [0.87886158, 0.62113842, 0.37886158],
       [0.72205691, 0.57476281, 0.23156748],
       [0.76843252, 0.72205691, 0.07476281],
       [0.92523719, 0.76843252, 0.22205691]])

Upvotes: 3

Views: 4561

Answers (1)

JohanC
JohanC

Reputation: 80439

You seem to have points in 3D, but no edge nor polygon information. Supposing the polyhedra are convex, scipy.spatial's ConvexHull can find all the polygons on the convex hull. The convex hull exists of triangles that can be added to a 3D plot as a Poly3DCollection.

from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
import numpy as np
from scipy.spatial import ConvexHull

A = np.array([[0.92523719, 0.26843252, 0.77794309], [0.73156748, 0.27794309, 0.57476281], [0.62113842, 0.37886158, 0.87886158], [0.72205691, 0.07476281, 0.76843252], [0.57476281, 0.23156748, 0.72205691], [0.77794309, 0.42523719, 0.73156748], [0.87886158, 0.12113842, 0.62113842], [0.76843252, 0.22205691, 0.92523719]])
B = np.array([[0.23156748, 0.72205691, 0.57476281], [0.26843252, 0.77794309, 0.92523719], [0.12113842, 0.62113842, 0.87886158], [0.22205691, 0.92523719, 0.76843252], [0.27794309, 0.57476281, 0.73156748], [0.37886158, 0.87886158, 0.62113842], [0.07476281, 0.76843252, 0.72205691], [0.42523719, 0.73156748, 0.77794309]])
C = np.array([[0.73156748, 0.77794309, 0.42523719], [0.62113842, 0.87886158, 0.12113842], [0.77794309, 0.92523719, 0.26843252], [0.57476281, 0.73156748, 0.27794309], [0.87886158, 0.62113842, 0.37886158], [0.72205691, 0.57476281, 0.23156748], [0.76843252, 0.72205691, 0.07476281], [0.92523719, 0.76843252, 0.22205691]])
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
for cube, color in zip([A, B, C], ['r', 'g', 'b']):
    hull = ConvexHull(cube)
    # draw the polygons of the convex hull
    for s in hull.simplices:
        tri = Poly3DCollection([cube[s]])
        tri.set_color(color)
        tri.set_alpha(0.5)
        ax.add_collection3d(tri)
    # draw the vertices
    ax.scatter(cube[:, 0], cube[:, 1], cube[:, 2], marker='o', color='purple')
plt.show()

3D plot

Supposing the longest side of each triangle is a face diagonal of the cube, we could search for the two shortest sides and draw them in black:

from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
import numpy as np
from scipy.spatial import ConvexHull, distance

A = np.array([[0.92523719, 0.26843252, 0.77794309], [0.73156748, 0.27794309, 0.57476281], [0.62113842, 0.37886158, 0.87886158], [0.72205691, 0.07476281, 0.76843252], [0.57476281, 0.23156748, 0.72205691], [0.77794309, 0.42523719, 0.73156748], [0.87886158, 0.12113842, 0.62113842], [0.76843252, 0.22205691, 0.92523719]])
B = np.array([[0.23156748, 0.72205691, 0.57476281], [0.26843252, 0.77794309, 0.92523719], [0.12113842, 0.62113842, 0.87886158], [0.22205691, 0.92523719, 0.76843252], [0.27794309, 0.57476281, 0.73156748], [0.37886158, 0.87886158, 0.62113842], [0.07476281, 0.76843252, 0.72205691], [0.42523719, 0.73156748, 0.77794309]])
C = np.array([[0.73156748, 0.77794309, 0.42523719], [0.62113842, 0.87886158, 0.12113842], [0.77794309, 0.92523719, 0.26843252], [0.57476281, 0.73156748, 0.27794309], [0.87886158, 0.62113842, 0.37886158], [0.72205691, 0.57476281, 0.23156748], [0.76843252, 0.72205691, 0.07476281], [0.92523719, 0.76843252, 0.22205691]])
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
for cube, color in zip([A, B, C], ['r', 'g', 'b']):
    hull = ConvexHull(cube)
    for s in hull.simplices:
        tri = Poly3DCollection([cube[s]])
        tri.set_color(color)
        tri.set_alpha(0.5)
        tri.set_edgecolor('none')
        ax.add_collection3d(tri)
        edges = []
        if distance.euclidean(cube[s[0]], cube[s[1]]) < distance.euclidean(cube[s[1]], cube[s[2]]):
            edges.append((s[0], s[1]))
            if distance.euclidean(cube[s[1]], cube[s[2]]) < distance.euclidean(cube[s[2]], cube[s[0]]):
                edges.append((s[1], s[2]))
            else:
                edges.append((s[2], s[0]))
        else:
            edges.append((s[1], s[2]))
            if distance.euclidean(cube[s[0]], cube[s[1]]) < distance.euclidean(cube[s[2]], cube[s[0]]):
                edges.append((s[0], s[1]))
            else:
                edges.append((s[2], s[0]))
        for v0, v1 in edges:
            ax.plot(xs=cube[[v0, v1], 0], ys=cube[[v0, v1], 1], zs=cube[[v0, v1], 2], color='black')
    ax.scatter(cube[:, 0], cube[:, 1], cube[:, 2], marker='o', color='purple')
plt.show()

cube edges

Upvotes: 10

Related Questions