0. Visual Goal
In the previous lesson, we learned how to create basic 3D plots. In this lesson, we start drawing recognizable 3D objects.
Line
A path joining points in 3D space.
Diagonal
A line that moves through multiple axes together.
Plane
A flat sheet in 3D space.
Cube
A box made from 8 corners and 12 edges.
Cone
A circular base rising to one top point.
Sphere and Emoji
A ball, then a face made by combining shapes.
1. Common Setup for 3D Drawing
Most programs in this lesson begin with the same setup.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
plt.show()
2. Draw a 3D Line
A line is a collection of points connected together.
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0, 10, 100)
x = t
y = t
z = t
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.plot(x, y, z, linewidth=3)
ax.set_title("3D Line")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
plt.show()
Try this
x = t
y = t**2
z = t**3
This creates a curved path instead of a straight line.
2A. Draw a Diagonal Line
A diagonal line moves in more than one direction at the same time. In 3D, a diagonal can move along X, Y, and Z together.
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0, 5, 100)
x = t
y = t
z = t
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.plot(x, y, z, linewidth=4)
ax.scatter([0, 5], [0, 5], [0, 5], s=80)
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(5, 5, 5, "End", fontsize=12)
ax.set_title("3D Diagonal Line")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_xlim(0, 5)
ax.set_ylim(0, 5)
ax.set_zlim(0, 5)
ax.set_box_aspect([1, 1, 1])
plt.show()
Diagonal on a Plane
We can also draw a diagonal across a flat square plane.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
# Plane
x = np.linspace(0, 5, 20)
y = np.linspace(0, 5, 20)
X, Y = np.meshgrid(x, y)
Z = np.zeros_like(X)
ax.plot_surface(X, Y, Z, alpha=0.35)
# Diagonal on the plane
d = np.linspace(0, 5, 100)
ax.plot(d, d, np.zeros_like(d), linewidth=5)
ax.scatter([0, 5], [0, 5], [0, 0], s=80)
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(5, 5, 0, "End", fontsize=12)
ax.set_title("Diagonal on a Plane")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_xlim(0, 5)
ax.set_ylim(0, 5)
ax.set_zlim(0, 5)
ax.set_box_aspect([1, 1, 1])
plt.show()
3. Draw a Plane
A plane is a flat surface. We create many x and y points, then calculate z.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 20)
y = np.linspace(-5, 5, 20)
X, Y = np.meshgrid(x, y)
Z = 2 * X + Y
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.plot_surface(X, Y, Z, alpha=0.75)
ax.set_title("Plane: z = 2x + y")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
plt.show()
4. Draw a Cube
A cube has 8 corners and 12 edges. We can draw it using line segments.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
points = [
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[1, 0, 1],
[1, 1, 1],
[0, 1, 1]
]
edges = [
[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]
]
for edge in edges:
p1 = points[edge[0]]
p2 = points[edge[1]]
x = [p1[0], p2[0]]
y = [p1[1], p2[1]]
z = [p1[2], p2[2]]
ax.plot(x, y, z, linewidth=3)
ax.scatter(
[p[0] for p in points],
[p[1] for p in points],
[p[2] for p in points],
s=60
)
ax.set_title("3D Cube Using Edges")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_box_aspect([1, 1, 1])
plt.show()
Cube with Body Diagonal
A cube diagonal joins one corner of the cube to the opposite corner.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
points = [
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[1, 0, 1],
[1, 1, 1],
[0, 1, 1]
]
edges = [
[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]
]
for edge in edges:
p1 = points[edge[0]]
p2 = points[edge[1]]
ax.plot(
[p1[0], p2[0]],
[p1[1], p2[1]],
[p1[2], p2[2]],
linewidth=3
)
# Body diagonal
ax.plot([0, 1], [0, 1], [0, 1], linewidth=5, color="black")
ax.scatter([0, 1], [0, 1], [0, 1], s=100, color="black")
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(1, 1, 1, "Opposite Corner", fontsize=12)
ax.set_title("Cube with Body Diagonal")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_box_aspect([1, 1, 1])
plt.show()
5. Draw a Cone
A cone has a circular base and one top point.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 80)
r = np.linspace(0, 1, 40)
Theta, R = np.meshgrid(theta, r)
X = R * np.cos(Theta)
Y = R * np.sin(Theta)
Z = 1 - R
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.plot_surface(X, Y, Z, alpha=0.85)
ax.set_title("3D Cone")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_box_aspect([1, 1, 1])
plt.show()
How it works
| Part | Meaning |
|---|---|
theta |
Angle around the circle |
r |
Radius from center |
X = R * cos(Theta) |
Horizontal circular position |
Y = R * sin(Theta) |
Depth circular position |
Z = 1 - R |
Height decreases as radius increases |
6. Draw a Sphere
A sphere is created using two angles.
import numpy as np
import matplotlib.pyplot as plt
u = np.linspace(0, 2 * np.pi, 80)
v = np.linspace(0, np.pi, 80)
X = np.outer(np.cos(u), np.sin(v))
Y = np.outer(np.sin(u), np.sin(v))
Z = np.outer(np.ones_like(u), np.cos(v))
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.plot_surface(X, Y, Z, alpha=0.85)
ax.set_title("3D Sphere")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_box_aspect([1, 1, 1])
plt.show()
7. Example: 3D Emoji Face
Now let us combine shapes. We will make a simple emoji-style face.
- Sphere for the head
- Two black points for eyes
- A curved smile line
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
# Face sphere
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
X = np.outer(np.cos(u), np.sin(v))
Y = np.outer(np.sin(u), np.sin(v))
Z = np.outer(np.ones_like(u), np.cos(v))
ax.plot_surface(X, Y, Z, alpha=0.75)
# Eyes
ax.scatter([-0.35, 0.35], [-0.82, -0.82], [0.35, 0.35], s=180, color="black")
# Smile
smile_x = np.linspace(-0.45, 0.45, 80)
smile_y = np.full_like(smile_x, -0.88)
smile_z = -0.15 - 0.35 * smile_x**2
ax.plot(smile_x, smile_y, smile_z, color="black", linewidth=5)
# View from front
ax.view_init(elev=10, azim=-90)
ax.set_title("Simple 3D Emoji Face")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_box_aspect([1, 1, 1])
plt.show()
8. Master Demo: All Shapes in One Program
This program shows a menu. Students can choose what they want to draw.
import numpy as np
import matplotlib.pyplot as plt
def setup_ax(title):
fig = plt.figure(figsize=(8, 7))
ax = fig.add_subplot(projection="3d")
ax.set_title(title)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
return fig, ax
def draw_line():
t = np.linspace(0, 10, 100)
x = t
y = t
z = t
fig, ax = setup_ax("3D Line")
ax.plot(x, y, z, linewidth=3)
plt.show()
def draw_diagonal():
t = np.linspace(0, 5, 100)
x = t
y = t
z = t
fig, ax = setup_ax("3D Diagonal Line")
ax.plot(x, y, z, linewidth=4)
ax.scatter([0, 5], [0, 5], [0, 5], s=80)
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(5, 5, 5, "End", fontsize=12)
ax.set_xlim(0, 5)
ax.set_ylim(0, 5)
ax.set_zlim(0, 5)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_diagonal_on_plane():
fig, ax = setup_ax("Diagonal on a Plane")
x = np.linspace(0, 5, 20)
y = np.linspace(0, 5, 20)
X, Y = np.meshgrid(x, y)
Z = np.zeros_like(X)
ax.plot_surface(X, Y, Z, alpha=0.35)
d = np.linspace(0, 5, 100)
ax.plot(d, d, np.zeros_like(d), linewidth=5)
ax.scatter([0, 5], [0, 5], [0, 0], s=80)
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(5, 5, 0, "End", fontsize=12)
ax.set_xlim(0, 5)
ax.set_ylim(0, 5)
ax.set_zlim(0, 5)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_plane():
x = np.linspace(-5, 5, 20)
y = np.linspace(-5, 5, 20)
X, Y = np.meshgrid(x, y)
Z = 2 * X + Y
fig, ax = setup_ax("Plane: z = 2x + y")
ax.plot_surface(X, Y, Z, alpha=0.75)
plt.show()
def draw_cube():
fig, ax = setup_ax("3D Cube")
points = [
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[1, 0, 1],
[1, 1, 1],
[0, 1, 1]
]
edges = [
[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]
]
for edge in edges:
p1 = points[edge[0]]
p2 = points[edge[1]]
x = [p1[0], p2[0]]
y = [p1[1], p2[1]]
z = [p1[2], p2[2]]
ax.plot(x, y, z, linewidth=3)
ax.scatter(
[p[0] for p in points],
[p[1] for p in points],
[p[2] for p in points],
s=60
)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_cube_with_diagonal():
fig, ax = setup_ax("Cube with Body Diagonal")
points = [
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[1, 0, 1],
[1, 1, 1],
[0, 1, 1]
]
edges = [
[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]
]
for edge in edges:
p1 = points[edge[0]]
p2 = points[edge[1]]
ax.plot(
[p1[0], p2[0]],
[p1[1], p2[1]],
[p1[2], p2[2]],
linewidth=3
)
ax.plot([0, 1], [0, 1], [0, 1], linewidth=5, color="black")
ax.scatter([0, 1], [0, 1], [0, 1], s=100, color="black")
ax.text(0, 0, 0, "Start", fontsize=12)
ax.text(1, 1, 1, "Opposite Corner", fontsize=12)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_cone():
theta = np.linspace(0, 2 * np.pi, 80)
r = np.linspace(0, 1, 40)
Theta, R = np.meshgrid(theta, r)
X = R * np.cos(Theta)
Y = R * np.sin(Theta)
Z = 1 - R
fig, ax = setup_ax("3D Cone")
ax.plot_surface(X, Y, Z, alpha=0.85)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_sphere():
u = np.linspace(0, 2 * np.pi, 80)
v = np.linspace(0, np.pi, 80)
X = np.outer(np.cos(u), np.sin(v))
Y = np.outer(np.sin(u), np.sin(v))
Z = np.outer(np.ones_like(u), np.cos(v))
fig, ax = setup_ax("3D Sphere")
ax.plot_surface(X, Y, Z, alpha=0.85)
ax.set_box_aspect([1, 1, 1])
plt.show()
def draw_emoji():
fig, ax = setup_ax("Simple 3D Emoji Face")
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
X = np.outer(np.cos(u), np.sin(v))
Y = np.outer(np.sin(u), np.sin(v))
Z = np.outer(np.ones_like(u), np.cos(v))
ax.plot_surface(X, Y, Z, alpha=0.75)
ax.scatter(
[-0.35, 0.35],
[-0.82, -0.82],
[0.35, 0.35],
s=180,
color="black"
)
smile_x = np.linspace(-0.45, 0.45, 80)
smile_y = np.full_like(smile_x, -0.88)
smile_z = -0.15 - 0.35 * smile_x**2
ax.plot(smile_x, smile_y, smile_z, color="black", linewidth=5)
ax.view_init(elev=10, azim=-90)
ax.set_box_aspect([1, 1, 1])
plt.show()
print("3D Drawing in Matplotlib")
print("1. Line")
print("2. Diagonal Line")
print("3. Diagonal on a Plane")
print("4. Plane")
print("5. Cube")
print("6. Cube with Body Diagonal")
print("7. Cone")
print("8. Sphere")
print("9. Emoji Face")
choice = input("Enter your choice: ")
if choice == "1":
draw_line()
elif choice == "2":
draw_diagonal()
elif choice == "3":
draw_diagonal_on_plane()
elif choice == "4":
draw_plane()
elif choice == "5":
draw_cube()
elif choice == "6":
draw_cube_with_diagonal()
elif choice == "7":
draw_cone()
elif choice == "8":
draw_sphere()
elif choice == "9":
draw_emoji()
else:
print("Invalid choice")
9. Shape Formula Cheat Sheet
| Shape | Main Idea | Matplotlib Tool |
|---|---|---|
| Line | Connect many points | ax.plot(x, y, z) |
| Diagonal Line | Move through X, Y, and Z together | ax.plot(t, t, t) |
| Diagonal on Plane | Move through X and Y while Z stays fixed | ax.plot(d, d, zeros) |
| Plane | Use z = ax + by + c |
ax.plot_surface(X, Y, Z) |
| Cube | Draw corners and edges | ax.plot() repeatedly |
| Cube Diagonal | Join one corner to the opposite corner | ax.plot([0, 1], [0, 1], [0, 1]) |
| Cone | Use radius and angle | ax.plot_surface() |
| Sphere | Use two angles | ax.plot_surface() |
| Emoji | Combine sphere, points, and curves | plot_surface, scatter, plot |
10. Embedded Python Editor
Copy any code from this lesson and run it inside the editor.
11. Student Practice Checklist
12. Homework
Easy
Draw a line from point (0, 0, 0) to (5, 5, 5).
Medium
Draw a diagonal across a square plane with side length 10.
Hard
Draw a cube with side length 2 and then draw a diagonal from one corner to the opposite corner.
Infinity
Create a 3D emoji with eyebrows, nose, mouth, ears, and a diagonal party hat.