Project 30: Sorting Race Visualizer 🏁¶
Difficulty: 🟡 Intermediate
Run cells top to bottom. Each step builds on the previous one and saves real files under outputs/sorting_race_visualizer/.
Description¶
Animate bubble sort vs insertion sort as frame sequences and save a side-by-side race GIF.
Libraries & Modules¶
numpy,matplotlibPIL.Imagefor GIF assembly
Python Concepts You'll Practice¶
Algorithms, snapshots, animation export
🎛️ Parameter Variations¶
N— array lengthDURATION_MS— GIF speed
In [1]:
# Install dependencies for this project (safe to re-run)
import sys
!{sys.executable} -m pip install pillow numpy matplotlib wordcloud qrcode[pil] python-barcode fpdf2 jinja2 folium plotly pandas scipy ipywidgets -q
Skipping pip install (already installed)
In [2]:
# Interactive Jupyter setup — run this cell first
%matplotlib inline
from pathlib import Path
from IPython.display import display, Image as IPImage, HTML, Markdown, Audio, IFrame
OUTPUT_DIR = Path("outputs") / "sorting_race_visualizer"
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
print(f"✅ Outputs folder: {OUTPUT_DIR.resolve()}")
✅ Outputs folder: C:\Users\Hansel Yan\Projects\CodeItAll\outputs\sorting_race_visualizer
Step 1 — Capture sort frames¶
In [3]:
import numpy as np
import matplotlib.pyplot as plt
from io import BytesIO
from PIL import Image
# 🎛️ TWEAK THESE
N = 24
SEED = 1
DURATION_MS = 80
rng = np.random.default_rng(SEED)
base = rng.permutation(np.arange(1, N + 1))
def frames_bubble(arr):
a = arr.copy()
snaps = [a.copy()]
for i in range(len(a)):
for j in range(0, len(a) - i - 1):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
snaps.append(a.copy())
return snaps
def frames_insertion(arr):
a = arr.copy()
snaps = [a.copy()]
for i in range(1, len(a)):
key = a[i]
j = i - 1
while j >= 0 and a[j] > key:
a[j + 1] = a[j]
j -= 1
snaps.append(a.copy())
a[j + 1] = key
snaps.append(a.copy())
return snaps
bubble = frames_bubble(base)
insert = frames_insertion(base)
print(f"Bubble frames: {len(bubble)} | Insertion frames: {len(insert)}")
Bubble frames: 156 | Insertion frames: 179
Step 2 — Render race GIF¶
In [4]:
def render(arr, title):
fig, ax = plt.subplots(figsize=(4.5, 3))
ax.bar(range(len(arr)), arr, color="#222222")
ax.set_title(title)
ax.set_ylim(0, N + 1)
ax.set_xticks([])
buf = BytesIO()
fig.savefig(buf, format="png", dpi=100)
plt.close(fig)
buf.seek(0)
return Image.open(buf).convert("RGB")
max_len = max(len(bubble), len(insert))
gif_frames = []
for i in range(max_len):
b = bubble[min(i, len(bubble) - 1)]
s = insert[min(i, len(insert) - 1)]
left = render(b, "Bubble sort")
right = render(s, "Insertion sort")
canvas = Image.new("RGB", (left.width + right.width, max(left.height, right.height)), (255, 255, 255))
canvas.paste(left, (0, 0))
canvas.paste(right, (left.width, 0))
gif_frames.append(canvas)
out = OUTPUT_DIR / "sorting_race.gif"
gif_frames[0].save(out, save_all=True, append_images=gif_frames[1:], duration=DURATION_MS, loop=0)
print(f"Saved race GIF → {out} ({len(gif_frames)} frames)")
Saved race GIF → outputs\sorting_race_visualizer\sorting_race.gif (179 frames)
✅ Project complete¶
Check your output folder: outputs/sorting_race_visualizer/
Next: Project 31: Markov Meme Writer · Index