Lesson 9 of 9

Mathematical Art & Visualization

Create beautiful mathematical art using trigonometry and animation!

Learning Objectives

  • Use trigonometry to create beautiful patterns
  • Build animated mathematical visualizations
  • Combine math and art through programming
  • Create your own mathematical art masterpiece

Animated Spiral Art

Let's create beautiful animated spirals using trigonometry and time-based animation:

import math
import tkinter as tk
from tkinter import Canvas
import time

def create_spiral_art():
    root = tk.Tk()
    root.title("Mathematical Spiral Art")
    root.geometry("800x600")
    root.configure(bg='black')
    
    canvas = Canvas(root, width=800, height=600, bg='black')
    canvas.pack()
    
    def draw_frame():
        canvas.delete("all")
        t = time.time()
        center_x, center_y = 400, 300
        
        # Draw multiple spirals
        for spiral in range(8):
            points = []
            for angle in range(0, 720, 2):
                rad = math.radians(angle)
                radius = angle / 10 + 20
                x = center_x + radius * math.cos(rad + t + spiral * math.pi/4)
                y = center_y + radius * math.sin(rad + t + spiral * math.pi/4)
                points.extend([x, y])
            
            # Create gradient color
            hue = (spiral * 45 + t * 50) % 360
            r = int(127 * (1 + math.sin(math.radians(hue))))
            g = int(127 * (1 + math.sin(math.radians(hue + 120))))
            b = int(127 * (1 + math.sin(math.radians(hue + 240))))
            color = f"#{r:02x}{g:02x}{b:02x}"
            
            if len(points) >= 4:
                canvas.create_line(points, fill=color, width=2, smooth=True)
        
        # Add decorative elements
        for i in range(12):
            angle = i * 30 + t * 20
            rad = math.radians(angle)
            x = center_x + 150 * math.cos(rad)
            y = center_y + 150 * math.sin(rad)
            size = 10 + 5 * math.sin(t * 3 + i)
            canvas.create_oval(x-size, y-size, x+size, y+size, 
                             fill="white", outline="yellow", width=2)
        
        canvas.create_text(400, 50, text="Mathematical Spiral Art", 
                          fill="white", font=("Arial", 20, "bold"))
        root.after(16, draw_frame)
    
    def on_escape(event):
        root.quit()
    
    root.bind('<Escape>', on_escape)
    root.focus_set()
    draw_frame()
    root.mainloop()

if __name__ == "__main__":
    create_spiral_art()

5. Particle Flow Visualization

Flow Fields & Particle Systems

Create mesmerizing particle flows using vector mathematics!

This advanced visualization combines vector mathematics, particle physics, and flow field theory to create beautiful flowing patterns. Each particle follows mathematical flow equations while leaving colorful trails.

Mathematical Concepts:

  • Vector Fields: Mathematical functions that assign vectors to points in space
  • Flow Equations: Differential equations describing particle movement
  • Harmonic Motion: Multiple sine/cosine waves creating complex patterns
  • Particle Physics: Velocity, acceleration, and force interactions

Interactive Particle Flow Code:

import math
import tkinter as tk
from tkinter import Canvas, Scale, Label, Frame
import time
import random

