title: “Consonant Frequency Animation with Manim” format: revealjs editor: visual —
Introduction
This presentation walks through the process of building an animation that:
- Analyzes consonant frequency in a text passage
- Shows the progressive counting of consonants
- Animates a bubble sort of the final histogram
Why is this relevant?
Animating code, especially for data processing and algorithm visualization, provides significant practical benefits:
- Education: Helps learners visually understand abstract concepts and algorithm steps.
- Debugging & Communication: Makes it easier to spot logical errors or inefficiencies in code, and to explain processes to others.
- Engagement: Turns data analysis into an interactive and compelling experience.
Text Passage to Analyze
We’ll use the following text as the input for our analysis:
“Omni Analytics Group specializes in advanced data science and artificial intelligence solutions. Our team leverages statistical modeling, machine learning, and data visualization to drive actionable insights for clients across a variety of industries.”
This text will be processed to count the frequency of each consonant character.
Project Setup
from manim import *
from collections import defaultdict
manim
: Provides all animation capabilitiesdefaultdict
: Helps track consonant counts efficiently
This code belongs at the top of your Python file.
Scene Class Definition
class ConsonantHistogram(Scene):
def construct(self):
...
Scene
: Base class for all Manim animationsconstruct()
: Mandatory method where the animation is built
This is the framework for our entire animation.
Text Input and Consonant Definition
= ("Omni Analytics Group specializes in advanced data science and artificial intelligence solutions. "
phrase "Our team leverages statistical modeling, machine learning, and data visualization to drive actionable "
"insights for clients across a variety of industries.")
= 'bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ' consonants
phrase
: The text to analyze (can be any string)consonants
: All consonant characters we’ll count (both cases)
This defines our data source and what characters to track.
Progressive Counting Mechanism
= defaultdict(int)
consonant_counts = []
consonant_progression
for i, char in enumerate(phrase):
if char in consonants:
+= 1
consonant_counts[char]
if i % 10 == 0 or i == len(phrase) - 1:
dict(consonant_counts)) consonant_progression.append(
defaultdict
: Automatically initializes counts to 0enumerate
: Tracks character position in texti % 10
: Takes snapshots every 10 characters
Stores progressive counts in consonant_progression
.
Histogram Creation Function
def create_histogram(counts):
= []
bars = max(counts.values()) if counts else 1
max_count = -6
x_offset = 0.8
bar_width = [BLUE, GREEN, YELLOW, PURPLE, ORANGE, TEAL] colors
max_count
: Normalizes bar heightsx_offset
: Starting x-position for first barcolors
: Color cycle for distinct bars
This function will be called for each progression step.
Bar Construction
for idx, (letter, count) in enumerate(sorted(counts.items())):
= count / max_count * 4
bar_height = colors[idx % len(colors)]
color = Rectangle(
bar =bar_width,
width=bar_height,
height=color,
fill_color=0.7,
fill_opacity=1
stroke_width-2 + bar_height / 2, 0])
).move_to([x_offset, # ^ Replace .set_x and .set_y with .move_to for 3D coordinates
Rectangle
: Manim shape for histogram barsmove_to
: Correctly positions bars (replace deprecated.set_x
and.set_y
)fill_opacity
: Makes bars semi-transparent
Adding Labels
= Text(letter, font_size=20).next_to(bar, DOWN)
letter_text = Text(str(count), font_size=20).next_to(bar, UP)
count_text = VGroup(bar, letter_text, count_text)
bar_group
bars.append((bar_group, bar, letter, count))+= 0.5 x_offset
Text
: Adds consonant character below bar, and count above barVGroup
: Combines elements for easy animationx_offset
: Spaces bars evenly
Animation Sequence
= Text("Consonant Frequency Progression", font_size=30, color=BLUE).to_edge(UP)
title self.play(Write(title))
= None
progress_text for i, counts in enumerate(consonant_progression):
if i > 0:
self.play(FadeOut(current_histogram))
= create_histogram(counts)
bars = VGroup(*[bar_group[0] for bar_group in bars])
current_histogram self.play(Create(current_histogram))
Write(title)
: Animates title appearanceFadeOut
: Clears previous histogramCreate
: Animates new histogram
Loops through each progression snapshot.
Progress Tracking
= Text(f"Progress: {i+1}/{len(consonant_progression)}",
progress_text =20).to_edge(DOWN)
font_sizeif i > 0:
self.play(ReplacementTransform(prev_progress, progress_text))
else:
self.play(Write(progress_text))
= progress_text
prev_progress self.wait(0.2)
- Shows current/total progression steps
ReplacementTransform
: Smoothly updates counterwait(0.2)
: Pause between steps
Transition to Sorting
self.play(FadeOut(progress_text))
self.play(FadeOut(title))
= Text("Sorting Consonants", font_size=30, color=BLUE).to_edge(UP)
title_sorting self.play(Write(title_sorting))
- Clears previous UI elements
- Introduces new phase with a different title
- Provides clear visual transition
Bubble Sort Implementation
for i in range(len(bars)):
for j in range(len(bars) - 1 - i):
= bars[j], bars[j + 1]
bar1, bar2
if bar1[3] > bar2[3]:
self.play(
1].animate.set_fill(RED, opacity=0.9),
bar1[1].animate.set_fill(RED, opacity=0.9),
bar2[=0.2
run_time )
- Classic bubble sort algorithm
set_fill(RED)
: Highlights compared barsrun_time
: Controls animation speed
Bar Swapping Animation
self.play(
0].animate.shift(0.5 * RIGHT),
bar1[0].animate.shift(-0.5 * LEFT),
bar2[=0.2
run_time
)+ 1] = bars[j + 1], bars[j]
bars[j], bars[j self.play(
1].animate.set_fill(bar1[1].fill_color, opacity=0.7),
bar1[1].animate.set_fill(bar2[1].fill_color, opacity=0.7),
bar2[=0.2
run_time )
shift()
: Moves bars horizontallyanimate
: Manim’s interpolation system- Resets colors after swap
- Updates list order
Final Result
The complete animation shows:
- Progressive counting of consonants
- Animated histogram building
- Visual sorting of final frequencies