title: “Dynamic Data Distribution” format: revealjs editor: visual —
Introduction
Dynamic data distribution refers to how data values change over time or across space, often in unpredictable or evolving patterns. It demonstrates real-world processes like population growth, temperature fluctuations, network traffic, or financial market trends. Visualizing dynamic data helps reveal patterns, outliers, and trends that static data can’t show. For example, in urban planning, it can show how electricity usage varies hourly across a city. In finance, it illustrates changing asset prices. Dynamic data distribution is crucial for decision-making, forecasting, and real-time monitoring in industries like logistics, healthcare, weather forecasting, and smart city infrastructure. It turns raw numbers into meaningful insights.
Importing Manim
from manim import *
We import everything from the Manim library. This allows us to access 3D scenes, geometries like Prism
, and camera tools.
Tip: Use a virtual environment and install Manim with:
pip install manim
Defining the Scene
class Cityscape3D(ThreeDScene):
def construct(self):
We define a custom animation class Cityscape3D
.
ThreeDScene
allows use of a 3D camera.
construct()
is Manim’s entry point: all animations go here.
Adding a Title
= Text("Dynamic Data Distribution", font_size=26, weight=BOLD, color=BLUE)
title * 0.4)
title.to_edge(UP self.add_fixed_in_frame_mobjects(title)
self.play(FadeIn(title, run_time=2))
- Adds a title and places it near the top.
add_fixed_in_frame_mobjects
keeps the title static while the camera moves.
Initial Camera Orientation
self.set_camera_orientation(
=75 * DEGREES,
phi=-45 * DEGREES,
theta=rate_functions.linear,
rate_func=6
run_time )
phi
tilts the camera (vertical axis).theta
rotates it around the z-axis.rate_func
controls transition speed (linear in this case).
Adjustment: Try run_time=4
if 6s feels too slow.
The Base Grid (NumberPlane)
= NumberPlane(
base_plane =[-7, 7, 1], y_range=[-7, 7, 1],
x_range={"stroke_opacity": 0},
axis_config={
background_line_style"stroke_color": GREY,
"stroke_width": 0.5,
"stroke_opacity": 0.7
}
)self.add(base_plane)
- Creates a light grey grid to simulate a floor.
- Axes are hidden (
stroke_opacity: 0
) for a cleaner look. - Helps with spatial orientation.
Setting Up Histograms
= VGroup()
histograms = [RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, TEAL, PINK]
colors = 50
num_histograms = 0.1 min_height
VGroup()
stores all histogram bars.- Cycles through a palette of 8 colors.
- Starting height is small (0.1) to animate growth later.
Adjustment: Increase num_histograms
to 75–100 for denser scenes.
Generating Bars
for i in range(num_histograms):
= min_height
height = colors[i % len(colors)]
color = Prism(dimensions=[0.5, 0.5, height], fill_color=color, fill_opacity=10)
bar
= np.random.uniform(-5, 5)
x_pos = np.random.uniform(-3, 3)
y_pos = height / 2
z_pos
bar.move_to([x_pos, y_pos, z_pos])
histograms.add(bar)
- Creates short bars (
Prism
) and randomly places them in the xy-plane. z_pos = height / 2
makes the base sit on the plane.- Manim’s prism coordinates use center points — hence the z-offset.
Fade-In Animation
for bar in histograms:
self.play(FadeIn(bar, run_time=0.3))
- Smoothly reveals each bar one by one.
- Makes the entrance visually appealing.
Adjustment: Use LaggedStart()
for grouped animations or self.play(*animations)
for simultaneous reveal.
Growing the Data Bars
= []
animations for bar in histograms:
= np.random.uniform(1, 3)
new_height = new_height / min_height
scale_factor
animations.append(1, 1, scale_factor])
bar.animate.scale([0, 0, (new_height - min_height) / 2])
.shift([ )
scale([1,1,z])
scales only the height.shift
keeps the bottom anchored on the base grid.
for anim in animations:
self.play(anim, run_time=1)
self.wait(0.5)
- Animates bars growing one after another.
Adjustment: For faster animation, use:
self.play(*animations, run_time=3)
Rotating the Scene
self.move_camera(phi=75 * DEGREES, theta=135 * DEGREES, run_time=3)
self.wait(1)
self.move_camera(phi=45 * DEGREES, theta=(360+45) * DEGREES, run_time=5)
self.move_camera(phi=75 * DEGREES, theta=45 * DEGREES, run_time=4)
self.move_camera(phi=0 * DEGREES, theta=405 * DEGREES, run_time=6)
self.move_camera(phi=0 * DEGREES, theta=765 * DEGREES, run_time=6)
- Smoothly transitions between multiple camera angles.
- Helps users appreciate the spatial layout of the data.
Advanced: Use self.begin_ambient_camera_rotation()
for continuous movement.
Fade Out
self.play(
*[FadeOut(mob) for mob in self.mobjects],
=5,
run_time=rate_functions.smooth
rate_func )
- Gracefully removes all elements from the scene.
- A polished conclusion to the animation.
Summary
- Used Manim’s 3D capabilities to build a vibrant histogram animation.
- Combined object animation and camera control for storytelling.
- Each bar’s height represented dynamic values, growing over time.
- Applied lighting, color, and movement to enhance visual engagement.
- Final camera rotations gave a complete spatial understanding of the scene.
Experiment Suggestions
- Swap random heights with real CSV data.
- Add axes labels using Axes3D.
- Group bars by color to represent categories.
- Add interactivity by syncing frame output with voice narration or subtitles.