def create_particle_flow():
    """
    Interactive particle flow with mathematical flow fields
    """
    root = tk.Tk()
    root.title("Particle Flow Art")
    root.geometry("1000x700")
    root.configure(bg='black')
    
    # Create main layout
    main_frame = Frame(root, bg='black')
    main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
    
    canvas = Canvas(main_frame, width=700, height=600, bg='black')
    canvas.pack(side=tk.LEFT, padx=(0, 20))
    
    # Control panel
    control_frame = Frame(main_frame, bg='black', width=250)
    control_frame.pack(side=tk.RIGHT, fill=tk.Y)
    
    # Parameters with sliders
    flow_strength = tk.DoubleVar(value=0.3)
    particle_count = tk.IntVar(value=50)
    trail_length = tk.IntVar(value=20)
    
    # Create sliders
    Label(control_frame, text="Flow Controls", fg="cyan", bg="black", 
          font=("Arial", 14, "bold")).pack(pady=10)
    
    Scale(control_frame, from_=0.0, to=1.0, resolution=0.05, 
          orient=tk.HORIZONTAL, variable=flow_strength, label="Flow Strength",
          bg="gray20", fg="white").pack(fill=tk.X, pady=5)
    
    Scale(control_frame, from_=10, to=100, resolution=10, 
          orient=tk.HORIZONTAL, variable=particle_count, label="Particles",
          bg="gray20", fg="white").pack(fill=tk.X, pady=5)
    
    Scale(control_frame, from_=5, to=40, resolution=5, 
          orient=tk.HORIZONTAL, variable=trail_length, label="Trail Length",
          bg="gray20", fg="white").pack(fill=tk.X, pady=5)
    
    particles = []
    
    class Particle:
        def __init__(self, x, y):
            self.x = x
            self.y = y
            self.vx = random.uniform(-1, 1)
            self.vy = random.uniform(-1, 1)
            self.life = random.uniform(100, 200)
            self.max_life = self.life
            self.trail = []
            self.hue = random.uniform(0, 360)
        
        def update(self, center_x, center_y, t, strength):
            # Calculate flow field
            dx = self.x - center_x
            dy = self.y - center_y
            distance = math.sqrt(dx*dx + dy*dy)
            
            if distance > 0:
                # Create swirling flow
                angle = math.atan2(dy, dx)
                flow_angle = angle + math.pi/2 + math.sin(t * 0.001 + distance * 0.02) * 0.5
                
                # Apply flow force
                flow_force = max(0, 200 - distance) / 200 * strength
                self.vx += math.cos(flow_angle) * flow_force * 0.1
                self.vy += math.sin(flow_angle) * flow_force * 0.1
            
            # Limit speed
            speed = math.sqrt(self.vx*self.vx + self.vy*self.vy)
            if speed > 3:
                self.vx = (self.vx / speed) * 3
                self.vy = (self.vy / speed) * 3
            
            # Update position
            self.x += self.vx
            self.y += self.vy
            self.life -= 1
            
            # Add to trail
            self.trail.append((self.x, self.y))
            if len(self.trail) > trail_length.get():
                self.trail.pop(0)
            
            # Wrap around screen
            if self.x < 0: self.x = 700
            if self.x > 700: self.x = 0
            if self.y < 0: self.y = 600
            if self.y > 600: self.y = 0
        
        def draw(self, canvas):
            if self.life <= 0:
                return
            
            # Draw colorful trail
            for i in range(1, len(self.trail)):
                fade = (i / len(self.trail)) * (self.life / self.max_life)
                
                # Rainbow colors
                hue_rad = math.radians(self.hue + i * 10)
                r = int(128 + 127 * math.sin(hue_rad) * fade)
                g = int(128 + 127 * math.sin(hue_rad + 2.09) * fade)
                b = int(128 + 127 * math.sin(hue_rad + 4.19) * fade)
                
                r = max(0, min(255, r))
                g = max(0, min(255, g))
                b = max(0, min(255, b))
                
                color = f"#{r:02x}{g:02x}{b:02x}"
                
                x1, y1 = self.trail[i-1]
                x2, y2 = self.trail[i]
                canvas.create_line(x1, y1, x2, y2, fill=color, width=2)
            
            # Draw particle
            if self.trail:
                x, y = self.trail[-1]
                canvas.create_oval(x-2, y-2, x+2, y+2, fill="white", outline="cyan")
    
    def draw_frame():
        canvas.delete("all")
        current_time = time.time() * 1000
        
        # Moving center point
        center_x = 350 + 50 * math.sin(current_time * 0.0008)
        center_y = 300 + 30 * math.cos(current_time * 0.0012)
        
        # Manage particles
        max_particles = particle_count.get()
        if len(particles) < max_particles and random.random() < 0.2:
            angle = random.uniform(0, 2 * math.pi)
            distance = random.uniform(100, 200)
            x = center_x + distance * math.cos(angle)
            y = center_y + distance * math.sin(angle)
            particles.append(Particle(x, y))
        
        # Update and draw particles
        strength = flow_strength.get()
        for particle in particles[:]:
            particle.update(center_x, center_y, current_time, strength)
            if particle.life <= 0:
                particles.remove(particle)
            else:
                particle.draw(canvas)
        
        # Draw center point
        pulse = 5 + 3 * math.sin(current_time * 0.005)
        canvas.create_oval(center_x-pulse, center_y-pulse, 
                          center_x+pulse, center_y+pulse, 
                          fill="white", outline="yellow", width=2)
        
        # Info display
        canvas.create_text(350, 30, text="Particle Flow Visualization", 
                          fill="white", font=("Arial", 16, "bold"))
        canvas.create_text(350, 50, text=f"Particles: {len(particles)}", 
                          fill="cyan", font=("Arial", 12))
        
        root.after(50, draw_frame)
    
    # Clear button
    def clear_particles():
        particles.clear()
    
    tk.Button(control_frame, text="Clear Particles", command=clear_particles,
              bg="orange", fg="white", font=("Arial", 12)).pack(pady=20)
    
    # Instructions
    instructions = [
        "β€’ Adjust flow strength to change particle behavior",
        "β€’ Increase particle count for denser flows",
        "β€’ Longer trails create more flowing effects",
        "β€’ Watch how math creates organic motion!"
    ]
    
    Label(control_frame, text="Instructions:", fg="yellow", bg="black", 
          font=("Arial", 10, "bold")).pack(pady=(20, 5))
    
    for instruction in instructions:
        Label(control_frame, text=instruction, fg="white", bg="black", 
              font=("Arial", 8), wraplength=200).pack(anchor="w", padx=5)
    
    # Start animation
    draw_frame()
    root.mainloop()

