python - Ad hoc 3D Plot

Subscribe Send me a message home page tags


#python  #3d  #computer graphics 

In this post, we will present a python script to do ad hoc 3D plot.

The idea is to plot the surface of 3D objects using the Axes3D.scatter method. The surface is simply a list of points and it can be represented by a 2D numpy array of size n * 3 where n is the number of points.

We will use the following helper method in our script:

1
2
3
4
5
def plotPoints(ax, points, color = 'red',  marker='o', markerSize=1):
    x = points[:, 0]
    y = points[:, 1]
    z = points[:, 2]
    ax.scatter(x, y, z, c = color, marker = marker, s = markerSize)

The main structure of the script would look like something like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

plotPoints(ax, my3dObject.getSurfacePoints(), color=np.array([[1, 0, 0, 0.2]]))

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

Now let's define two common 3D objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Sphere:
    def __init__(self, c, r, theta_sample_num=30, phi_sample_num=30):
        self.c = c
        self.r = r
        self.theta_sample_num = theta_sample_num
        self.phi_sample_num = phi_sample_num

    def getSurfacePoints(self):
        points = []
        for theta in np.linspace(0, 2 * np.pi, num = self.theta_sample_num):
            for phi in np.linspace(0, 2 * np.pi, num = self.phi_sample_num):
                d = np.cos(phi) * self.r
                x = d * np.cos(theta)
                y = d * np.sin(theta)
                z = self.r * np.sin(phi)

                points.append([x, y, z])

        return np.asarray(points) + self.c


class Cuboid:
    def __init__(self, center, width, length, height, nx, ny, nz):
        self.center = center
        self.width = width
        self.length = length
        self.height = height
        self.nx = nx
        self.ny = ny
        self.nz = nz


    def getSurfacePoints(self):
        x = np.linspace(0, self.width, num = self.nx)
        y = np.linspace(0, self.length, num = self.ny)
        z = np.linspace(0, self.height, num = self.nz)

        xy = np.meshgrid(x, y)
        bottom = np.hstack( (xy[0].reshape(-1, 1), xy[1].reshape(-1, 1), np.zeros_like(xy[0]).reshape(-1, 1)))

        top = np.hstack( ( xy[0].reshape(-1, 1),
                           xy[1].reshape(-1, 1),
                           np.full_like(xy[0], self.height).reshape(-1, 1)
                        ) )

        yz = np.meshgrid(y, z)
        left = np.hstack( (np.zeros_like(yz[0]).reshape(-1, 1), yz[0].reshape(-1, 1), yz[1].reshape(-1, 1)) )
        right = np.hstack( (np.full_like(yz[0], self.width).reshape(-1, 1), yz[0].reshape(-1, 1), yz[1].reshape(-1, 1)) )

        xz = np.meshgrid(x, z)
        front = np.hstack( (xz[0].reshape(-1, 1), np.zeros_like(xz[0]).reshape(-1, 1), xz[1].reshape(-1, 1)) )
        rear = np.hstack( (xz[0].reshape(-1, 1), np.full_like(xz[0], self.length).reshape(-1, 1), xz[1].reshape(-1, 1)) )

        center = np.array([self.width / 2., self.length / 2., self.height / 2.])

        return np.vstack((bottom, top, left, right, front, rear)) + self.center - center

Put everything together, we have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

sphere = Sphere(c = np.array([7, 7, 7]), r = 6, theta_sample_num=120, phi_sample_num=120)
cuboid = Cuboid(center=np.array([-10, -10, -10]), width = 10, length = 20, height=15, nx = 80, ny = 80, nz= 80)

plotPoints(ax, sphere.getSurfacePoints(), color=np.array([[1, 0, 0, 0.2]]))
plotPoints(ax, cuboid.getSurfacePoints(), color=np.array([[0, 0, 1, 0.2]]))

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()
demo.png

----- END -----

If you have questions about this post, you could find me on Discord.
Send me a message Subscribe to blog updates

Want some fun stuff?

/static/shopping_demo.png