mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
240 lines
7.5 KiB
Python
240 lines
7.5 KiB
Python
![]() |
from helpers import *
|
||
|
import scipy
|
||
|
|
||
|
from animation.animation import Animation
|
||
|
from animation.transform import *
|
||
|
from animation.simple_animations import *
|
||
|
from animation.playground import *
|
||
|
from animation.continual_animation import *
|
||
|
from topics.geometry import *
|
||
|
from topics.characters import *
|
||
|
from topics.functions import *
|
||
|
from topics.fractals import *
|
||
|
from topics.number_line import *
|
||
|
from topics.combinatorics import *
|
||
|
from topics.numerals import *
|
||
|
from topics.three_dimensions import *
|
||
|
from topics.objects import *
|
||
|
from topics.probability import *
|
||
|
from topics.complex_numbers import *
|
||
|
from topics.common_scenes import *
|
||
|
from scene import Scene
|
||
|
from scene.reconfigurable_scene import ReconfigurableScene
|
||
|
from scene.zoomed_scene import *
|
||
|
from camera import Camera
|
||
|
from mobject import *
|
||
|
from mobject.image_mobject import *
|
||
|
from mobject.vectorized_mobject import *
|
||
|
from mobject.svg_mobject import *
|
||
|
from mobject.tex_mobject import *
|
||
|
from topics.graph_scene import *
|
||
|
|
||
|
from active_projects.fourier import *
|
||
|
|
||
|
|
||
|
class GaussianDistributionWrapper(Line):
|
||
|
"""
|
||
|
This is meant to encode a 2d normal distribution as
|
||
|
a mobject (so as to be able to have it be interpolated
|
||
|
during animations). It is a line whose start_point coordinates
|
||
|
encode the coordinates of mu, and whose end_point - start_point
|
||
|
encodes the coordinates of sigma.
|
||
|
"""
|
||
|
CONFIG = {
|
||
|
"stroke_width" : 0,
|
||
|
"mu_x" : 0,
|
||
|
"sigma_x" : 1,
|
||
|
"mu_y" : 0,
|
||
|
"sigma_y" : 0,
|
||
|
}
|
||
|
def __init__(self, **kwargs):
|
||
|
Line.__init__(self, ORIGIN, RIGHT, **kwargs)
|
||
|
self.change_parameters(self.mu_x, self.mu_y, self.sigma_x, self.sigma_y)
|
||
|
|
||
|
def change_parameters(self, mu_x = None, mu_y = None, sigma_x = None, sigma_y = None):
|
||
|
curr_parameters = self.get_parameteters()
|
||
|
args = [mu_x, mu_y, sigma_x, sigma_y]
|
||
|
new_parameters = [
|
||
|
arg or curr
|
||
|
for curr, arg in zip(curr_parameters, args)
|
||
|
]
|
||
|
mu_x, mu_y, sigma_x, sigma_y = new_parameters
|
||
|
mu_point = mu_x*RIGHT + mu_y*UP
|
||
|
sigma_vect = sigma_x*RIGHT + sigma_y*UP
|
||
|
self.put_start_and_end_on(mu_point, mu_point + sigma_vect)
|
||
|
return self
|
||
|
|
||
|
def get_parameteters(self):
|
||
|
""" Return mu_x, mu_y, sigma_x, sigma_y"""
|
||
|
start, end = self.get_start_and_end()
|
||
|
return tuple(it.chain(start[:2], (end - start)[:2]))
|
||
|
|
||
|
def get_random_points(self, size = 1):
|
||
|
mu_x, mu_y, sigma_x, sigma_y = self.get_parameteters()
|
||
|
x_vals = np.random.normal(mu_x, sigma_x, size)
|
||
|
y_vals = np.random.normal(mu_y, sigma_y, size)
|
||
|
return np.array([
|
||
|
x*RIGHT + y*UP
|
||
|
for x, y in zip(x_vals, y_vals)
|
||
|
])
|
||
|
|
||
|
class ProbabalisticMobjectCloud(ContinualAnimation):
|
||
|
CONFIG = {
|
||
|
"fill_opacity" : 0.25,
|
||
|
"n_copies" : 100,
|
||
|
"gaussian_distribution_wrapper_config" : {
|
||
|
"sigma_x" : 1,
|
||
|
}
|
||
|
}
|
||
|
def __init__(self, prototype, **kwargs):
|
||
|
digest_config(self, kwargs)
|
||
|
fill_opacity = self.fill_opacity or prototype.get_fill_opacity()
|
||
|
self.gaussian_distribution_wrapper = GaussianDistributionWrapper(
|
||
|
**self.gaussian_distribution_wrapper_config
|
||
|
)
|
||
|
group = VGroup(*[
|
||
|
prototype.copy().set_fill(opacity = fill_opacity)
|
||
|
for x in range(self.n_copies)
|
||
|
])
|
||
|
ContinualAnimation.__init__(self, group, **kwargs)
|
||
|
|
||
|
def update_mobject(self, dt):
|
||
|
group = self.mobject
|
||
|
points = self.gaussian_distribution_wrapper.get_random_points(len(group))
|
||
|
for mob, point in zip(group, points):
|
||
|
self.update_mobject_by_point(mob, point)
|
||
|
return self
|
||
|
|
||
|
def update_mobject_by_point(self, mobject, point):
|
||
|
mobject.move_to(point)
|
||
|
return self
|
||
|
|
||
|
class ProbabalisticDotCloud(ProbabalisticMobjectCloud):
|
||
|
CONFIG = {
|
||
|
"color" : BLUE,
|
||
|
}
|
||
|
def __init__(self, **kwargs):
|
||
|
digest_config(self, kwargs)
|
||
|
dot = Dot(color = self.color)
|
||
|
ProbabalisticMobjectCloud.__init__(self, dot)
|
||
|
|
||
|
class ProbabalisticVectorCloud(ProbabalisticMobjectCloud):
|
||
|
CONFIG = {
|
||
|
"color" : RED,
|
||
|
"n_copies" : 20,
|
||
|
"fill_opacity" : 0.5,
|
||
|
"center_func" : lambda : ORIGIN,
|
||
|
}
|
||
|
def __init__(self, **kwargs):
|
||
|
digest_config(self, kwargs)
|
||
|
vector = Vector(
|
||
|
RIGHT, color = self.color,
|
||
|
max_tip_length_to_length_ratio = 1,
|
||
|
)
|
||
|
ProbabalisticMobjectCloud.__init__(self, vector)
|
||
|
|
||
|
def update_mobject_by_point(self, vector, point):
|
||
|
vector.put_start_and_end_on(
|
||
|
self.center_func(),
|
||
|
point
|
||
|
)
|
||
|
|
||
|
###################
|
||
|
|
||
|
class MentionUncertaintyPrinciple(TeacherStudentsScene):
|
||
|
def construct(self):
|
||
|
title = TextMobject("Heisenberg Uncertainty Principle")
|
||
|
title.to_edge(UP)
|
||
|
|
||
|
dot_cloud = ProbabalisticDotCloud()
|
||
|
vector_cloud = ProbabalisticVectorCloud(
|
||
|
gaussian_distribution_wrapper_config = {"sigma_x" : 0.2},
|
||
|
center_func = dot_cloud.gaussian_distribution_wrapper.get_start,
|
||
|
)
|
||
|
for cloud in dot_cloud, vector_cloud:
|
||
|
gdw = cloud.gaussian_distribution_wrapper
|
||
|
gdw.move_to(title.get_center(), LEFT)
|
||
|
gdw.shift(2*DOWN)
|
||
|
vector_cloud.gaussian_distribution_wrapper.shift(3*RIGHT)
|
||
|
|
||
|
def get_brace_text_group_update(gdw, vect, text):
|
||
|
brace = Brace(gdw, vect)
|
||
|
text = brace.get_tex("\\sigma_{\\text{%s}}"%text, buff = SMALL_BUFF)
|
||
|
group = VGroup(brace, text)
|
||
|
def update_group(group):
|
||
|
brace, text = group
|
||
|
brace.match_width(gdw, stretch = True)
|
||
|
brace.next_to(gdw, vect)
|
||
|
text.next_to(brace, vect, buff = SMALL_BUFF)
|
||
|
return ContinualUpdateFromFunc(group, update_group)
|
||
|
|
||
|
dot_brace_anim = get_brace_text_group_update(
|
||
|
dot_cloud.gaussian_distribution_wrapper,
|
||
|
DOWN, "position",
|
||
|
)
|
||
|
vector_brace_anim = get_brace_text_group_update(
|
||
|
vector_cloud.gaussian_distribution_wrapper,
|
||
|
UP, "momentum",
|
||
|
)
|
||
|
|
||
|
self.add(title)
|
||
|
self.add(dot_cloud)
|
||
|
self.play(
|
||
|
Write(title),
|
||
|
self.teacher.change, "raise_right_hand",
|
||
|
self.get_student_changes(*["pondering"]*3)
|
||
|
)
|
||
|
self.play(
|
||
|
Write(dot_brace_anim.mobject, run_time = 1)
|
||
|
)
|
||
|
self.add(dot_brace_anim)
|
||
|
self.wait()
|
||
|
# self.wait(2)
|
||
|
self.play(
|
||
|
dot_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 0.1},
|
||
|
run_time = 2,
|
||
|
)
|
||
|
self.wait()
|
||
|
self.add(vector_cloud)
|
||
|
self.play(
|
||
|
FadeIn(vector_brace_anim.mobject)
|
||
|
)
|
||
|
self.add(vector_brace_anim)
|
||
|
self.play(
|
||
|
vector_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 1},
|
||
|
self.get_student_changes(*3*["confused"]),
|
||
|
run_time = 3,
|
||
|
)
|
||
|
self.wait()
|
||
|
#Back and forth
|
||
|
self.play(
|
||
|
dot_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 2},
|
||
|
vector_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 0.1},
|
||
|
run_time = 3,
|
||
|
)
|
||
|
self.change_student_modes("thinking", "erm", "sassy")
|
||
|
self.play(
|
||
|
dot_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 0.1},
|
||
|
vector_cloud.gaussian_distribution_wrapper.change_parameters,
|
||
|
{"sigma_x" : 1},
|
||
|
run_time = 3,
|
||
|
)
|
||
|
self.wait(2)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|