if __name__ == "__main__":
    create_particle_flow()

6. Advanced Parametric Formula Art

Complex Parametric Equations

Create stunning organic patterns using advanced mathematical formulas!

This advanced visualization demonstrates how complex parametric equations can create beautiful, organic patterns. The formula combines multiple trigonometric functions, harmonic oscillations, and time-based animation to generate flowing mathematical art.

Advanced Mathematical Concepts:

  • Complex Parametric Equations: Multi-variable mathematical functions
  • Harmonic Analysis: Combining multiple oscillating frequencies
  • Amplitude Modulation: Varying the strength of oscillations over time
  • Phase Relationships: How different waves interact and combine

Interactive Parametric Formula Code:

import math
import tkinter as tk
from tkinter import Canvas, Scale, Label, Frame
import time

def create_interactive_parametric_art():
    """
    Interactive parametric formula art with parameter controls
    Formula: d = k(3+sin(t+Ο„))Γ—sin(mag/(e/99+t/99+cos(mag)+200))
    """
    root = tk.Tk()
    root.title("Interactive Parametric Formula Art")
    root.geometry("1200x700")
    root.configure(bg='black')
    
    # Create main frame
    main_frame = Frame(root, bg='black')
    main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
    
    # Canvas for drawing
    canvas = Canvas(main_frame, width=800, height=600, bg='black')
    canvas.pack(side=tk.LEFT, padx=(0, 20))
    
    # Control panel
    control_frame = Frame(main_frame, bg='black', width=350)
    control_frame.pack(side=tk.RIGHT, fill=tk.Y)
    
    # Parameters with interactive controls
    scale_factor = tk.DoubleVar(value=300.0)
    k_multiplier = tk.DoubleVar(value=15.0)
    amplitude_boost = tk.DoubleVar(value=5.0)
    time_speed = tk.DoubleVar(value=1.0)
    pattern_complexity = tk.DoubleVar(value=1.0)
    harmonic_layers = tk.IntVar(value=3)
    
    def create_slider(parent, label, variable, from_, to, resolution=0.1):
        frame = Frame(parent, bg='black')
        frame.pack(fill=tk.X, pady=3)
        
        Label(frame, text=label, fg="white", bg="black", 
              font=("Arial", 9, "bold")).pack()
        slider = Scale(frame, from_=from_, to=to, resolution=resolution, 
                      orient=tk.HORIZONTAL, variable=variable, 
                      bg="gray20", fg="white", highlightbackground="black")
        slider.pack(fill=tk.X)
        return slider
    
    # Create control sliders
    Label(control_frame, text="Parametric Formula Controls", 
          font=("Arial", 14, "bold"), fg="white", bg="black").pack(pady=10)
    
    create_slider(control_frame, "Scale Factor", scale_factor, 50, 500, 10)
    create_slider(control_frame, "K Multiplier", k_multiplier, 5, 30, 1)
    create_slider(control_frame, "Amplitude Boost", amplitude_boost, 1, 20, 0.5)
    create_slider(control_frame, "Time Speed", time_speed, 0.1, 3.0, 0.1)
    create_slider(control_frame, "Complexity", pattern_complexity, 0.5, 3.0, 0.1)
    create_slider(control_frame, "Harmonic Layers", harmonic_layers, 1, 5, 1)
    
    def draw_frame():
        canvas.delete("all")
        
        center_x, center_y = 400, 300
        current_time = time.time() * time_speed.get()
        
        # Get current parameters
        scale = scale_factor.get()
        k_mult = k_multiplier.get()
        complexity = pattern_complexity.get()
        amp_boost = amplitude_boost.get()
        layers = harmonic_layers.get()
        
        # Draw multiple harmonic layers
        for layer in range(layers):
            points = []
            layer_offset = layer * 0.3
            layer_scale = scale * (1 - layer * 0.1)
            
            # Generate points using the parametric formula
            for t in range(0, 3600, 2):
                t_rad = math.radians(t / 10)
                
                # Core parametric formula
                k = k_mult * math.cos(t_rad / 8 + current_time + layer_offset) * complexity
                e = t_rad / 8 - 12.5 + math.sin(current_time * 0.5) * 2
                
                # Magnitude calculation
                mag_component = (e * 3 / 1499 + 
                               math.cos(e / 4 + current_time * 2) / 5 + 
                               math.sin(t_rad * 0.1 + current_time) * 0.3 + 1) * amp_boost
                
                # Distance calculation with formula
                try:
                    denominator = e / 99 + t_rad / 99 + math.cos(mag_component) + 200
                    if abs(denominator) > 0.001:
                        d = k * (3 + math.sin(t_rad + current_time * 2)) * \
                            math.sin(mag_component / denominator) * amp_boost
                    else:
                        d = 0
                except:
                    d = 0
                
                # Calculate final position
                x = center_x + layer_scale * d * math.cos(t_rad)
                y = center_y + layer_scale * d * math.sin(t_rad)
                
                if abs(x - center_x) <= 350 and abs(y - center_y) <= 250:
                    points.append((x, y))
            
            # Draw this layer with rainbow colors
            if len(points) > 1:
                for i in range(1, len(points)):
                    progress = i / len(points)
                    
                    # Rainbow gradient
                    hue = (progress * 360 + current_time * 30 + layer * 72) % 360
                    r = int(127 * (1 + math.sin(math.radians(hue))))
                    g = int(127 * (1 + math.sin(math.radians(hue + 120))))
                    b = int(127 * (1 + math.sin(math.radians(hue + 240))))
                    
                    color = f"#{r:02x}{g:02x}{b:02x}"
                    width = max(1, int(2 * (1 + math.sin(progress * math.pi * 4) * 0.5)))
                    
                    x1, y1 = points[i-1]
                    x2, y2 = points[i]
                    canvas.create_line(x1, y1, x2, y2, fill=color, width=width, smooth=True)
        
        # Center point with pulse effect
        pulse = 8 + 5 * math.sin(current_time * 3)
        canvas.create_oval(center_x-pulse, center_y-pulse, center_x+pulse, center_y+pulse, 
                          fill="white", outline="gold", width=3)
        
        # Display information
        canvas.create_text(400, 25, text="Interactive Parametric Formula Art", 
                          fill="white", font=("Arial", 16, "bold"))
        canvas.create_text(400, 45, text=f"Scale: {scale:.0f} | Layers: {layers} | Complexity: {complexity:.1f}", 
                          fill="cyan", font=("Arial", 12))
        canvas.create_text(400, 575, text="d = k(3+sin(t+Ο„))Γ—sin(mag/(e/99+t/99+cos(mag)+200)) Γ— BOOST", 
                          fill="yellow", font=("Arial", 10))
        
        root.after(30, draw_frame)
    
    # Preset buttons
    def preset_large():
        scale_factor.set(400.0)
        k_multiplier.set(25.0)
        amplitude_boost.set(10.0)
        pattern_complexity.set(2.0)
        harmonic_layers.set(4)
    
    def preset_complex():
        scale_factor.set(350.0)
        k_multiplier.set(20.0)
        amplitude_boost.set(8.0)
        pattern_complexity.set(2.5)
        harmonic_layers.set(5)
        time_speed.set(0.5)
    
    button_frame = Frame(control_frame, bg='black')
    button_frame.pack(pady=20)
    
    tk.Button(button_frame, text="Large Pattern", command=preset_large,
              bg="orange", fg="white", font=("Arial", 10, "bold")).pack(pady=2)
    
    tk.Button(button_frame, text="Complex Pattern", command=preset_complex,
              bg="purple", fg="white", font=("Arial", 10, "bold")).pack(pady=2)
    
    # Instructions
    instructions = [
        "β€’ Scale Factor controls overall size",
        "β€’ K Multiplier affects pattern shape", 
        "β€’ Amplitude Boost makes dramatic changes",
        "β€’ Try preset buttons for instant effects",
        "β€’ Adjust layers for visual complexity"
    ]
    
    Label(control_frame, text="Instructions:", fg="yellow", bg="black", 
          font=("Arial", 10, "bold")).pack(pady=(20, 5))
    
    for instruction in instructions:
        Label(control_frame, text=instruction, fg="white", bg="black", 
              font=("Arial", 8), anchor="w").pack(anchor="w", padx=10)
    
    # Start animation
    draw_frame()
    root.mainloop()

