In Lesson 14, you learned to create 2D mathematical art using parametric equations. Now we're taking it to the next level with 3D graphics, interactive visualizations, and advanced mathematical concepts!
Make sure you've completed Lesson 14: Mathematical Art first. We'll build on those concepts to create even more amazing visualizations!
Today we'll explore 3D parametric surfaces, complex number visualizations, fractal geometry, and real-time interactive graphics - the same techniques used in video games and scientific visualization!
Here's what you'll be creating - beautiful 3D mathematical surfaces that evolve in real-time:
3D parametric surfaces created with mathematical equations - watch how they transform and rotate in real-time!
Before we code, let's explore what we're building! Visit this interactive 3D parametric art demo:
Try these controls:
• Drag to rotate the 3D view
• Shift + Drag to pan
• Mouse wheel to zoom
• Try different patterns (Pattern 6 is great for rotation!)
• Enable "Persistent Trails" for beautiful art
The web demo shows exactly what we'll recreate in Python! You'll learn:
Let's create stunning 3D mathematical surfaces using matplotlib. This builds on the 2D concepts from Lesson 14:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from matplotlib.widgets import Slider, Button
import math
class Advanced3DMathArt:
def __init__(self):
self.fig = plt.figure(figsize=(12, 8))
self.ax = self.fig.add_subplot(111, projection='3d')
self.t = 0
self.surface_type = 0
# Set up the plot
self.fig.suptitle('Advanced 3D Mathematical Art', fontsize=16, fontweight='bold')
self.ax.set_facecolor('black')
def parametric_surface_1(self, u, v, t):
"""Klein Bottle - Advanced mathematical surface"""
# Klein bottle parametric equations
x = (2 + np.cos(v/2) * np.sin(u) - np.sin(v/2) * np.sin(2*u + t)) * np.cos(v)
y = (2 + np.cos(v/2) * np.sin(u) - np.sin(v/2) * np.sin(2*u + t)) * np.sin(v)
z = np.sin(v/2) * np.sin(u) + np.cos(v/2) * np.sin(2*u + t)
return x, y, z
def parametric_surface_2(self, u, v, t):
"""Twisted Torus with time animation"""
R = 3 # Major radius
r = 1 # Minor radius
twist = t * 0.5
x = (R + r * np.cos(v + twist)) * np.cos(u)
y = (R + r * np.cos(v + twist)) * np.sin(u)
z = r * np.sin(v + twist) + 0.5 * np.sin(3*u + t)
return x, y, z
def parametric_surface_3(self, u, v, t):
"""Seashell Surface - Fibonacci spiral in 3D"""
# Golden ratio for natural spirals
phi = (1 + np.sqrt(5)) / 2
# Seashell parametric equations
x = u * np.cos(v) * np.cos(u/phi + t)
y = u * np.cos(v) * np.sin(u/phi + t)
z = u * np.sin(v) + 0.3 * np.sin(5*u + t)
return x, y, z
def mandelbrot_surface(self, u, v, t):
"""3D Mandelbrot-inspired surface"""
# Convert to complex plane
c = u + 1j * v
z = 0 + 0j
# Mandelbrot iteration (simplified for 3D)
for i in range(10):
z = z*z + c + 0.1*t
# Convert back to 3D coordinates
x = np.real(z)
y = np.imag(z)
z_height = np.abs(z) * np.sin(t + np.abs(z))
return x, y, z_height
def create_3d_surface(self, surface_func, t_val):
"""Generate 3D surface data"""
# Create parameter grids
u = np.linspace(-np.pi, np.pi, 50)
v = np.linspace(-np.pi, np.pi, 50)
U, V = np.meshgrid(u, v)
# Calculate surface coordinates
X, Y, Z = surface_func(U, V, t_val)
return X, Y, Z
def update_surface(self, frame):
"""Animation function for real-time updates"""
self.ax.clear()
# Choose surface based on current type
surfaces = [
self.parametric_surface_1,
self.parametric_surface_2,
self.parametric_surface_3,
self.mandelbrot_surface
]
current_surface = surfaces[self.surface_type % len(surfaces)]
# Generate surface data
X, Y, Z = self.create_3d_surface(current_surface, self.t)
# Create beautiful color mapping
colors = plt.cm.plasma(np.sqrt(X**2 + Y**2 + Z**2))
# Plot the 3D surface
surf = self.ax.plot_surface(X, Y, Z, facecolors=colors,
alpha=0.8, antialiased=True)
# Set labels and title
surface_names = ["Klein Bottle", "Twisted Torus", "Seashell", "Mandelbrot Surface"]
self.ax.set_title(surface_names[self.surface_type % len(surfaces)] + "\nTime: " + str(round(self.t, 2)),
color='white', fontsize=12)
# Set axis properties
self.ax.set_xlabel('X', color='white')
self.ax.set_ylabel('Y', color='white')
self.ax.set_zlabel('Z', color='white')
# Make background black
self.ax.xaxis.pane.fill = False
self.ax.yaxis.pane.fill = False
self.ax.zaxis.pane.fill = False
# Update time
self.t += 0.1
return surf,
def change_surface(self):
"""Change to next surface type"""
self.surface_type += 1
print("Switched to surface type: " + str(self.surface_type % 4))
def start_animation(self):
"""Start the 3D animation"""
print("🚀 Starting 3D Mathematical Art Animation")
print("Close the window to stop")
# Create animation
ani = animation.FuncAnimation(self.fig, self.update_surface,
frames=200, interval=100, blit=False)
plt.show()
return ani
def main():
"""Main function to run 3D mathematical art"""
art_generator = Advanced3DMathArt()
# Add interactive controls
print("🎨 3D Mathematical Art Generator")
print("Controls:")
print("- Close window to exit")
print("- Watch the beautiful 3D surfaces evolve!")
# Start the animation
animation_obj = art_generator.start_animation()
if __name__ == "__main__":
main() Now let's create stunning 3D mathematical surfaces using parametric equations:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import tkinter as tk
from tkinter import ttk
import math
class Interactive3DArt:
def __init__(self):
self.setup_gui()
# Initialize 3D parameters
self.u_range = (-2, 2)
self.v_range = (-2, 2)
self.resolution = 50
self.animation_speed = 0.05
self.current_surface = "torus"
def setup_gui(self):
"""Create the interactive GUI"""
self.root = tk.Tk()
self.root.title("Interactive Fractal Art Generator")
self.root.geometry("400x600")
# Create control panel
control_frame = ttk.Frame(self.root, padding="10")
control_frame.pack(fill=tk.BOTH, expand=True)
# Title
title_label = ttk.Label(control_frame, text="🎨 3D Parametric Art Generator",
font=("Arial", 16, "bold"))
title_label.pack(pady=10)
# Surface type selection
ttk.Label(control_frame, text="3D Surface Type:").pack(anchor=tk.W)
self.surface_type = tk.StringVar(value="torus")
surface_combo = ttk.Combobox(control_frame, textvariable=self.surface_type,
values=["torus", "sphere", "klein_bottle", "mobius_strip", "seashell"])
surface_combo.pack(fill=tk.X, pady=5)
# Resolution control
ttk.Label(control_frame, text="Surface Resolution:").pack(anchor=tk.W, pady=(10,0))
self.resolution_var = tk.IntVar(value=50)
resolution_scale = ttk.Scale(control_frame, from_=20, to=100,
variable=self.resolution_var, orient=tk.HORIZONTAL)
resolution_scale.pack(fill=tk.X, pady=5)
# Animation Speed control
ttk.Label(control_frame, text="Animation Speed:").pack(anchor=tk.W, pady=(10,0))
self.speed_var = tk.DoubleVar(value=0.05)
speed_scale = ttk.Scale(control_frame, from_=0.01, to=0.2,
variable=self.speed_var, orient=tk.HORIZONTAL)
speed_scale.pack(fill=tk.X, pady=5)
# Scale Factor control
ttk.Label(control_frame, text="Scale Factor:").pack(anchor=tk.W, pady=(10,0))
self.scale_var = tk.DoubleVar(value=1.0)
scale_scale = ttk.Scale(control_frame, from_=0.5, to=3.0,
variable=self.scale_var, orient=tk.HORIZONTAL)
scale_scale.pack(fill=tk.X, pady=5)
# Rotation Speed control
ttk.Label(control_frame, text="Rotation Speed:").pack(anchor=tk.W, pady=(10,0))
self.rotation_var = tk.DoubleVar(value=1.0)
rotation_scale = ttk.Scale(control_frame, from_=0.1, to=5.0,
variable=self.rotation_var, orient=tk.HORIZONTAL)
rotation_scale.pack(fill=tk.X, pady=5)
# Color scheme
ttk.Label(control_frame, text="Color Scheme:").pack(anchor=tk.W, pady=(10,0))
self.colormap_var = tk.StringVar(value="hot")
color_combo = ttk.Combobox(control_frame, textvariable=self.colormap_var,
values=["hot", "plasma", "viridis", "cool", "rainbow"])
color_combo.pack(fill=tk.X, pady=5)
# Generate button
generate_btn = ttk.Button(control_frame, text="🎨 Generate 3D Surface",
command=self.generate_surface)
generate_btn.pack(pady=20, fill=tk.X)
# Save button
save_btn = ttk.Button(control_frame, text="💾 Save Image",
command=self.save_surface)
save_btn.pack(pady=5, fill=tk.X)
# Info display
self.info_text = tk.Text(control_frame, height=8, width=40)
self.info_text.pack(pady=10, fill=tk.BOTH, expand=True)
self.info_text.insert(tk.END, "🌟 Welcome to 3D Parametric Art Generator!\n\n")
self.info_text.insert(tk.END, "Adjust the controls and click 'Generate 3D Surface' to create beautiful mathematical art.\n\n")
self.info_text.insert(tk.END, "Try different surface types and parameters to explore 3D mathematical beauty!\n")
def generate_torus(self):
"""Generate a 3D torus surface"""
resolution = self.resolution_var.get()
scale = self.scale_var.get()
# Torus parameters
R = 3.0 * scale # Major radius
r = 1.0 * scale # Minor radius
# Parameter ranges
u = np.linspace(0, 2*np.pi, resolution)
v = np.linspace(0, 2*np.pi, resolution)
U, V = np.meshgrid(u, v)
# Parametric equations for torus
X = (R + r * np.cos(V)) * np.cos(U)
Y = (R + r * np.cos(V)) * np.sin(U)
Z = r * np.sin(V)
return X, Y, Z
def generate_sphere(self):
"""Generate a 3D sphere surface"""
resolution = self.resolution_var.get()
scale = self.scale_var.get()
# Sphere parameters
radius = 2.0 * scale
# Parameter ranges
u = np.linspace(0, 2*np.pi, resolution)
v = np.linspace(0, np.pi, resolution)
U, V = np.meshgrid(u, v)
# Parametric equations for sphere
X = radius * np.sin(V) * np.cos(U)
Y = radius * np.sin(V) * np.sin(U)
Z = radius * np.cos(V)
return X, Y, Z
def generate_klein_bottle(self):
"""Generate a Klein bottle surface"""
resolution = self.resolution_var.get()
scale = self.scale_var.get()
# Parameter ranges
u = np.linspace(0, 2*np.pi, resolution)
v = np.linspace(0, 2*np.pi, resolution)
U, V = np.meshgrid(u, v)
# Klein bottle parametric equations
X = scale * (3 + np.cos(U/2)*np.sin(V) - np.sin(U/2)*np.sin(2*V)) * np.cos(U)
Y = scale * (3 + np.cos(U/2)*np.sin(V) - np.sin(U/2)*np.sin(2*V)) * np.sin(U)
Z = scale * (np.sin(U/2)*np.sin(V) + np.cos(U/2)*np.sin(2*V))
return X, Y, Z
def generate_seashell(self):
"""Generate a seashell surface"""
resolution = self.resolution_var.get()
scale = self.scale_var.get()
# Parameter ranges
u = np.linspace(0, 6*np.pi, resolution)
v = np.linspace(0, 2*np.pi, resolution)
U, V = np.meshgrid(u, v)
# Seashell parametric equations
X = scale * (1 + 0.2*np.cos(V)) * np.cos(U) * (1 + 0.1*U)
Y = scale * (1 + 0.2*np.cos(V)) * np.sin(U) * (1 + 0.1*U)
Z = scale * (0.2*np.sin(V) + 0.1*U)
return X, Y, Z
def generate_surface(self):
"""Generate and display 3D surfaces"""
surface_type = self.surface_type.get()
self.info_text.insert(tk.END, "Generating " + surface_type + " surface...\n")
self.root.update()
# Generate surface data
if surface_type == "torus":
X, Y, Z = self.generate_torus()
elif surface_type == "sphere":
X, Y, Z = self.generate_sphere()
elif surface_type == "klein_bottle":
X, Y, Z = self.generate_klein_bottle()
elif surface_type == "seashell":
X, Y, Z = self.generate_seashell()
else:
X, Y, Z = self.generate_torus() # Default
# Create 3D plot
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
# Plot surface with colors
surf = ax.plot_surface(X, Y, Z, cmap=self.colormap_var.get(),
alpha=0.8, linewidth=0, antialiased=True)
# Customize the plot
ax.set_title(surface_type.title() + " - 3D Parametric Surface", fontsize=16)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# Add color bar
fig.colorbar(surf, shrink=0.5, aspect=5)
# Store for saving
self.current_surface = (X, Y, Z)
plt.show()
self.info_text.insert(tk.END, "3D surface generated successfully!\n")
self.info_text.see(tk.END)
def save_surface(self):
"""Save the current 3D surface as an image"""
if hasattr(self, 'current_surface'):
X, Y, Z = self.current_surface
filename = "3d_surface_" + self.surface_type.get().lower() + ".png"
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap=self.colormap_var.get(),
alpha=0.8, linewidth=0, antialiased=True)
ax.set_title(self.surface_type.get().title() + " - 3D Parametric Surface")
plt.savefig(filename, dpi=300, bbox_inches='tight')
plt.close()
self.info_text.insert(tk.END, "Saved as " + filename + "\n")
self.info_text.see(tk.END)
else:
self.info_text.insert(tk.END, "Generate a 3D surface first!\n")
def run(self):
"""Start the interactive 3D art generator"""
print("🎨 Starting Interactive 3D Parametric Art Generator")
print("Use the GUI controls to explore 3D mathematical surfaces!")
self.root.mainloop()
def main():
"""Main function"""
generator = Interactive3DArt()
generator.run()
if __name__ == "__main__":
main() The interactive web demo uses the same mathematical principles we'll implement in Python. Here's how they connect:
// Torus equations in JavaScript
x = (R + r * cos(v)) * cos(u)
y = (R + r * cos(v)) * sin(u)
z = r * sin(v) # Same torus equations in Python
X = (R + r * np.cos(V)) * np.cos(U)
Y = (R + r * np.cos(V)) * np.sin(U)
Z = r * np.sin(V) Key Insight: The math is identical! Only the syntax changes between languages. This teaches you that mathematical concepts are universal - once you understand the math, you can implement it anywhere.
Our art uses parametric equations - mathematical formulas where x and y coordinates are calculated using a parameter (in our case, time 't').
math.sin() and math.cos() - Create wave patterns and circular motionsmath.sqrt() - Calculate distances from centermath.atan2() - Find angles for polar coordinatesThe patterns we create follow mathematical principles found in nature:
Try changing these values in the mathematical formula:
k = x / 8 - 25 to k = x / 12 - 30d = 5 * math.cos(...) to use different multipliersmath.sin(d * 6 - t) instead of math.sin(d * 4 - t)Question: How do these changes affect the pattern?
Design your own mathematical pattern function:
def my_pattern(self, x, y, t):
"""Your custom mathematical pattern"""
# Try creating patterns with:
# - Different numbers of petals: math.sin(angle * 6)
# - Spiral effects: r + t * 0.1
# - Wave combinations: math.sin(x*0.1) + math.cos(y*0.1)
center_x, center_y = 200, 200
dx = x - center_x
dy = y - center_y
# Your mathematical creativity here!
pattern_x = x + 20 * math.sin(dx * 0.1 + t)
pattern_y = y + 20 * math.cos(dy * 0.1 + t)
return pattern_x, pattern_y Create colors based on mathematical formulas:
def mathematical_color(self, x, y, t):
"""Generate colors using mathematics"""
# Distance from center affects hue
distance = math.sqrt((x-200)**2 + (y-200)**2)
hue = (distance + t * 50) % 360
# Angle affects saturation
angle = math.atan2(y-200, x-200)
saturation = (math.sin(angle * 3) + 1) / 2
# Create RGB from HSV
rgb = colorsys.hsv_to_rgb(hue/360, saturation, 1.0)
return rgb Movie studios use similar mathematical formulas to create:
Architects use parametric equations for:
Scientists use mathematical art to visualize:
Create an interactive art gallery that:
You can create a list of different mathematical functions and cycle through them. Try combining multiple patterns or creating transitions between them!