Programmers Picnic AI-ML Classes by Champak Roy

3D Drawing in Matplotlib

Draw a line, diagonal line, diagonal on a plane, plane, cube, cone, sphere, and a fun emoji-style face using Python, NumPy, and Matplotlib 3D.

Today we draw

  • A 3D line
  • A diagonal line
  • A diagonal across a plane
  • A flat plane
  • A cube using edges
  • A cone using a surface
  • A sphere using parametric equations
  • A simple 3D emoji face

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.

Line Diagonal Plane Cube Cone

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()
In Matplotlib 3D, we do not draw objects directly like a game engine. We build shapes from points, lines, surfaces, and mathematical equations.

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()
This diagonal starts at (0, 0, 0) and ends at (5, 5, 5). It moves equally in X, Y, and Z directions.

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()
Here the diagonal lies flat on the plane because all z values are 0.

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()
The equation z = 2x + y creates a slanted plane.

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()
The cube is not one single command here. It is built from points and edges.

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()
set_box_aspect([1, 1, 1]) helps the sphere look like a real sphere, not a stretched egg.

7. Example: 3D Emoji Face

Now let us combine shapes. We will make a simple emoji-style face.

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()
This is not a real emoji image. It is a 3D drawing made from a sphere, points, and a curve.

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.

Python Starter Editor | Matplotlib 3D Drawing Practice
If the editor does not load inside the page because of browser security settings, use the Open New Tab button.

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.