if __name__ == "__main__":
    create_interactive_parametric_art()

Try the Interactive Web Version!

Interactive Mathematical Art Simulations

Experience mathematical beauty in your web browser!

We've created web-based versions of these mathematical art generators that run directly in your browser. All include interactive controls, real-time parameter adjustment, and beautiful visual effects.

πŸŒ€ Lissajous Curve Explorer

Interactive parametric equations with frequency ratios, amplitudes, and phase controls.

Launch Explorer

πŸ’« Particle Flow Simulator

Interactive particle systems with flow fields, trails, and dynamic physics controls.

Launch Simulator

∞ Parametric Formula Art

Complex mathematical formulas creating organic patterns with harmonic layers and controls.

Launch Formula Art

Your Mathematical Art Challenge

Create Your Own Mathematical Masterpiece!

Now it's time to create your own mathematical art! Here are some ideas to explore:

  • Golden Ratio Art: Use the golden ratio (1.618...) to create naturally beautiful proportions
  • Fibonacci Spirals: Create spirals based on the famous Fibonacci sequence
  • Mandala Generator: Use symmetry and repetition to create mandala patterns
  • Music Visualizer: Create patterns that change with mathematical "music" frequencies
← Previous: Advanced Physics Games

Congratulations! You've mastered Python programming!

From basic variables to mathematical art - you've come so far!

Back to Programming Hub