0
# Probability and Statistics
1
2
ManimGL provides specialized tools for creating probability and statistical visualizations through the probability module. These components enable interactive probability demonstrations, statistical data visualization, and educational content around probability theory with sample spaces and customizable charts.
3
4
## Capabilities
5
6
### Sample Space Visualization
7
8
Create visual representations of probability sample spaces as colored rectangles that can be subdivided to show probability distributions and conditional probabilities.
9
10
```python { .api }
11
class SampleSpace(Rectangle):
12
def __init__(
13
self,
14
width: float = 3,
15
height: float = 3,
16
fill_color: ManimColor = GREY_D,
17
fill_opacity: float = 1,
18
stroke_width: float = 0.5,
19
stroke_color: ManimColor = GREY_B,
20
default_label_scale_val: float = 1,
21
**kwargs
22
):
23
"""
24
Create a visual sample space for probability demonstrations.
25
26
Parameters:
27
- width: Width of the sample space rectangle
28
- height: Height of the sample space rectangle
29
- fill_color: Base color for the sample space
30
- fill_opacity: Opacity of the filled region
31
- stroke_width: Border thickness
32
- stroke_color: Border color
33
- default_label_scale_val: Scale factor for labels
34
"""
35
36
def add_title(self, title: str = "Sample space", buff: float = MED_SMALL_BUFF) -> None:
37
"""Add a title above the sample space."""
38
39
def add_label(self, label: str) -> None:
40
"""Add a label to the sample space."""
41
42
def complete_p_list(self, p_list: list[float]) -> list[float]:
43
"""
44
Ensure probability list sums to 1 by adding remainder.
45
46
Parameters:
47
- p_list: List of probability values
48
49
Returns:
50
Completed probability list that sums to 1
51
"""
52
53
def get_horizontal_division(
54
self,
55
p_list,
56
colors=[GREEN_E, BLUE_E],
57
vect=DOWN
58
) -> VGroup:
59
"""
60
Create horizontal subdivision of sample space.
61
62
Parameters:
63
- p_list: List of probability values for division
64
- colors: Colors for each subdivision
65
- vect: Direction vector for subdivision
66
67
Returns:
68
VGroup of divided regions
69
"""
70
71
def get_vertical_division(
72
self,
73
p_list,
74
colors=[MAROON_B, YELLOW],
75
vect=RIGHT
76
) -> VGroup:
77
"""
78
Create vertical subdivision of sample space.
79
80
Parameters:
81
- p_list: List of probability values for division
82
- colors: Colors for each subdivision
83
- vect: Direction vector for subdivision
84
85
Returns:
86
VGroup of divided regions
87
"""
88
89
def divide_horizontally(self, *args, **kwargs) -> None:
90
"""Divide the sample space horizontally and add to scene."""
91
92
def divide_vertically(self, *args, **kwargs) -> None:
93
"""Divide the sample space vertically and add to scene."""
94
95
def get_subdivision_braces_and_labels(
96
self,
97
parts,
98
labels,
99
direction,
100
buff=SMALL_BUFF
101
) -> VGroup:
102
"""
103
Create braces and labels for subdivisions.
104
105
Parameters:
106
- parts: List of subdivision parts
107
- labels: List of label strings
108
- direction: Direction for brace placement
109
- buff: Buffer distance from subdivision
110
111
Returns:
112
VGroup containing braces and labels
113
"""
114
115
def get_side_braces_and_labels(
116
self,
117
labels,
118
direction=LEFT,
119
**kwargs
120
) -> VGroup:
121
"""Create side braces and labels for sample space."""
122
123
def get_top_braces_and_labels(self, labels, **kwargs) -> VGroup:
124
"""Create top braces and labels for sample space."""
125
126
def get_bottom_braces_and_labels(self, labels, **kwargs) -> VGroup:
127
"""Create bottom braces and labels for sample space."""
128
129
def __getitem__(self, index: int | slice) -> VGroup:
130
"""Access subdivisions by index."""
131
```
132
133
### Statistical Charts
134
135
Create customizable bar charts for displaying discrete probability distributions and statistical data with axes, labels, and styling.
136
137
```python { .api }
138
class BarChart(VGroup):
139
def __init__(
140
self,
141
values: Iterable[float],
142
height: float = 4,
143
width: float = 6,
144
n_ticks: int = 4,
145
include_x_ticks: bool = False,
146
tick_width: float = 0.2,
147
tick_height: float = 0.15,
148
label_y_axis: bool = True,
149
y_axis_label_height: float = 0.25,
150
max_value: float = 1,
151
bar_colors: list[ManimColor] = [BLUE, YELLOW],
152
bar_fill_opacity: float = 0.8,
153
bar_stroke_width: float = 3,
154
bar_names: list[str] = [],
155
bar_label_scale_val: float = 0.75,
156
**kwargs
157
):
158
"""
159
Create a statistical bar chart with axes and labels.
160
161
Parameters:
162
- values: Iterable of numeric values for bar heights
163
- height: Total height of the chart
164
- width: Total width of the chart
165
- n_ticks: Number of tick marks on y-axis
166
- include_x_ticks: Whether to include x-axis tick marks
167
- tick_width: Width of tick marks
168
- tick_height: Height of tick marks
169
- label_y_axis: Whether to label the y-axis
170
- y_axis_label_height: Height of y-axis labels
171
- max_value: Maximum value for scaling bars
172
- bar_colors: Colors for bars (gradient applied)
173
- bar_fill_opacity: Opacity of bar fills
174
- bar_stroke_width: Width of bar borders
175
- bar_names: Labels for individual bars
176
- bar_label_scale_val: Scale factor for bar labels
177
"""
178
179
def add_axes(self) -> None:
180
"""Create and add x and y axes with tick marks."""
181
182
def add_bars(self, values: Iterable[float]) -> None:
183
"""
184
Create bars proportional to input values.
185
186
Parameters:
187
- values: Numeric values determining bar heights
188
"""
189
190
def change_bar_values(self, values: Iterable[float]) -> None:
191
"""
192
Update bar heights dynamically while maintaining positions.
193
194
Parameters:
195
- values: New values for bar heights
196
"""
197
```
198
199
## Usage Examples
200
201
### Basic Probability Space Demonstration
202
203
```python
204
from manimlib import *
205
206
class BasicProbability(Scene):
207
def construct(self):
208
# Create a sample space
209
sample_space = SampleSpace(width=4, height=3)
210
sample_space.add_title("Rolling a Die")
211
sample_space.set_fill(BLUE_E, opacity=0.3)
212
213
self.play(ShowCreation(sample_space))
214
self.wait()
215
216
# Show equally likely outcomes
217
probabilities = [1/6] * 6
218
horizontal_div = sample_space.get_horizontal_division(
219
probabilities,
220
colors=[RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE]
221
)
222
223
self.play(ShowCreation(horizontal_div))
224
225
# Add labels for outcomes
226
outcome_labels = ["1", "2", "3", "4", "5", "6"]
227
braces_and_labels = sample_space.get_bottom_braces_and_labels(
228
outcome_labels
229
)
230
231
self.play(Write(braces_and_labels))
232
self.wait()
233
```
234
235
### Conditional Probability Visualization
236
237
```python
238
class ConditionalProbability(Scene):
239
def construct(self):
240
# Create sample space for conditional probability
241
sample_space = SampleSpace(width=5, height=4)
242
sample_space.add_title("P(B|A) - Conditional Probability")
243
244
self.add(sample_space)
245
246
# First division: P(A) and P(A')
247
sample_space.divide_horizontally([0.4, 0.6])
248
249
# Add horizontal labels
250
h_labels = sample_space.get_side_braces_and_labels(["A", "A'"])
251
self.play(Write(h_labels))
252
self.wait()
253
254
# Second division: P(B|A) and P(B'|A) within each region
255
sample_space.divide_vertically([0.7, 0.3])
256
257
# Add vertical labels
258
v_labels = sample_space.get_top_braces_and_labels(["B", "B'"])
259
self.play(Write(v_labels))
260
self.wait()
261
262
# Highlight the intersection P(A ∩ B)
263
intersection = sample_space[0][0] # Top-left region
264
intersection.set_fill(YELLOW, opacity=0.8)
265
266
# Add calculation text
267
calc_text = TexText(
268
"P(A ∩ B) = P(A) × P(B|A) = 0.4 × 0.7 = 0.28",
269
font_size=36
270
).to_edge(DOWN)
271
272
self.play(
273
intersection.animate.set_fill(YELLOW, opacity=0.8),
274
Write(calc_text)
275
)
276
self.wait()
277
```
278
279
### Probability Mass Function Visualization
280
281
```python
282
class ProbabilityDistribution(Scene):
283
def construct(self):
284
# Binomial distribution example
285
n, p = 4, 0.3
286
287
# Calculate binomial probabilities
288
from math import comb
289
values = []
290
labels = []
291
292
for k in range(n + 1):
293
prob = comb(n, k) * (p ** k) * ((1 - p) ** (n - k))
294
values.append(prob)
295
labels.append(f"X = {k}")
296
297
# Create bar chart
298
chart = BarChart(
299
values,
300
height=4,
301
width=8,
302
max_value=0.5,
303
bar_names=labels,
304
bar_colors=[BLUE, RED],
305
include_x_ticks=True
306
)
307
308
# Add title and axis labels
309
title = Text("Binomial Distribution: n=4, p=0.3", font_size=32)
310
title.to_edge(UP)
311
312
y_label = Text("P(X = k)", font_size=24)
313
y_label.rotate(PI/2)
314
y_label.next_to(chart, LEFT)
315
316
x_label = Text("Number of Successes (k)", font_size=24)
317
x_label.next_to(chart, DOWN)
318
319
self.play(ShowCreation(chart))
320
self.play(Write(title), Write(x_label), Write(y_label))
321
322
# Animate probability calculation
323
for i, (val, label) in enumerate(zip(values, labels)):
324
prob_text = Text(f"P({label.split()[-1]}) = {val:.3f}", font_size=20)
325
prob_text.next_to(chart[1][i], UP, buff=0.1)
326
327
self.play(Write(prob_text), run_time=0.5)
328
329
self.wait()
330
```
331
332
### Interactive Statistical Comparison
333
334
```python
335
from manimlib.mobject.interactive import LinearNumberSlider
336
337
class InteractiveStats(Scene):
338
def setup(self):
339
# Create sliders for parameters
340
self.n_slider = LinearNumberSlider(
341
value=10, min_value=5, max_value=50, step=1
342
)
343
self.p_slider = LinearNumberSlider(
344
value=0.5, min_value=0.1, max_value=0.9, step=0.05
345
)
346
347
self.n_slider.to_edge(DOWN).shift(UP * 0.5)
348
self.p_slider.to_edge(DOWN)
349
350
self.add(self.n_slider, self.p_slider)
351
352
def construct(self):
353
# Create responsive chart
354
def get_binomial_chart():
355
n = int(self.n_slider.get_value())
356
p = self.p_slider.get_value()
357
358
# Calculate probabilities
359
from math import comb
360
values = []
361
for k in range(min(n + 1, 20)): # Limit for display
362
prob = comb(n, k) * (p ** k) * ((1 - p) ** (n - k))
363
values.append(prob)
364
365
return BarChart(
366
values,
367
height=3,
368
width=6,
369
max_value=0.4,
370
bar_colors=[BLUE, YELLOW]
371
)
372
373
chart = get_binomial_chart()
374
chart.to_edge(UP)
375
376
# Add updater
377
def update_chart(c):
378
new_chart = get_binomial_chart()
379
new_chart.to_edge(UP)
380
c.become(new_chart)
381
382
chart.add_updater(update_chart)
383
384
# Add parameter labels
385
n_label = Text("n (trials)", font_size=20).next_to(self.n_slider, LEFT)
386
p_label = Text("p (success prob)", font_size=20).next_to(self.p_slider, LEFT)
387
388
# Dynamic title
389
title = Text("Interactive Binomial Distribution", font_size=28)
390
title.to_edge(UP).shift(DOWN * 0.5)
391
392
def update_title(t):
393
n = int(self.n_slider.get_value())
394
p = self.p_slider.get_value()
395
new_title = Text(
396
f"Binomial Distribution: n={n}, p={p:.2f}",
397
font_size=28
398
)
399
new_title.to_edge(UP).shift(DOWN * 0.5)
400
t.become(new_title)
401
402
title.add_updater(update_title)
403
404
self.add(chart, n_label, p_label, title)
405
self.wait(15) # Interactive exploration time
406
```
407
408
### Monte Carlo Simulation
409
410
```python
411
class MonteCarloDemo(Scene):
412
def construct(self):
413
# Set up sample space for coin flips
414
sample_space = SampleSpace(width=3, height=2)
415
sample_space.add_title("Coin Flip Outcomes")
416
sample_space.to_edge(LEFT)
417
418
# Divide for heads/tails
419
sample_space.divide_horizontally([0.5, 0.5])
420
sample_space[0].set_fill(GREEN, opacity=0.7)
421
sample_space[1].set_fill(RED, opacity=0.7)
422
423
labels = sample_space.get_side_braces_and_labels(["H", "T"])
424
425
# Results chart
426
chart = BarChart(
427
[0, 0], # Start with no results
428
height=3,
429
width=4,
430
max_value=1,
431
bar_names=["Heads", "Tails"],
432
bar_colors=[GREEN, RED]
433
)
434
chart.to_edge(RIGHT)
435
436
self.add(sample_space, labels, chart)
437
438
# Simulate coin flips
439
import random
440
heads_count = 0
441
total_flips = 0
442
443
counter_text = Text("Flips: 0", font_size=24).to_edge(UP)
444
self.add(counter_text)
445
446
for flip in range(100):
447
total_flips += 1
448
result = random.choice([0, 1]) # 0 = heads, 1 = tails
449
450
if result == 0:
451
heads_count += 1
452
453
# Update proportions
454
heads_prop = heads_count / total_flips
455
tails_prop = 1 - heads_prop
456
457
# Update chart
458
chart.change_bar_values([heads_prop, tails_prop])
459
460
# Update counter
461
counter_text.become(
462
Text(f"Flips: {total_flips}", font_size=24).to_edge(UP)
463
)
464
465
if flip % 10 == 0: # Update every 10 flips for animation
466
self.wait(0.1)
467
468
# Final result
469
final_text = Text(
470
f"Final: {heads_count}/{total_flips} = {heads_prop:.3f}",
471
font_size=24
472
).to_edge(DOWN)
473
474
self.play(Write(final_text))
475
self.wait()
476
```
477
478
### Statistical Test Visualization
479
480
```python
481
class HypothesisTest(Scene):
482
def construct(self):
483
# Set up hypothesis testing scenario
484
title = Text("Hypothesis Testing", font_size=36).to_edge(UP)
485
486
# Null and alternative hypotheses
487
h0 = TexText("H₀: p = 0.5 (fair coin)", font_size=24)
488
h1 = TexText("H₁: p ≠ 0.5 (biased coin)", font_size=24)
489
490
hypotheses = VGroup(h0, h1).arrange(DOWN, buff=0.3)
491
hypotheses.to_edge(LEFT).shift(UP)
492
493
# Sample space showing expected vs observed
494
expected_space = SampleSpace(width=2.5, height=1.5)
495
expected_space.add_title("Expected (H₀)")
496
expected_space.divide_horizontally([0.5, 0.5])
497
expected_space[0].set_fill(BLUE, opacity=0.6)
498
expected_space[1].set_fill(RED, opacity=0.6)
499
500
observed_space = SampleSpace(width=2.5, height=1.5)
501
observed_space.add_title("Observed")
502
observed_space.divide_horizontally([0.3, 0.7]) # Biased result
503
observed_space[0].set_fill(BLUE, opacity=0.6)
504
observed_space[1].set_fill(RED, opacity=0.6)
505
506
spaces = VGroup(expected_space, observed_space)
507
spaces.arrange(RIGHT, buff=1).to_edge(DOWN).shift(UP * 0.5)
508
509
# Statistical analysis
510
analysis = VGroup(
511
Text("Sample size: n = 100", font_size=20),
512
Text("Observed heads: 30", font_size=20),
513
Text("Expected heads: 50", font_size=20),
514
Text("Test statistic: z = -4.0", font_size=20),
515
Text("p-value < 0.001", font_size=20),
516
).arrange(DOWN, aligned_edge=LEFT, buff=0.2)
517
analysis.to_edge(RIGHT)
518
519
# Animate the analysis
520
self.play(Write(title))
521
self.play(Write(hypotheses))
522
self.play(ShowCreation(spaces))
523
524
for line in analysis:
525
self.play(Write(line), run_time=0.8)
526
527
# Conclusion
528
conclusion = Text("Reject H₀: Strong evidence of bias",
529
font_size=24, color=YELLOW)
530
conclusion.to_edge(DOWN)
531
532
self.play(Write(conclusion))
533
self.wait()
534
```
535
536
## Advanced Features
537
538
### Custom Probability Distributions
539
540
```python
541
# Create custom sample space divisions
542
def create_custom_distribution(probabilities, colors):
543
space = SampleSpace()
544
division = space.get_horizontal_division(probabilities, colors)
545
return space, division
546
547
# Multi-level conditioning
548
def create_tree_diagram(space, levels):
549
for level in levels:
550
# Recursive subdivision logic
551
pass
552
```
553
554
### Dynamic Chart Updates
555
556
```python
557
# Smooth transitions between data sets
558
def animate_data_change(chart, old_values, new_values, run_time=2):
559
# Custom animation for smooth bar transitions
560
pass
561
562
# Real-time data streaming
563
def add_streaming_updater(chart, data_source):
564
def updater(c):
565
new_data = data_source.get_latest()
566
c.change_bar_values(new_data)
567
chart.add_updater(updater)
568
```
569
570
The probability and statistics module in ManimGL provides powerful tools for creating educational content around probability theory and statistical analysis, with particular strengths in visual probability demonstrations and interactive statistical visualizations.