├── 2021
├── Car.svg
├── Car_Oben.svg
├── Left_Hand_Rule_Up.svg
├── Opening-Book.svg
├── Pin.svg
├── Right_Hand_Rule_Down.svg
├── Right_Hand_Rule_Up.svg
├── Right_Hand_Rule_Winding.svg
├── TrigFunc-Parameter-a.py
├── TrigFunc-Parameter-b.py
├── Vektoren-RMV-Addition.py
├── Vektoren-RMV-Intros.py
├── Vektoren-RMV-Linearkombination.py
├── Vektoren-RMV-SkalareMultiplikation.py
├── Vektoren-RMV-Skalarprodukt.py
├── Vektoren-RMV-Subtraktion.py
├── Vektoren-RMV-Trailer.py
├── Vektoren-RMV-Vektorprodukt.py
└── video_icon.svg
├── 2022
├── Binomial Distribution
│ ├── Binom-00-Trailer.py
│ ├── Binom-01-BExp.py
│ ├── Binom-02-BTrail.py
│ ├── Binom-03-BFormula.py
│ ├── Binom-04-Hist.py
│ ├── Binom-05-ExpValue.py
│ ├── Binom-06-HistProp.py
│ ├── Binom-07-Kum.py
│ ├── Binom-08-KumTables.py
│ ├── Binom-09-Mindestens-Hoechstens.py
│ ├── BinomHelper.py
│ └── SVGs and IMGs
│ │ ├── Blood_Donation.svg
│ │ ├── BrainBulb.svg
│ │ ├── GummyBear.svg
│ │ ├── Jakob_Bernoulli.jpg
│ │ ├── Rabbit.svg
│ │ ├── biathlon-shoot.svg
│ │ ├── biathlon-skiing.svg
│ │ ├── clubs.svg
│ │ ├── diamonds.svg
│ │ ├── emoji_couple_holding_hands.svg
│ │ ├── emoji_couple_holding_hands_ww.svg
│ │ ├── emoji_heart_eyes.svg
│ │ ├── emoji_middle_finger.svg
│ │ ├── emoji_sunglas.svg
│ │ ├── hearts.svg
│ │ ├── human_body_back.svg
│ │ ├── open-tafelwerk-tables.png
│ │ ├── rose_illustration.svg
│ │ ├── smartphone.svg
│ │ ├── smartwatch.svg
│ │ ├── spades.svg
│ │ ├── table_binom_cdf_100.png
│ │ ├── table_binom_cdf_10_20_25.png
│ │ └── table_binom_cdf_50.png
├── Hypotests-01-Links.py
├── Hypotests-02-Links-Alpha.py
├── TrigFunc-All-Parameters.py
├── TrigFunc-Parameter-c.py
└── TrigFunc-Parameter-d.py
└── README.md
/2021/Car.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
68 |
--------------------------------------------------------------------------------
/2021/Car_Oben.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
87 |
--------------------------------------------------------------------------------
/2021/Left_Hand_Rule_Up.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
35 |
--------------------------------------------------------------------------------
/2021/Pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 |
--------------------------------------------------------------------------------
/2021/Right_Hand_Rule_Down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
58 |
--------------------------------------------------------------------------------
/2021/Right_Hand_Rule_Up.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
--------------------------------------------------------------------------------
/2021/Right_Hand_Rule_Winding.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
42 |
--------------------------------------------------------------------------------
/2021/Vektoren-RMV-Intros.py:
--------------------------------------------------------------------------------
1 | from manim import *
2 |
3 | vec_a_color = RED
4 | vec_b_color = YELLOW
5 | vec_c_color = BLUE
6 |
7 | x_color = PINK
8 | y_color = ORANGE
9 |
10 |
11 | # Video Icon
12 | class Intro_Addition(Scene):
13 | def construct(self):
14 |
15 | self.video_nums = 5
16 | self.this_video_index = 0
17 | self.video_path_arc = -90*DEGREES
18 | self.target_point = 4.5*LEFT + DOWN
19 |
20 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
21 |
22 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
23 | .scale(2)\
24 | .shift(RIGHT + DOWN)\
25 | .set_color(GREEN_E)
26 |
27 | self.video_rect = ScreenRectangle(height = 4)\
28 | .set_color(GREY)\
29 | .move_to(1.5*RIGHT + 1.5*DOWN)
30 |
31 | self.title_episode = Text("Addition von Vektoren")\
32 | .set_color_by_gradient(vec_a_color, vec_b_color, vec_c_color)\
33 | .set_fill(color = GREY, opacity = 0.5)\
34 | .set_stroke(width = 1.5)\
35 | .next_to(self.video_rect.get_top(), UP)
36 |
37 | self.setup_scene()
38 | self.pop_out_this_series()
39 | self.show_scenes_from_episode()
40 |
41 |
42 | def setup_scene(self):
43 |
44 | series = self.series = self.get_series_filmrolls()
45 | # calcs = self.calcs = self.get_calc_symbols()
46 | addition = self.get_add_pic()
47 | scalar = self.get_scalar_pic()
48 | lin_comp = self.get_lincomb_pic()
49 | dot_prod = self.get_dotprod_pic()
50 | cross_prod = self.get_crossprod_pic()
51 |
52 | self.calc_pics = VGroup(addition, scalar, lin_comp, dot_prod, cross_prod)
53 |
54 |
55 | self.play(
56 | AnimationGroup(
57 | *[DrawBorderThenFill(episode, run_time = 3) for episode in series], lag_ratio = 0.1,
58 | ),
59 | AnimationGroup(
60 | *[Create(pic, run_time = 3) for pic in self.calc_pics], lag_ratio = 0.1
61 | ),
62 | # Create(calcs, lag_ratio = 0.1, run_time = 3),
63 | Write(self.title_series, run_time = 1.5)
64 | )
65 | self.wait()
66 |
67 | def pop_out_this_series(self):
68 | target_point = self.target_point
69 |
70 | icon_and_pic = VGroup(self.series[self.this_video_index], self.calc_pics[self.this_video_index])
71 | icon_and_pic.save_state()
72 |
73 | icon_and_pic.generate_target()
74 | icon_and_pic.target.move_to(target_point)
75 |
76 | self.this_video = self.series[self.this_video_index]
77 |
78 | self.play(
79 | MoveToTarget(icon_and_pic, path_arc = self.video_path_arc),
80 | FadeOut(self.title_series, shift = 4*RIGHT),
81 | run_time = 2
82 | )
83 | self.wait()
84 |
85 | self.icon_and_pic = icon_and_pic
86 |
87 | def show_scenes_from_episode(self):
88 | this_video = self.this_video
89 |
90 | rotation_point = this_video[0:5].get_left()
91 |
92 | self.play(
93 | Rotating(this_video[0:5], radians = 30*DEGREES, about_point = rotation_point, rate_func = smooth, run_time = 1.5),
94 | Create(self.video_rect, run_time = 2),
95 | Write(self.title_episode, run_time = 2)
96 | )
97 | self.wait()
98 |
99 | self.play(Rotating(this_video[0:5], radians = -30*DEGREES, about_point = rotation_point, rate_func = smooth, run_time = 0.5))
100 | self.play(
101 | ShrinkToCenter(self.video_rect),
102 | FadeOut(self.title_episode, target_position = self.video_rect.get_center())
103 | )
104 | self.wait()
105 |
106 |
107 | self.play(
108 | Restore(self.icon_and_pic, path_arc = -self.video_path_arc),
109 | run_time = 2
110 | )
111 | self.wait()
112 |
113 |
114 | self.play(
115 | LaggedStartMap(FadeOut, self.series, shift = 2*UP, lag_ratio = 0.15),
116 | LaggedStartMap(FadeOut, self.calc_pics, shift = 2*UP, lag_ratio = 0.15),
117 | run_time = 3
118 | )
119 | self.wait()
120 |
121 | # functions
122 |
123 | def get_series_filmrolls(self):
124 | icon = SVGMobject(file_name = "video_icon")
125 |
126 | series = VGroup(*[icon.copy() for x in range(self.video_nums)])
127 | series.arrange_submobjects(RIGHT, buff = 0.75)
128 | series.set(width = config["frame_width"] - MED_LARGE_BUFF)
129 | series.set_color(GREY)#(LIGHTER_GREY, LIGHT_GREY, GREY, DARK_GREY, DARKER_GREY)#RED_A, RED_B, RED_C, RED_D, RED_E
130 | series.to_edge(UP)
131 |
132 | return series
133 |
134 | def get_calc_symbols(self):
135 | calcs = VGroup(*[
136 | MathTex(*tex)\
137 | .move_to(icon[-1])\
138 | .set_color_by_tex_to_color_map({"\\vec{a}": vec_a_color, "\\vec{b}": vec_b_color, "r": vec_c_color, "\\bullet": GREEN, "\\times": GREEN})
139 | for tex, icon in zip(
140 | [["\\vec{a}", "+", "\\vec{b}"], ["r", "\\cdot", "\\vec{a}"], ["r", "\\cdot", "\\vec{a}", "+", "s", "\\cdot", "\\vec{b}"], ["\\vec{a}", "\\bullet", "\\vec{b}"], ["\\vec{a}", "\\times", "\\vec{b}"]],
141 | self.series
142 | )
143 | ])
144 |
145 | def get_add_pic(self):
146 | vec_a_num = [1.5, 0, 0]
147 | vec_b_num = [0.5, 1, 0]
148 | vec_c_num = [a+b for a,b in zip(vec_a_num, vec_b_num)]
149 |
150 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
151 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
152 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
153 |
154 | vec_a2 = vec_a.copy().shift(vec_b_num[0]*RIGHT + vec_b_num[1]*UP)
155 | vec_b2 = vec_b.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
156 |
157 | for vec in vec_a2, vec_b2:
158 | vec.set_stroke(opacity = 0.4)
159 | vec.set_fill(opacity = 0.4)
160 |
161 | pic = VGroup(vec_a, vec_b, vec_a2, vec_b2, vec_c)
162 | pic.move_to(self.series[0][-1])
163 | pic.set(height = self.series[0][-1].get_height() - 0.2)
164 |
165 | return pic
166 |
167 | def get_scalar_pic(self):
168 | vec_a_num = [0.7, 0.2, 0]
169 | vec_c_num = [3*x for x in vec_a_num]
170 |
171 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
172 | vec_a2 = vec_a.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
173 | vec_a3 = vec_a2.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
174 |
175 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
176 |
177 | for vec in vec_a, vec_a2, vec_a3:
178 | vec.shift(0.5*UP)
179 |
180 | pic = VGroup(vec_a, vec_a2, vec_a3, vec_c)
181 | pic.move_to(self.series[1][-1])
182 | pic.set(height = self.series[1][-1].get_height() - 0.2)
183 |
184 | return pic
185 |
186 | def get_lincomb_pic(self):
187 | scalar_a = 0.5
188 | scalar_b = 2/3
189 |
190 | vec_a_num = [1.5, 0, 0]
191 | vec_b_num = [0.5, 1, 0]
192 | vec_c_num = [scalar_a * a + scalar_b * b for a,b in zip(vec_a_num, vec_b_num)]
193 |
194 | vec_a2_num = [scalar_a * x for x in vec_a_num]
195 | vec_b2_num = [scalar_b * x for x in vec_b_num]
196 |
197 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
198 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
199 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
200 |
201 | vec_a2 = Arrow(ORIGIN, vec_a2_num[0]*RIGHT + vec_a2_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
202 | vec_b2 = Arrow(ORIGIN, vec_b2_num[0]*RIGHT + vec_b2_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
203 |
204 | line_a = DashedLine(vec_a2.get_end(), vec_c.get_end(), color = GREY)
205 | line_b = DashedLine(vec_b2.get_end(), vec_c.get_end(), color = GREY)
206 |
207 | for vec in vec_a, vec_b:
208 | vec.set_stroke(opacity = 0.4)
209 | vec.set_fill(opacity = 0.4)
210 |
211 | pic = VGroup(line_a, line_b, vec_a, vec_b, vec_a2, vec_b2, vec_c)
212 | pic.move_to(self.series[2][-1])
213 | pic.set(height = self.series[2][-1].get_height() - 0.2)
214 |
215 | return pic
216 |
217 | def get_dotprod_pic(self):
218 | vec_a_num = [1.5, 0, 0]
219 | vec_b_num = [0.8, 1, 0]
220 | vec_c_num = [0.8, 0, 0]
221 |
222 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
223 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
224 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
225 |
226 | line = DashedLine(vec_b.get_end(), vec_c.get_end(), color = GREY)
227 |
228 | pic = VGroup(line, vec_a, vec_b, vec_c)
229 | pic.move_to(self.series[3][-1])
230 | pic.set(height = self.series[3][-1].get_height() - 0.2)
231 |
232 | return pic
233 |
234 | def get_crossprod_pic(self):
235 | vec_a_num = [1.25, 0.0, 0]
236 | vec_b_num = [0.75, 0.5, 0]
237 | vec_c_num = [0.00, 1, 0]
238 |
239 | vec_s_num = [a+b for a,b in zip(vec_a_num, vec_b_num)]
240 |
241 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
242 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
243 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
244 |
245 | vec_s = Arrow(ORIGIN, vec_s_num[0]*RIGHT + vec_s_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
246 |
247 | rect = VMobject()
248 | rect.set_points_as_corners([
249 | vec_a.get_start(),
250 | vec_a.get_end(),
251 | vec_s.get_end(),
252 | vec_b.get_end(),
253 | vec_b.get_start()
254 | ])
255 | rect.set_fill(color = vec_c_color, opacity = 0.3)
256 | rect.set_stroke(width = 0)
257 |
258 |
259 | pic = VGroup(rect, vec_a, vec_b, vec_c)
260 | pic.move_to(self.series[4][-1])
261 | pic.set(height = self.series[4][-1].get_height() - 0.2)
262 |
263 | return pic
264 |
265 |
266 | class Intro_Scalar(Intro_Addition):
267 | def construct(self):
268 |
269 | self.video_nums = 5
270 | self.this_video_index = 1
271 | self.video_path_arc = -120*DEGREES
272 | self.target_point = 4.5*LEFT + DOWN
273 |
274 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
275 |
276 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
277 | .scale(2)\
278 | .shift(RIGHT + DOWN)\
279 | .set_color(GREEN_E)
280 |
281 | self.video_rect = ScreenRectangle(height = 4)\
282 | .set_color(GREY)\
283 | .move_to(1.5*RIGHT + 1.5*DOWN)
284 |
285 | self.title_episode = Text("Skalare Multiplikation")\
286 | .set_color_by_gradient(vec_a_color, vec_b_color, vec_c_color)\
287 | .set_fill(color = GREY, opacity = 0.5)\
288 | .set_stroke(width = 1.5)\
289 | .next_to(self.video_rect.get_top(), UP)
290 |
291 | self.setup_scene()
292 | self.pop_out_this_series()
293 | self.show_scenes_from_episode()
294 |
295 |
296 | class Intro_Linear_Combination(Intro_Addition):
297 | def construct(self):
298 |
299 | self.video_nums = 5
300 | self.this_video_index = 2
301 | self.video_path_arc = -90*DEGREES
302 | self.target_point = 4.5*LEFT + DOWN
303 |
304 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
305 |
306 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
307 | .scale(2)\
308 | .shift(RIGHT + DOWN)\
309 | .set_color(GREEN_E)
310 |
311 | self.video_rect = ScreenRectangle(height = 4)\
312 | .set_color(GREY)\
313 | .move_to(1.5*RIGHT + 1.5*DOWN)
314 |
315 | self.title_episode = Text("Linearkombinationen")\
316 | .set_color_by_gradient(vec_a_color, vec_b_color, vec_c_color)\
317 | .set_fill(color = GREY, opacity = 0.5)\
318 | .set_stroke(width = 1.5)\
319 | .next_to(self.video_rect.get_top(), UP)
320 |
321 | self.setup_scene()
322 | self.pop_out_this_series()
323 | self.show_scenes_from_episode()
324 |
325 |
326 | class Intro_DotProduct(Intro_Addition):
327 | def construct(self):
328 |
329 | self.video_nums = 5
330 | self.this_video_index = 3
331 | self.video_path_arc = -90*DEGREES
332 | self.target_point = 4.5*LEFT + DOWN
333 |
334 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
335 |
336 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
337 | .scale(2)\
338 | .shift(RIGHT + DOWN)\
339 | .set_color(GREEN_E)
340 |
341 | self.video_rect = ScreenRectangle(height = 4)\
342 | .set_color(GREY)\
343 | .move_to(1.5*RIGHT + 1.5*DOWN)
344 |
345 | self.title_episode = Text("Skalarprodukt")\
346 | .set_color_by_gradient(vec_a_color, vec_b_color, vec_c_color)\
347 | .set_fill(color = GREY, opacity = 0.5)\
348 | .set_stroke(width = 1.5)\
349 | .next_to(self.video_rect.get_top(), UP)
350 |
351 | self.setup_scene()
352 | self.point_at_coming_episodes()
353 | self.new_pop_out_this_series()
354 | self.show_scenes_from_episode()
355 |
356 |
357 |
358 | def point_at_coming_episodes(self):
359 | self.play(
360 | AnimationGroup(
361 | VGroup(self.series[-2], self.calc_pics[-2]).animate(rate_func = there_and_back).shift(0.75*DOWN),
362 | VGroup(self.series[-1], self.calc_pics[-1]).animate(rate_func = there_and_back).shift(0.75*DOWN),
363 | FadeOut(self.title_series, shift = 14*LEFT),
364 | lag_ratio = 0.1
365 | ),
366 | run_time = 4
367 | )
368 | self.wait()
369 |
370 | def new_pop_out_this_series(self):
371 | target_point = self.target_point
372 |
373 | icon_and_pic = VGroup(self.series[self.this_video_index], self.calc_pics[self.this_video_index])
374 | icon_and_pic.save_state()
375 |
376 | icon_and_pic.generate_target()
377 | icon_and_pic.target.move_to(target_point)
378 |
379 | self.this_video = self.series[self.this_video_index]
380 |
381 | self.play(
382 | MoveToTarget(icon_and_pic, path_arc = self.video_path_arc),
383 | run_time = 4
384 | )
385 | self.wait()
386 |
387 | self.icon_and_pic = icon_and_pic
388 |
389 |
390 | class Intro_CrossProduct(Intro_Addition):
391 | def construct(self):
392 |
393 | self.video_nums = 5
394 | self.this_video_index = 4
395 | self.video_path_arc = -90*DEGREES
396 | self.target_point = 4.5*LEFT + DOWN
397 |
398 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
399 |
400 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
401 | .scale(2)\
402 | .shift(RIGHT + DOWN)\
403 | .set_color(GREEN_E)
404 |
405 | self.video_rect = ScreenRectangle(height = 4)\
406 | .set_color(GREY)\
407 | .move_to(1.5*RIGHT + 1.5*DOWN)
408 |
409 | self.title_episode = Text("Kreuzprodukt")\
410 | .set_color_by_gradient(vec_a_color, vec_b_color, vec_c_color)\
411 | .set_fill(color = GREY, opacity = 0.5)\
412 | .set_stroke(width = 1.5)\
413 | .next_to(self.video_rect.get_top(), UP)
414 |
415 | self.setup_scene()
416 | self.pop_out_this_series()
417 | self.show_scenes_from_episode()
418 |
419 |
420 |
421 |
422 |
423 | class Intro_Trailer(Intro_Addition):
424 | def construct(self):
425 | self.video_nums = 5
426 | self.this_video_index = 1
427 | self.video_path_arc = -120*DEGREES
428 | self.target_point = 4.5*LEFT + DOWN
429 |
430 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
431 |
432 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
433 | .scale(2)\
434 | .shift(RIGHT + DOWN)\
435 | .set_color(GREEN_E)
436 |
437 | self.video_rect = ScreenRectangle(height = 4)\
438 | .set_color(GREY)\
439 | .move_to(1.5*RIGHT + 1.5*DOWN)
440 |
441 |
442 | self.setup_scene()
443 | self.arrange_vertically()
444 | self.go_through_episodes()
445 | self.pop_out_window()
446 |
447 |
448 | def arrange_vertically(self):
449 | for mob in self.series, self.calc_pics:
450 | mob.save_state()
451 |
452 | self.calc_pics.generate_target()
453 | self.calc_pics.target.arrange_submobjects(DOWN).to_edge(LEFT).shift(2*RIGHT)
454 |
455 | self.play(
456 | AnimationGroup(
457 | ApplyMethod(self.series.shift, 3*UP, lag_ratio = 0.2),
458 | FadeOut(self.title_series),
459 | MoveToTarget(self.calc_pics),
460 | lag_ratio = 0.2
461 | ),
462 | run_time = 4
463 | )
464 | self.wait()
465 |
466 |
467 | self.epi_numbers = VGroup(*[
468 | MathTex(tex).next_to(pic.get_center(), LEFT, buff = 1.5)
469 | for tex, pic in zip(
470 | ["01", "02", "03", "04", "05"],
471 | self.calc_pics
472 | )
473 | ])
474 |
475 | self.epi_titles = VGroup(*[
476 | Tex(tex).next_to(pic.get_center(), RIGHT, buff = 1.5)
477 | for tex, pic in zip(
478 | ["Addition", "Skalare Multiplikation", "Linearkombinationen", "Skalarprodukt", "Kreuzprodukt"],
479 | self.calc_pics
480 | )
481 | ])
482 | self.play(
483 | FadeIn(self.epi_numbers, shift = RIGHT, lag_ratio = 0.15),
484 | FadeIn(self.epi_titles, shift = LEFT, lag_ratio = 0.15),
485 | run_time = 2
486 | )
487 | self.wait()
488 |
489 | def go_through_episodes(self):
490 | self.play(
491 | *[mob[1:].animate.set_color(DARK_GREY) for mob in [self.epi_numbers, self.epi_titles]]
492 | )
493 | self.wait(1.75)
494 |
495 | for index in range(1, len(self.calc_pics)):
496 | self.play(
497 | *[mob[index - 1].animate.set_color(DARK_GREY) for mob in [self.epi_numbers, self.epi_titles]],
498 | *[mob[index].animate.set_color(WHITE) for mob in [self.epi_numbers, self.epi_titles]],
499 | )
500 | self.wait(1.75)
501 |
502 | self.play(*[mob[:-1].animate.set_color(WHITE) for mob in [self.epi_numbers, self.epi_titles]])
503 | self.wait()
504 |
505 |
506 | self.play(
507 | Restore(self.calc_pics),
508 | Restore(self.series),
509 | FadeOut(self.epi_numbers, shift = RIGHT),
510 | FadeOut(self.epi_titles, shift = LEFT),
511 | run_time = 3
512 | )
513 | self.wait()
514 |
515 | def pop_out_window(self):
516 | rect = ScreenRectangle(height = 5, stroke_width = 3)
517 | rect.next_to(self.series, DOWN)
518 |
519 | self.play(Create(rect), run_time = 2)
520 | self.wait()
521 |
522 |
523 |
--------------------------------------------------------------------------------
/2021/Vektoren-RMV-Trailer.py:
--------------------------------------------------------------------------------
1 | from manim import *
2 |
3 | vec_a_color = RED
4 | vec_b_color = YELLOW
5 | vec_c_color = BLUE
6 |
7 | x_color = PINK
8 | y_color = ORANGE
9 |
10 |
11 |
12 |
13 |
14 | class Intro_Trailer(Scene):
15 | def construct(self):
16 | self.video_nums = 5
17 | self.this_video_index = 1
18 | self.video_path_arc = -120*DEGREES
19 | self.target_point = 4.5*LEFT + DOWN
20 |
21 | self.arrow_kwargs = {"buff": 0, "stroke_width": 3, "max_tip_length_to_length_ratio": 0.2}
22 |
23 | self.title_series = Text("Rechnen mit \nVektoren", font = "Bahnschrift")\
24 | .scale(2)\
25 | .shift(RIGHT + DOWN)\
26 | .set_color(GREEN_E)
27 |
28 | self.video_rect = ScreenRectangle(height = 4)\
29 | .set_color(GREY)\
30 | .move_to(1.5*RIGHT + 1.5*DOWN)
31 |
32 |
33 | self.setup_scene()
34 | self.arrange_vertically()
35 | self.show_episodes()
36 | self.pop_out_window()
37 | self.go_through_episodes()
38 |
39 | def setup_scene(self):
40 |
41 | series = self.series = self.get_series_filmrolls()
42 | # calcs = self.calcs = self.get_calc_symbols()
43 | addition = self.get_add_pic()
44 | scalar = self.get_scalar_pic()
45 | lin_comp = self.get_lincomb_pic()
46 | dot_prod = self.get_dotprod_pic()
47 | cross_prod = self.get_crossprod_pic()
48 |
49 | self.calc_pics = VGroup(addition, scalar, lin_comp, dot_prod, cross_prod)
50 |
51 |
52 | self.play(
53 | AnimationGroup(
54 | *[DrawBorderThenFill(episode, run_time = 3) for episode in series], lag_ratio = 0.1,
55 | ),
56 | AnimationGroup(
57 | *[Create(pic, run_time = 3) for pic in self.calc_pics], lag_ratio = 0.1
58 | ),
59 | # Create(calcs, lag_ratio = 0.1, run_time = 3),
60 | Write(self.title_series, run_time = 1.5)
61 | )
62 | self.wait()
63 |
64 | def arrange_vertically(self):
65 | for mob in self.series, self.calc_pics:
66 | mob.save_state()
67 |
68 | self.calc_pics.generate_target()
69 | self.calc_pics.target.arrange_submobjects(DOWN).to_edge(LEFT).shift(2*RIGHT)
70 |
71 | self.play(
72 | AnimationGroup(
73 | ApplyMethod(self.series.shift, 3*UP, lag_ratio = 0.2),
74 | FadeOut(self.title_series),
75 | MoveToTarget(self.calc_pics),
76 | lag_ratio = 0.2
77 | ),
78 | run_time = 4
79 | )
80 | self.wait()
81 |
82 |
83 | self.epi_numbers = VGroup(*[
84 | MathTex(tex).next_to(pic.get_center(), LEFT, buff = 1.5)
85 | for tex, pic in zip(
86 | ["01", "02", "03", "04", "05"],
87 | self.calc_pics
88 | )
89 | ])
90 |
91 | self.epi_titles = VGroup(*[
92 | Tex(tex).next_to(pic.get_center(), RIGHT, buff = 1.5)
93 | for tex, pic in zip(
94 | ["Addition", "Skalare Multiplikation", "Linearkombinationen", "Skalarprodukt", "Kreuzprodukt"],
95 | self.calc_pics
96 | )
97 | ])
98 | self.play(
99 | FadeIn(self.epi_numbers, shift = RIGHT, lag_ratio = 0.15),
100 | FadeIn(self.epi_titles, shift = LEFT, lag_ratio = 0.15),
101 | run_time = 2
102 | )
103 | self.wait()
104 |
105 | def show_episodes(self):
106 | self.play(
107 | *[mob[1:].animate.set_color(DARK_GREY) for mob in [self.epi_numbers, self.epi_titles]]
108 | )
109 | self.wait(1.75)
110 |
111 | for index in range(1, len(self.calc_pics)):
112 | self.play(
113 | *[mob[index - 1].animate.set_color(DARK_GREY) for mob in [self.epi_numbers, self.epi_titles]],
114 | *[mob[index].animate.set_color(WHITE) for mob in [self.epi_numbers, self.epi_titles]],
115 | )
116 | self.wait(1.75)
117 |
118 | self.play(*[mob[:-1].animate.set_color(WHITE) for mob in [self.epi_numbers, self.epi_titles]])
119 | self.wait()
120 |
121 |
122 | self.play(
123 | Restore(self.calc_pics),
124 | Restore(self.series),
125 | FadeOut(self.epi_numbers, shift = RIGHT),
126 | self.epi_titles.animate.scale(0.7).to_edge(LEFT).shift(1*DOWN + 0.5*RIGHT),
127 | run_time = 3
128 | )
129 | self.wait()
130 |
131 | def pop_out_window(self):
132 | rect = ScreenRectangle(height = 5, stroke_width = 3)
133 | rect.next_to(self.series, DOWN)
134 | rect.to_edge(RIGHT)
135 |
136 | self.play(Create(rect), run_time = 2)
137 | self.wait(2)
138 |
139 | def go_through_episodes(self):
140 | pass
141 |
142 | # functions
143 |
144 | def get_series_filmrolls(self):
145 | icon = SVGMobject(file_name = "video_icon")
146 |
147 | series = VGroup(*[icon.copy() for x in range(self.video_nums)])
148 | series.arrange_submobjects(RIGHT, buff = 0.75)
149 | series.set(width = config["frame_width"] - MED_LARGE_BUFF)
150 | series.set_color(GREY)#(LIGHTER_GREY, LIGHT_GREY, GREY, DARK_GREY, DARKER_GREY)#RED_A, RED_B, RED_C, RED_D, RED_E
151 | series.to_edge(UP)
152 |
153 | return series
154 |
155 | def get_calc_symbols(self):
156 | calcs = VGroup(*[
157 | MathTex(*tex)\
158 | .move_to(icon[-1])\
159 | .set_color_by_tex_to_color_map({"\\vec{a}": vec_a_color, "\\vec{b}": vec_b_color, "r": vec_c_color, "\\bullet": GREEN, "\\times": GREEN})
160 | for tex, icon in zip(
161 | [["\\vec{a}", "+", "\\vec{b}"], ["r", "\\cdot", "\\vec{a}"], ["r", "\\cdot", "\\vec{a}", "+", "s", "\\cdot", "\\vec{b}"], ["\\vec{a}", "\\bullet", "\\vec{b}"], ["\\vec{a}", "\\times", "\\vec{b}"]],
162 | self.series
163 | )
164 | ])
165 |
166 | def get_add_pic(self):
167 | vec_a_num = [1.5, 0, 0]
168 | vec_b_num = [0.5, 1, 0]
169 | vec_c_num = [a+b for a,b in zip(vec_a_num, vec_b_num)]
170 |
171 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
172 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
173 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
174 |
175 | vec_a2 = vec_a.copy().shift(vec_b_num[0]*RIGHT + vec_b_num[1]*UP)
176 | vec_b2 = vec_b.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
177 |
178 | for vec in vec_a2, vec_b2:
179 | vec.set_stroke(opacity = 0.4)
180 | vec.set_fill(opacity = 0.4)
181 |
182 | pic = VGroup(vec_a, vec_b, vec_a2, vec_b2, vec_c)
183 | pic.move_to(self.series[0][-1])
184 | pic.set(height = self.series[0][-1].get_height() - 0.2)
185 |
186 | return pic
187 |
188 | def get_scalar_pic(self):
189 | vec_a_num = [0.7, 0.2, 0]
190 | vec_c_num = [3*x for x in vec_a_num]
191 |
192 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
193 | vec_a2 = vec_a.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
194 | vec_a3 = vec_a2.copy().shift(vec_a_num[0]*RIGHT + vec_a_num[1]*UP)
195 |
196 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
197 |
198 | for vec in vec_a, vec_a2, vec_a3:
199 | vec.shift(0.5*UP)
200 |
201 | pic = VGroup(vec_a, vec_a2, vec_a3, vec_c)
202 | pic.move_to(self.series[1][-1])
203 | pic.set(height = self.series[1][-1].get_height() - 0.2)
204 |
205 | return pic
206 |
207 | def get_lincomb_pic(self):
208 | scalar_a = 0.5
209 | scalar_b = 2/3
210 |
211 | vec_a_num = [1.5, 0, 0]
212 | vec_b_num = [0.5, 1, 0]
213 | vec_c_num = [scalar_a * a + scalar_b * b for a,b in zip(vec_a_num, vec_b_num)]
214 |
215 | vec_a2_num = [scalar_a * x for x in vec_a_num]
216 | vec_b2_num = [scalar_b * x for x in vec_b_num]
217 |
218 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
219 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
220 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
221 |
222 | vec_a2 = Arrow(ORIGIN, vec_a2_num[0]*RIGHT + vec_a2_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
223 | vec_b2 = Arrow(ORIGIN, vec_b2_num[0]*RIGHT + vec_b2_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
224 |
225 | line_a = DashedLine(vec_a2.get_end(), vec_c.get_end(), color = GREY)
226 | line_b = DashedLine(vec_b2.get_end(), vec_c.get_end(), color = GREY)
227 |
228 | for vec in vec_a, vec_b:
229 | vec.set_stroke(opacity = 0.4)
230 | vec.set_fill(opacity = 0.4)
231 |
232 | pic = VGroup(line_a, line_b, vec_a, vec_b, vec_a2, vec_b2, vec_c)
233 | pic.move_to(self.series[2][-1])
234 | pic.set(height = self.series[2][-1].get_height() - 0.2)
235 |
236 | return pic
237 |
238 | def get_dotprod_pic(self):
239 | vec_a_num = [1.5, 0, 0]
240 | vec_b_num = [0.8, 1, 0]
241 | vec_c_num = [0.8, 0, 0]
242 |
243 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
244 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
245 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
246 |
247 | line = DashedLine(vec_b.get_end(), vec_c.get_end(), color = GREY)
248 |
249 | pic = VGroup(line, vec_a, vec_b, vec_c)
250 | pic.move_to(self.series[3][-1])
251 | pic.set(height = self.series[3][-1].get_height() - 0.2)
252 |
253 | return pic
254 |
255 | def get_crossprod_pic(self):
256 | vec_a_num = [1.25, 0.0, 0]
257 | vec_b_num = [0.75, 0.5, 0]
258 | vec_c_num = [0.00, 1, 0]
259 |
260 | vec_s_num = [a+b for a,b in zip(vec_a_num, vec_b_num)]
261 |
262 | vec_a = Arrow(ORIGIN, vec_a_num[0]*RIGHT + vec_a_num[1]*UP, color = vec_a_color, **self.arrow_kwargs)
263 | vec_b = Arrow(ORIGIN, vec_b_num[0]*RIGHT + vec_b_num[1]*UP, color = vec_b_color, **self.arrow_kwargs)
264 | vec_c = Arrow(ORIGIN, vec_c_num[0]*RIGHT + vec_c_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
265 |
266 | vec_s = Arrow(ORIGIN, vec_s_num[0]*RIGHT + vec_s_num[1]*UP, color = vec_c_color, **self.arrow_kwargs)
267 |
268 | rect = VMobject()
269 | rect.set_points_as_corners([
270 | vec_a.get_start(),
271 | vec_a.get_end(),
272 | vec_s.get_end(),
273 | vec_b.get_end(),
274 | vec_b.get_start()
275 | ])
276 | rect.set_fill(color = vec_c_color, opacity = 0.3)
277 | rect.set_stroke(width = 0)
278 |
279 |
280 | pic = VGroup(rect, vec_a, vec_b, vec_c)
281 | pic.move_to(self.series[4][-1])
282 | pic.set(height = self.series[4][-1].get_height() - 0.2)
283 |
284 | return pic
285 |
286 |
287 | class ThreeVsTwoDimensions(Scene):
288 | def construct(self):
289 | pass
290 |
291 |
292 |
293 |
--------------------------------------------------------------------------------
/2021/video_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
41 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/Binom-00-Trailer.py:
--------------------------------------------------------------------------------
1 | from manim import *
2 | from BinomHelpers import *
3 |
4 |
5 | class OpinionPoll(Scene):
6 | def construct(self):
7 | map = self.get_german_map()
8 |
9 | pins = VGroup(*[SVGMobject(SVG_DIR + "pin", height = 0.25) for _ in range(6)])
10 | pins.arrange(RIGHT)
11 | pins[0].move_to(3.4*LEFT + 2.5*UP)
12 | pins[1].move_to(4*LEFT + 1.85*UP)
13 | pins[2].move_to(3*LEFT + 1*UP)
14 | pins[3].move_to(5.5*LEFT + 0.25*UP)
15 | pins[4].move_to(3.75*LEFT + 1.25*DOWN)
16 | pins[5].move_to(5*LEFT + 2*DOWN)
17 |
18 |
19 | self.play(Write(map), run_time = 3)
20 | self.play(LaggedStartMap(FadeIn, pins, shift = DOWN, lag_ratio = 0.1), run_time = 2)
21 | self.wait()
22 |
23 | data0 = np.zeros(6)
24 | data = np.array([0.4, 0.28, 0.13, 0.09, 0.06, 0.04])
25 | histo0 = Histogram(data0, width = 5, height = 4, bar_colors = [PURPLE, MAROON, ORANGE], include_x_labels = False)
26 | histo = Histogram(data, width = 5, height = 4, bar_colors = [PURPLE, MAROON, ORANGE], include_x_labels = False)
27 |
28 | for h in histo0, histo:
29 | h.shift(2.5*RIGHT)
30 |
31 | title = Tex("Hate it or love it", font_size = 64)
32 | title.scale(1.25)
33 | title.next_to(histo, UP, aligned_edge=RIGHT)
34 | title.set_color_by_gradient(PURPLE, MAROON, ORANGE)
35 |
36 | self.play(
37 | FadeIn(histo.axes),
38 | ReplacementTransform(histo0.bars, histo.bars, lag_ratio = 0.1),
39 | run_time = 3
40 | )
41 | self.play(Write(title))
42 |
43 | subject = Tex("Stochastik", color = YELLOW_E)
44 | subject.rotate(90*DEGREES)
45 | subject.set(width = histo.bars[0].width - 0.3)
46 | subject.next_to(histo.bars[0].get_bottom(), UP, buff = 0.2)
47 |
48 | self.play(FadeIn(subject, shift = 3*UP), run_time = 1)
49 | self.wait()
50 |
51 |
52 | # Bruchrechnung --> Baumdiagramm --> Pfadregeln
53 |
54 | histo_group = VGroup(title, histo, subject)
55 | tree = BinomTree(width = 5, height = 6, num_events = 3, cx_font_size = 16)
56 | tree.to_edge(LEFT)
57 |
58 | pfad = [1,5,12] # [[1,5,13], [1,5,12], [1,4,11], [1,4,10], [0,3,9], [0,3,8], [0,2,7], [0,2,6]]
59 | prob_all = tree.get_pfad_prob(texp = "0.75", texq = "0.25", use_prob_values=True)
60 |
61 | prob_pfad = VGroup(*[prob_all[x] for x in pfad])
62 |
63 | mult = MathTex("0.75", "\\cdot", "0.75", "\\cdot", "0.25")
64 | mult.move_to(tree)
65 |
66 | self.play(
67 | histo_group.animate.to_edge(RIGHT),
68 | Unwrite(map),
69 | LaggedStartMap(ShrinkToCenter, pins, lag_ratio = 0.1),
70 | FadeIn(mult, shift = 5*RIGHT, rate_func = squish_rate_func(smooth, 0.5, 1)),
71 | run_time = 2.5
72 | )
73 | self.wait(0.5)
74 | self.play(
75 | ReplacementTransform(mult, prob_pfad),
76 | FadeIn(tree.cx_marks, lag_ratio = 0.1),
77 | run_time = 2
78 | )
79 | self.wait(0.5)
80 |
81 |
82 | pfad_list = [[1,5,13], [1,5,12], [1,4,11], [1,4,10], [0,3,9], [0,3,8], [0,2,7], [0,2,6]]
83 | pfade = VGroup(*[tree.get_pfad(numbers) for numbers in pfad_list])
84 | moving_dots = VGroup(*[Dot(point = tree.lines[0].get_start()).set_fill(opacity = 0) for _ in range(8)])
85 | traces = VGroup(*[
86 | TracedPath(dot.get_center, dissipating_time=0.75, stroke_opacity=[0, 1, 0],
87 | stroke_color = YELLOW_D, stroke_width = 6)
88 | for dot in moving_dots
89 | ])
90 | self.add(traces)
91 | self.play(
92 | AnimationGroup(
93 | *[MoveAlongPath(dot, pfad, run_time = 2.5) for dot, pfad in zip(moving_dots, pfade)],
94 | lag_ratio = 0.1
95 | ),
96 | )
97 | for trace in traces:
98 | trace.clear_updaters()
99 | self.bring_to_back(tree)
100 | self.play(FadeOut(traces))
101 | self.wait()
102 |
103 | # functions
104 | def get_german_map(self):
105 | map = SVGMobject(SVG_DIR + "germany_map", height = config["frame_height"] - 2)
106 | map.to_edge(LEFT)
107 | map.set_fill(BLUE, 0.75)
108 | map.set_stroke(width = 2, color = YELLOW)
109 |
110 | return map
111 |
112 |
113 | class CodingScene(Scene):
114 | def construct(self):
115 |
116 | question = Tex("Wie programmiert \\\\man den Zufall?")
117 | question.scale(2)
118 | self.play(Write(question))
119 | self.wait()
120 |
121 | self.play(FadeOut(question, shift = 2*DOWN))
122 |
123 |
124 | code = '''
125 | self.play(
126 | AnimationGroup(*[
127 | MoveAlongPath(dot, pfad, run_time = 5)
128 | for dot, pfad in zip(moving_dots, pfade)
129 | ], lag_ratio = 0.1),
130 | run_time = 5
131 | )
132 | self.wait()
133 | '''
134 | rendered_code = Code(code=code, tab_width=4, background="window", language="Python", font="Monospace")
135 | self.play(Write(rendered_code))
136 | self.wait(3)
137 |
138 |
139 | self.play(
140 | rendered_code.animate.scale(0.8).to_edge(UP, buff = 0.2),
141 | run_time = 2
142 | )
143 | self.wait(3)
144 |
145 |
146 | class CodingScene2(Scene):
147 | def construct(self):
148 | code = '''
149 | choices = get_die_faces()
150 |
151 | def shuffle_die(mob):
152 | new_mob = random.choice(choices)
153 | new_mob.match_height(mob)
154 | mob.become(new_mob)
155 |
156 | for k in range(len(dices)):
157 | self.play(UpdateFromFunc(first_die, shuffle_die))
158 | first_die.become(choices[dice_values[k] - 1])
159 | self.play(TransformFromCopy(first_die, dices[k]))
160 | counter += 1
161 | num.set_value(counter)
162 | '''
163 |
164 | rendered_code = Code(code=code, tab_width=4, background="window", language="Python", font="Monospace")
165 | self.play(Write(rendered_code), run_time = 1.5)
166 | self.wait(3)
167 |
168 |
169 | class RiseHistoFromGround(HistoScene):
170 | def construct(self):
171 | n = 10
172 | p = 0.7
173 | histo_kwargs = {
174 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
175 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
176 | "bar_colors": [RED, GREEN, BLUE, YELLOW]
177 | }
178 | histo_0 = self.get_histogram(n, p, zeros = True, **histo_kwargs)
179 | histo = self.get_histogram(n, p, zeros = False, **histo_kwargs)
180 |
181 | for mob in histo_0, histo:
182 | mob.center().to_edge(UP)
183 |
184 | title = Tex("Binomialverteilung")\
185 | .set_color_by_gradient(*histo_kwargs["bar_colors"])\
186 | .set_fill(color = WHITE, opacity = 0.3)\
187 | .set_stroke(width = 1.5)\
188 | .set(width = config["frame_width"] - 3)\
189 | .to_edge(DOWN)
190 |
191 | self.play(
192 | DrawBorderThenFill(title, rate_func = squish_rate_func(smooth, 0.6, 1)),
193 | FadeIn(histo.axes),
194 | ReplacementTransform(histo_0.bars, histo.bars, lag_ratio = 0.2),
195 | run_time = 5
196 | )
197 | self.wait()
198 | self.remove(histo_0)
199 |
200 |
201 | p_val = ValueTracker(0.7)
202 | histo.p_val = p_val
203 | histo.n = n
204 | self.play(
205 | p_val.animate.set_value(0.25),
206 | UpdateFromFunc(histo, self.update_histogram),
207 | run_time = 4
208 | )
209 | self.wait()
210 |
211 | # functions
212 | def update_histogram(self, hist):
213 | new_dist = scipy.stats.binom(hist.n, hist.p_val.get_value())
214 | new_data = np.array([new_dist.pmf(x) for x in range(0, hist.n + 1)])
215 |
216 | new_bars = hist.get_bars(new_data)
217 | new_bars.match_style(hist.bars)
218 | hist.bars.become(new_bars)
219 |
220 |
221 | class AskForAbo(Scene):
222 | def construct(self):
223 | title = Tex("Wie wäre es denn mit einem...", " Abo", "???")
224 | title.set(width = 12)
225 | title.to_edge(UL)
226 |
227 | wheel = self.wheel = self.get_wheel()
228 | wheel.scale(1.25)
229 | wheel.shift(4*RIGHT)
230 |
231 | self.play(
232 | AnimationGroup(
233 | Write(title[0]),
234 | DrawBorderThenFill(wheel),
235 | lag_ratio = 0.4
236 | ),
237 | run_time = 3
238 | )
239 | self.wait()
240 |
241 |
242 | succ = wheel.succ[0].copy().scale(0.5)
243 | fail = wheel.fail[0].copy().scale(0.5)
244 | sf = VGroup(succ, fail)
245 | sf.arrange(DOWN, buff = 1)
246 | sf.move_to(5*LEFT)
247 |
248 | yes = Tex("Ja, warum nicht!").scale(1.25).next_to(succ, RIGHT)
249 | no = Tex("Ähm nope, Danke!").scale(1.25).next_to(fail, RIGHT)
250 |
251 | self.play(
252 | FadeIn(title[1:], shift = UP, scale = 0.1),
253 | LaggedStartMap(GrowFromCenter, sf, lag_ratio = 0.25),
254 | LaggedStartMap(FadeIn, VGroup(yes, no), shift = 2*LEFT, lag_ratio = 0.25),
255 | run_time = 1.5
256 | )
257 | self.wait()
258 |
259 | self.rotate_arrow(deg_angle = -(7*360 - 110), run_time = 8)
260 | self.wait()
261 |
262 | # functions
263 | def get_wheel(self):
264 | colors = [BLUE, ORANGE, BLUE, BLUE, BLUE]
265 | sectors = VGroup()
266 | for i in range(5):
267 | sector = Sector(
268 | outer_radius = 1.8, angle = 72*DEGREES, start_angle = i * 72*DEGREES - 36*DEGREES,
269 | color = colors[i], fill_opacity = 0.75
270 | )
271 | sector.set_stroke(width = 1, color = WHITE)
272 | sectors.add(sector)
273 |
274 | dot = Dot(color = WHITE).set_stroke(width = 1, color = BLACK)
275 | arrow = Arrow(1.35*DOWN, 1.35*UP, stroke_width = 8, color = BLACK).move_to(dot)
276 | arrow.rotate(-10*DEGREES)
277 | arrow.set_stroke(width = 10)
278 |
279 | wheel = VGroup(sectors, arrow, dot)
280 | wheel.arrow = arrow
281 | wheel.succ = VGroup(sectors[0], sectors[2], sectors[3], sectors[4])
282 | wheel.fail = VGroup(sectors[1])
283 |
284 | return wheel
285 |
286 | def rotate_arrow(self, deg_angle, added_anims = None, **kwargs):
287 | wheel = self.wheel
288 |
289 | if added_anims is None:
290 | added_anims = []
291 |
292 | self.play(
293 | Rotate(
294 | wheel.arrow,
295 | angle = deg_angle*DEGREES,
296 | about_point = wheel.get_center(),
297 | rate_func = slow_into,
298 | **kwargs
299 | ),
300 | *added_anims
301 | )
302 |
303 |
304 | class Thumbnail(HistoScene):
305 | def construct(self):
306 | n = 10
307 | p = 0.7
308 | p_val = ValueTracker(p)
309 | histo_kwargs = {
310 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
311 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
312 | "bar_colors": [RED, GREEN, BLUE, YELLOW]
313 | }
314 | histo = self.get_histogram(n, p, zeros = False, **histo_kwargs)
315 | histo.center()
316 | histo.to_edge(DOWN)
317 |
318 | title = Tex("Binomialverteilung")
319 | title.set(width = histo.width)
320 | title.set_color_by_gradient(RED, GREEN, BLUE, YELLOW)
321 | title.to_corner(UL)
322 |
323 | trailer = Tex("Trailer")
324 | trailer.to_edge(UP).shift(0.65*RIGHT)
325 |
326 | # for x in [0,1,2,3,4,6]:
327 | # histo.bars[x].set_fill(opacity = 0.2)
328 |
329 | p6 = MathTex("P", "(", "X", "=", "6", ")")
330 | p6[-2].set_color(C_COLOR)
331 | p6.rotate(90*DEGREES)
332 | p6.set(height = histo.bars[6].height - 0.25)
333 | p6.next_to(histo.bars[6].get_bottom(), UP, buff = 0.1)
334 |
335 | binom5 = get_binom_formula(10, 0.7, 6)[7:]
336 | binom5.next_to(histo.bars[6].get_corner(UL), UL)
337 |
338 |
339 | carrow = CurvedArrow(binom5.get_bottom() + 0.1*DOWN, histo.bars[6].get_left() + 0.5*UP, angle = TAU / 8, stroke_width = 3)
340 |
341 |
342 | self.add(histo, title, trailer)
343 | self.add(p6, binom5)
344 | self.add(carrow)
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 | class CasNoCas(Scene):
358 | def construct(self):
359 | title = Tex("Wir schreiben den Test ... ")
360 | title.scale(2.5)
361 | title.shift(UP)
362 |
363 | origin = Tex("mit Cas", color = RED)
364 | origin.scale(2.5)
365 |
366 | def update_tex(mob):
367 | value = random.uniform(0,1)
368 | if value < 0.5:
369 | tex = Tex("mit CAS", font_size = 72, color = RED)
370 | else:
371 | tex = Tex("ohne CAS", font_size = 72, color = GREEN)
372 | tex.scale(2.5)
373 | mob.become(tex)
374 |
375 | self.play(
376 | Write(title),
377 | FadeIn(origin, shift = 2*UP),
378 | )
379 | self.wait()
380 |
381 | self.play(
382 | UpdateFromFunc(origin, update_tex),
383 | run_time = 5
384 | )
385 | self.wait()
386 |
387 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/Binom-04-Hist.py:
--------------------------------------------------------------------------------
1 | from manim import *
2 | from BinomHelpers import *
3 | import random
4 |
5 | import scipy.stats
6 |
7 |
8 | class Intro(HistoScene):
9 | def construct(self):
10 | n = 10
11 | p = 0.7
12 | histo_kwargs = {
13 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
14 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
15 | "bar_colors": [RED, GREEN, BLUE, YELLOW]
16 | }
17 | histo_0 = self.get_histogram(n, p, zeros = True, **histo_kwargs)
18 | histo = self.get_histogram(n, p, zeros = False, **histo_kwargs)
19 |
20 | for mob in histo_0, histo:
21 | mob.center().to_edge(DOWN)
22 |
23 | title = Tex("Histogramm")\
24 | .set_color_by_gradient(*histo_kwargs["bar_colors"])\
25 | .set_fill(color = WHITE, opacity = 0.3)\
26 | .set_stroke(width = 1.5)\
27 | .set(width = config["frame_width"] - 6)\
28 | .to_corner(UR)
29 |
30 |
31 | self.add(histo_0)
32 | self.play(
33 | DrawBorderThenFill(title, rate_func = squish_rate_func(smooth, 0.6, 1)),
34 | ReplacementTransform(histo_0.bars, histo.bars, lag_ratio = 0.2),
35 | run_time = 5
36 | )
37 | self.wait()
38 | self.remove(histo_0)
39 |
40 |
41 | prop_val = ValueTracker(p)
42 | histo.p_val = prop_val
43 | histo.n = n
44 | def update_histogram(hist):
45 | new_dist = scipy.stats.binom(hist.n, hist.p_val.get_value())
46 | new_data = np.array([new_dist.pmf(x) for x in range(0, hist.n + 1)])
47 | new_bars = hist.get_bars(new_data)
48 | new_bars.match_style(hist.bars)
49 | hist.bars.become(new_bars)
50 |
51 | for prop in [0.1, 0.5, p]:
52 | self.play(
53 | prop_val.animate.set_value(prop),
54 | UpdateFromFunc(histo, update_histogram, suspend_mobject_updating=False),
55 | run_time = 4.5
56 | )
57 | self.wait(0.5)
58 | self.wait(0.5)
59 |
60 | remember = Tex("Merke dir das...", font_size = 72).shift(2*LEFT + 0.4*DOWN)
61 | self.play(Write(remember))
62 | self.wait(3)
63 |
64 |
65 | class WhatsTheModell(HistoScene):
66 | def construct(self):
67 | self.n = 10
68 | self.p = 0.7
69 |
70 | self.both_result()
71 | self.probability()
72 | self.trail_of_length_10()
73 |
74 | def both_result(self):
75 | coin_scale = 1.5
76 | results = VGroup(*[get_coin(symbol).scale(coin_scale) for symbol in ["Z", "K"]])
77 | results.arrange(RIGHT, buff = 2)
78 | for result in results:
79 | result.save_state()
80 | result.center()
81 |
82 | init_heads = get_coin("K").scale(1.5)
83 |
84 | def random_update_result(mob):
85 | p = random.uniform(0,1)
86 | if p > 0.5:
87 | choice = get_coin("K")
88 | else:
89 | choice = get_coin("Z")
90 | choice.scale(coin_scale)
91 | mob.become(choice)
92 |
93 | self.play(
94 | UpdateFromFunc(init_heads, random_update_result, run_time = 6)
95 | )
96 | self.add(results)
97 | self.remove(init_heads)
98 | self.play(*[Restore(result) for result in results], run_time = 2)
99 |
100 |
101 | myTemplate = TexTemplate()
102 | myTemplate.add_to_preamble(r"\usepackage{pifont}")
103 |
104 | sf_marks = VGroup(*[
105 | Tex(mark, color = tex_color, tex_template = myTemplate, font_size = 120)
106 | for mark, tex_color in zip([CMARK_TEX, XMARK_TEX], [C_COLOR, X_COLOR])
107 | ])
108 | for mark, result in zip(sf_marks, results):
109 | mark.next_to(result, UP, buff = 1)
110 |
111 | self.play(DrawBorderThenFill(sf_marks, lag_ratio = 0.1), run_time = 1.5)
112 | self.play(Swap(*results), run_time = 1.5)
113 | self.wait()
114 |
115 | succ_group = VGroup(sf_marks[0], results[1])
116 | succ_group.generate_target()
117 | succ_group.target.arrange(RIGHT, buff = 0.5).to_edge(UP).shift(4*RIGHT)
118 |
119 | fail_group = VGroup(results[0], sf_marks[1])
120 | fail_group.generate_target()
121 | fail_group.target.arrange(RIGHT, buff = 0.5).to_edge(UP).shift(4*LEFT)
122 |
123 | self.play(
124 | *[MoveToTarget(group) for group in [succ_group, fail_group]],
125 | run_time = 1.5
126 | )
127 |
128 | self.succ_group, self.fail_group = succ_group, fail_group
129 |
130 | def probability(self):
131 | prob = ValueTracker(0.5)
132 | succ = DecimalNumber(prob.get_value())\
133 | .scale(1.5)\
134 | .set_color(C_COLOR)\
135 | .next_to(self.succ_group, DOWN, buff = 0.5)\
136 | .add_updater(lambda dec: dec.set_value(prob.get_value()))
137 | fail = DecimalNumber(1 - prob.get_value())\
138 | .scale(1.5)\
139 | .set_color(X_COLOR)\
140 | .next_to(self.fail_group, DOWN, buff = 0.5)\
141 | .add_updater(lambda dec: dec.set_value(1 - prob.get_value()))
142 |
143 | self.play(*[FadeIn(sf, shift = DOWN) for sf in [succ, fail]])
144 | self.wait()
145 | self.play(prob.animate.set_value(self.p), run_time = 3)
146 | self.play(Circumscribe(succ, color = C_COLOR, stroke_width = 6, run_time = 2))
147 | self.wait()
148 |
149 | bools = 7 * [True] + 3 * [False]
150 | grid = get_coin_grid(bools, height=6)
151 | grid.arrange(RIGHT).set(height = 1).shift(DOWN)
152 |
153 | random.shuffle(bools)
154 | grid_shuffle = get_coin_grid(bools, height=6)
155 | grid_shuffle.arrange(RIGHT).set(height = 1).shift(DOWN)
156 | self.play(LaggedStartMap(FadeIn, grid_shuffle, shift = 0.5*UP, lag_ratio = 0.1), run_time = 1.5)
157 | self.wait()
158 |
159 | self.play(ReplacementTransform(grid_shuffle, grid))
160 | self.wait()
161 |
162 |
163 | bools = 70 * [True] + 30 * [False]
164 | new_grid = get_coin_grid(bools, height = 5)
165 | new_grid.to_edge(DOWN)
166 |
167 | random.shuffle(bools)
168 | new_grid_shuffle = get_coin_grid(bools, height = 5)
169 | new_grid_shuffle.to_edge(DOWN)
170 |
171 | self.play(ReplacementTransform(grid, new_grid_shuffle))
172 | self.wait()
173 |
174 | self.play(TransformMatchingShapes(new_grid_shuffle, new_grid))
175 | self.wait(2)
176 |
177 | self.play(
178 | AnimationGroup(
179 | FadeOut(new_grid[:70], shift = 5*UP),
180 | FadeOut(new_grid[70:], shift = 3*DOWN),
181 | lag_ratio = 0.1
182 | ),
183 | run_time = 2
184 | )
185 | self.wait()
186 |
187 | self.play(
188 | AnimationGroup(
189 | *[dec.animate.next_to(group, direction, buff = 0.35) for dec, group, direction
190 | in zip([succ, fail],[self.succ_group, self.fail_group],[LEFT, RIGHT])],
191 | lag_ratio = 0.1
192 | ),
193 | run_time = 2.5
194 | )
195 | self.wait()
196 |
197 | def trail_of_length_10(self):
198 | # Create 20 DecimalNumbers
199 | numbers = VGroup()
200 | for i in range(self.n):
201 | num = DecimalNumber()
202 | numbers.add(num)
203 |
204 | # set their value
205 | def randomize_numbers(numbers):
206 | for num in numbers:
207 | value = random.uniform(0,1)
208 | num.set_value(value)
209 | if value < 0.3:
210 | num.set_color(RED)
211 | else:
212 | num.set_color(GREEN)
213 |
214 | numbers.set(height = 0.2)
215 | numbers.arrange(RIGHT, buff = 0.35)
216 | numbers.to_edge(UP, buff = 2.75)
217 |
218 | # get results (K or Z) depending on that number
219 | def get_results(numbers):
220 | results = VGroup()
221 | for num in numbers:
222 | if num.get_value() < 0.3:
223 | result = Tex("Z").set_color(RED)
224 | else:
225 | result = Tex("K").set_color(BLUE)
226 |
227 | result.set(height = 0.4)
228 | result.next_to(num, UP)
229 | results.add(result)
230 | return results
231 |
232 | succ_nums = VGroup()
233 | grid = VGroup()
234 | for x in range(10):
235 | succ_var = 0
236 | self.play(
237 | numbers.animate.shift(0.5*DOWN),
238 | UpdateFromFunc(numbers, randomize_numbers)
239 | )
240 |
241 | for num in numbers:
242 | if num.get_value() > 0.3:
243 | succ_var += 1
244 |
245 | results = get_results(numbers)
246 | grid.add(*results)
247 | self.play(LaggedStartMap(FadeIn, results, shift = 0.2*DOWN))
248 |
249 | succ_num = Integer()\
250 | .set_value(succ_var)\
251 | .next_to(results, RIGHT, buff = 0.5)\
252 | .align_to(self.succ_group, RIGHT)\
253 | .shift(0.6*LEFT)\
254 | .set_color(YELLOW_E)
255 | succ_num.value = succ_var
256 |
257 | succ_nums.add(succ_num)
258 |
259 | self.play(Write(succ_num))
260 |
261 | self.wait(2)
262 |
263 | # FadeOut numbers, results & arrange succ_nums
264 | succ_nums.generate_target()
265 | succ_nums.target.scale(1.75).arrange(RIGHT, buff = 0.75).center()
266 | self.play(
267 | LaggedStartMap(ShrinkToCenter, grid, lag_ratio = 0.01, run_time = 2),
268 | LaggedStartMap(ShrinkToCenter, numbers, lag_ratio = 0.1, run_time = 2),
269 | MoveToTarget(succ_nums, lag_ratio = 0.05, rate_func = squish_rate_func(smooth, 0.3, 1), run_time = 3)
270 | )
271 | self.wait()
272 |
273 | # clarify meaning again
274 | def get_arrows_from_value(value):
275 | value_group = VGroup(*[number for number in succ_nums if number.value == value])
276 | arrows = VGroup()
277 | for mob in value_group:
278 | arrow = Arrow(ORIGIN, 1.5*UP)
279 | arrow.next_to(mob, DOWN)
280 | arrows.add(arrow)
281 |
282 | return arrows
283 |
284 | arrows_6 = get_arrows_from_value(6)
285 | arrows_7 = get_arrows_from_value(7)
286 | self.play(FadeIn(arrows_6, shift = UP, lag_ratio = 0.1))
287 | self.wait()
288 | self.play(
289 | FadeOut(arrows_6, shift = DOWN, lag_ratio = 0.1),
290 | FadeIn(arrows_7, shift = UP, lag_ratio = 0.1)
291 | )
292 | self.wait()
293 | self.play(FadeOut(arrows_7))
294 | self.wait()
295 |
296 | # prepare for histogram
297 | histo_kwargs = {
298 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
299 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
300 | "include_h_lines": True, "bar_colors": [RED, GREEN, BLUE, YELLOW]
301 | }
302 | histo = self.get_histogram(self.n, self.p, **histo_kwargs)
303 | histo.center().to_edge(DOWN)
304 |
305 | for num in succ_nums:
306 | value = num.value
307 | num.generate_target()
308 | target_mob = histo.axes.x_labels[value]
309 | num.target.match_height(target_mob).match_color(target_mob).move_to(target_mob)
310 | self.play(
311 | LaggedStartMap(MoveToTarget, succ_nums, lag_ratio = 0.1), run_time = 5
312 | )
313 | self.wait()
314 | self.play(
315 | Create(histo.axes.x_axis),
316 | ShowIncreasingSubsets(histo.axes.x_labels),
317 | run_time = 5
318 | )
319 | self.remove(succ_nums)
320 | self.wait(2)
321 |
322 | self.play(
323 | Create(histo.axes.y_axis),
324 | Create(histo.axes.h_lines),
325 | run_time = 3
326 | )
327 | self.wait(3)
328 |
329 |
330 | # Brian Links:
331 | # https://github.com/brianamedee/3B1B-Animated-Tutorials/blob/main/3b1bProbability.py
332 | # https://www.youtube.com/watch?v=t_wBGoO8TA8&t=467s
333 |
334 | # 3Blue1Brown
335 | # https://youtu.be/8idr1WZ1A7Q?t=366
336 |
337 |
338 | class SimulateHistogram(HistoScene):
339 | def construct(self):
340 | self.n = 10
341 | self.p = 0.7
342 | histo_kwargs = {
343 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
344 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
345 | "include_h_lines": True, "bar_colors": [RED, GREEN, BLUE, YELLOW]
346 | }
347 | histo = self.get_histogram(self.n, self.p, **histo_kwargs)
348 | histo.center().to_edge(DOWN)
349 |
350 |
351 | def get_bars(histogram, data):
352 | portions = np.array(data).astype(float)
353 | total = portions.sum()
354 | if total == 0:
355 | portions[:] = 0
356 | else:
357 | portions /= total
358 |
359 | bars = VGroup()
360 |
361 | for x, prop in enumerate(portions):
362 | p1 = VectorizedPoint().move_to(histogram[0].c2p(x, 0))
363 | p2 = VectorizedPoint().move_to(histogram[0].c2p(x + 1, 0))
364 | p3 = VectorizedPoint().move_to(histogram[0].c2p(x + 1, prop))
365 | p4 = VectorizedPoint().move_to(histogram[0].c2p(x, prop))
366 | points = VGroup(p1, p2, p3, p4)
367 | bar = Rectangle().replace(points, stretch=True)
368 | bar.set_stroke(width = 1)
369 | bars.add(bar)
370 | # bars.set_style(fill_color = [*histo_kwargs["bar_colors"]], fill_opacity = 0.6, stroke_color = WHITE)
371 | return bars
372 |
373 |
374 | data = np.zeros(11) # Possible outcomes as an array
375 | row = get_random_row(p = self.p, n = self.n).shift(0.25*DOWN)
376 | bars = get_bars(histogram=histo, data=data)
377 |
378 | text_counter = Tex("Anzahl: ", font_size = 60).shift(3.5*LEFT + UP)
379 | counter = always_redraw(
380 | lambda: Integer()\
381 | .scale(1.25)\
382 | .set_value(sum(data))\
383 | .next_to(text_counter, RIGHT, buff=0.3, aligned_edge = UP)
384 | )
385 | arrow = Line(ORIGIN, DOWN * 0.8).add_tip().set_color(PINK)
386 |
387 | # Update function
388 | def update(dummy, n_added_data_points=0):
389 | new_row = get_random_row().shift(0.25*DOWN)
390 | row.become(new_row)
391 |
392 | count = sum([m.positive for m in new_row.nums])
393 | data[count] += 1
394 | if n_added_data_points:
395 | values = np.random.random((n_added_data_points, 10))
396 | counts = (values > 0.3).sum(1) # changed from < 0.2
397 | for i in range(len(data)):
398 | data[i] += (counts == i).sum()
399 |
400 | bars.become(get_bars(histogram=histo, data=data))
401 |
402 | arrow.next_to(bars[count], UP, buff=0.1)
403 |
404 | # bars[2].set_style(
405 | # fill_color = [*histo_kwargs["bar_colors"]],
406 | # fill_opacity = 0.6,
407 | # stroke_color = WHITE,
408 | # )
409 |
410 | self.add(histo.axes)
411 | self.wait()
412 |
413 | self.play(
414 | AnimationGroup(
415 | FadeIn(row, shift = DOWN, lag_ratio = 0.1),
416 | lag_ratio = 0.1
417 | ),
418 | run_time = 3
419 | )
420 | self.wait()
421 | self.play(
422 | AnimationGroup(
423 | Write(text_counter),
424 | FadeIn(counter, shift = UP),
425 | lag_ratio = 0.1
426 | ),
427 | run_time = 2
428 | )
429 | self.wait()
430 | self.play(Circumscribe(counter, color = YELLOW_D, time_width = 0.75, run_time = 3))
431 | self.wait()
432 | self.add(bars, arrow)
433 |
434 |
435 | group = VGroup(row, bars, arrow)
436 | self.play(UpdateFromFunc(group, update), run_time = 2)
437 | self.wait(2)
438 |
439 |
440 | self.play(
441 | LaggedStart(*[mark.animate(rate_func = there_and_back).shift(0.5*DOWN) for mark in row.syms], lag_ratio = 0.1),
442 | run_time = 3
443 | )
444 | self.play(Circumscribe(arrow, color = YELLOW_D, time_width = 0.75, run_time = 3))
445 | self.wait()
446 |
447 |
448 | self.play(UpdateFromFunc(group, lambda m: update(m, 10)), run_time = 2)
449 | self.wait(2)
450 | self.play(UpdateFromFunc(group, lambda m: update(m, 100)), run_time = 2)
451 | self.play(UpdateFromFunc(group, lambda m: update(m, 500)), run_time = 2)
452 | self.play(UpdateFromFunc(group, lambda m: update(m, 1000)), run_time = 2)
453 | self.play(UpdateFromFunc(group, lambda m: update(m, 1000)), run_time = 2)
454 | self.wait(3)
455 |
456 |
457 | histo_0 = self.get_histogram(self.n, self.p, zeros = True, **histo_kwargs)
458 | histo_0.center().to_edge(DOWN)
459 |
460 | counter.clear_updaters()
461 | self.play(
462 | FadeOut(VGroup(row, text_counter, counter, arrow)),
463 | ReplacementTransform(histo_0.bars, histo.bars, lag_ratio = 0.1),
464 | run_time = 5
465 | )
466 | self.remove(bars)
467 | self.wait(3)
468 |
469 |
470 | class SimulationAfterEffects(HistoScene, MovingCameraScene):
471 | def construct(self):
472 | self.n = 10
473 | self.p = 0.7
474 | histo_kwargs = {
475 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
476 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
477 | "include_h_lines": True, "bar_colors": [RED, GREEN, BLUE, YELLOW]
478 | }
479 | histo = self.histo = self.get_histogram(self.n, self.p, **histo_kwargs)
480 | histo.center().to_edge(DOWN)
481 |
482 | self.add(histo)
483 | self.wait(2)
484 |
485 | self.connect_to_formula()
486 | self.formula_to_bar()
487 | self.probs_sum_up_to_1()
488 | self.changing_parameters()
489 |
490 |
491 | def connect_to_formula(self):
492 | n, p, histo = self.n, self.p, self.histo
493 |
494 | k = self.k = 7
495 | binom_data = VGroup(*[MathTex(*tex) for tex in (["n", "=", str(n)], ["p", "=", str(p)])])\
496 | .arrange_submobjects(RIGHT, aligned_edge = UP)\
497 | .scale(0.6)\
498 | .to_corner(UL, buff = 0.1)\
499 | .save_state()\
500 | .scale(2.5)\
501 | .center()\
502 | .shift(LEFT + UP)
503 |
504 | formula = get_binom_formula(n, p, k)
505 | formula.scale(1.25)
506 | formula.to_edge(UP)
507 | formula.shift(1.1*LEFT)
508 |
509 | self.play(ShowIncreasingSubsets(binom_data), run_time = 2)
510 | self.wait()
511 | self.play(Restore(binom_data))
512 | self.wait(0.5)
513 |
514 | self.play(Write(formula[:7]), run_time = 1)
515 | self.wait()
516 |
517 | self.play(FocusOn(histo.axes.x_labels[k], run_time = 1))
518 | self.play(Circumscribe(histo.axes.x_labels[k], color = C_COLOR))
519 | self.wait()
520 |
521 | self.play(Write(formula[7:11]))
522 | self.wait()
523 | self.play(Write(formula[11:14]))
524 | self.wait()
525 | self.play(Write(formula[14:]))
526 | self.wait()
527 |
528 | self.play(Circumscribe(formula, color = BLUE, time_width = 0.75, stroke_width = 2, run_time = 3))
529 | self.wait()
530 |
531 | self.formula, self.binom_data = formula, binom_data
532 |
533 | def formula_to_bar(self):
534 | k, n, p, histo = self.k, self.n, self.p, self.histo
535 | formula = self.formula
536 |
537 | result = get_binom_result(n, p, k)
538 | result_tex = MathTex("\\approx", str(result)).scale(1.25).next_to(formula, RIGHT, buff = 0.1)
539 |
540 | line = DashedLine(dash_length = 0.01, stroke_width = 1, stroke_color = WHITE)
541 | line.match_width(histo.axes.x_axis)
542 | line.next_to(histo.axes.c2p(0, result), buff = 0)
543 |
544 | self.play(FadeIn(result_tex, shift = 2*LEFT), run_time = 2)
545 | self.play(Circumscribe(result_tex, color = histo.bars[k].get_color(), run_time = 2))
546 | self.wait()
547 |
548 | dot = Dot(point = histo.axes.c2p(0,0), color = histo.bars[k].get_color())
549 | self.play(FocusOn(dot))
550 | self.play(dot.animate.move_to(histo.axes.c2p(0, result)), run_time = 2)
551 | self.play(
552 | Create(line),
553 | dot.animate.move_to(histo.axes.c2p(n + 1, result)),
554 | rate_func = smooth, run_time = 2
555 | )
556 | self.highlight_single_bar(histo, k, run_time = 2)
557 | self.play(ApplyWave(histo.bars[k], run_time = 2))
558 | self.play(ShrinkToCenter(dot))
559 | self.wait()
560 |
561 |
562 | for k in [10, 6, 3]:
563 | new_formula = get_binom_formula(n, p, k)\
564 | .scale(1.25)\
565 | .to_edge(UP)\
566 | .shift(1.1*LEFT)
567 | self.play(Transform(formula, new_formula))
568 | self.wait(0.5)
569 |
570 | new_result = round(scipy.stats.binom.pmf(k,n,p), 4)
571 | new_tex = MathTex("\\approx", str(new_result)).scale(1.25).next_to(formula, RIGHT, buff = 0.1)
572 | self.play(Transform(result_tex, new_tex))
573 | self.wait(0.5)
574 |
575 | new_line = DashedLine(dash_length = 0.01, stroke_width = 1, stroke_color = WHITE)
576 | new_line.match_width(histo.axes.x_axis)
577 | new_line.next_to(histo.axes.c2p(0, new_result), buff = 0)
578 |
579 | self.highlight_single_bar(histo, k, run_time = 1.5)
580 | self.play(Transform(line, new_line))
581 | self.wait()
582 |
583 | self.highlight_group_of_bars(histo, 0, 10, run_time = 3)
584 | self.play(
585 | FadeOut(line),
586 | FadeOut(formula),
587 | FadeOut(result_tex),
588 | FadeOut(self.binom_data)
589 | )
590 | self.wait()
591 |
592 |
593 | formulas = VGroup(*[MathTex("P", "(", "X", "=", str(num), ")") for num in range(11)])
594 | formulas.rotate(90*DEGREES)
595 |
596 | for form, bar in zip(formulas, histo.bars):
597 | form[-2].set_color(C_COLOR)
598 | form.add_background_rectangle()
599 | form.next_to(bar.get_top(), UP, buff = 0.15)
600 |
601 | labels = histo.axes.x_labels.copy()
602 | for label, form in zip(labels, formulas):
603 | label.generate_target()
604 | label.target.rotate(90*DEGREES).match_height(form[-2]).move_to(form[-2]).set_color(C_COLOR)
605 |
606 | self.play(
607 | AnimationGroup(
608 | LaggedStartMap(MoveToTarget, labels, lag_ratio = 0.1),
609 | LaggedStartMap(FadeIn, formulas, lag_ratio = 0.1),
610 | lag_ratio = 0.3
611 | ),
612 | run_time = 4
613 | )
614 | self.remove(*labels)
615 | self.wait()
616 |
617 | self.play(
618 | LaggedStart(*[Indicate(form[1:], color = RED) for form in formulas], lag_ratio = 0.1),
619 | run_time = 3
620 | )
621 | self.wait()
622 |
623 | self.formulas = formulas
624 |
625 | def probs_sum_up_to_1(self):
626 | histo, formulas = self.histo, self.formulas
627 |
628 | group = VGroup()
629 | formulas.generate_target()
630 | formulas.target.rotate(-90*DEGREES).arrange_submobjects(DOWN, buff = 0.15, aligned_edge = RIGHT).to_edge(LEFT)
631 |
632 | equals = VGroup()
633 | for form in formulas.target: # added .target
634 | equal = MathTex("=")
635 | equal.next_to(form, RIGHT, buff = 0.5)
636 | equals.add(equal)
637 |
638 | datas = np.array([round(scipy.stats.binom.pmf(x, 10, 0.7), 4) for x in range(0, 10 + 1)])
639 | results = VGroup()
640 | for data, equal in zip(datas, equals):
641 | result = MathTex(str(data))
642 | result.next_to(equal, RIGHT, buff = 0.5)
643 | results.add(result)
644 |
645 | result0 = MathTex("0.0000").move_to(results[0], aligned_edge=LEFT)
646 | result3 = MathTex("0.0090").move_to(results[3], aligned_edge=LEFT)
647 | results[0] = result0
648 | results[3] = result3
649 |
650 | braces = VGroup()
651 | for result in results:
652 | brace = Brace(VGroup(results[0], result), RIGHT, buff = 0.5, color = GREY)
653 | braces.add(brace)
654 |
655 | cum_datas = np.array([round(scipy.stats.binom.cdf(x, 10, 0.7), 4) for x in range(0, 10 + 1)])
656 | cum_results = VGroup()
657 | for brace, data in zip(braces, cum_datas):
658 | cum = MathTex(str(data), font_size = 60, color = YELLOW)
659 | cum.next_to(brace, RIGHT, buff = 0.5)
660 | cum_results.add(cum)
661 |
662 | # Show binom probability results
663 | self.play(
664 | FadeOut(histo),
665 | MoveToTarget(formulas),
666 | AnimationGroup(
667 | LaggedStartMap(FadeIn, equals, shift = LEFT, lag_ratio = 0.1),
668 | LaggedStartMap(FadeIn, results, shift = LEFT, lag_ratio = 0.1),
669 | lag_ratio = 0.3
670 | ),
671 | run_time = 3
672 | )
673 | self.wait()
674 |
675 | cum_brace = braces[0]
676 | cum_result = cum_results[0]
677 | self.play(
678 | Create(cum_brace),
679 | Write(cum_result)
680 | )
681 | self.wait()
682 |
683 | # Add prob up to 1
684 | for k in range(1, len(braces)):
685 | self.play(
686 | Transform(cum_brace, braces[k]),
687 | Transform(cum_result, cum_results[k]),
688 | run_time = 0.75
689 | )
690 | self.wait(0.25)
691 |
692 | # highlight 1
693 | self.play(Circumscribe(cum_result, color = YELLOW_D, run_time = 3))
694 | self.wait()
695 |
696 |
697 | #
698 | group.add(formulas, equals, results, cum_brace, cum_result)
699 |
700 | self.play(
701 | group.animate.scale(0.75).shift(RIGHT + UP),
702 | FadeIn(self.histo)
703 | )
704 |
705 | histo_one_kwargs = {
706 | "width": config["frame_width"] - 2, "height": 10/3*(config["frame_height"] - 3.25),
707 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 1, "y_tick_num": 10,
708 | "include_h_lines": True, "bar_colors": [RED, GREEN, BLUE, YELLOW]
709 | }
710 | histo_one = self.get_histogram(10, 0.7, **histo_one_kwargs)
711 | histo_one.center().to_edge(DOWN)
712 |
713 | bars = self.histo.bars
714 | bars.save_state()
715 | bars.generate_target()
716 | bars.target.arrange_submobjects(DOWN, buff = 0).next_to(histo.axes.c2p(7.5,0), UP, buff = 0)
717 |
718 | self.play(
719 | MoveToTarget(bars, lag_ratio = 0.1),
720 | run_time = 3
721 | )
722 |
723 | self.camera.frame.save_state()
724 | self.play(
725 | self.camera.frame.animate.shift(10*UP),
726 | group.animate.shift(9*UP),
727 | FadeIn(histo_one.axes),
728 | run_time = 3
729 | )
730 |
731 | dot = Dot(point = histo_one.axes.c2p(0,1), color = YELLOW_D)
732 | trace = TracedPath(dot.get_center, dissipating_time=0.5, stroke_width = 4, stroke_color = YELLOW_D, stroke_opacity=[1,0])
733 | self.add(dot, trace)
734 | self.play(
735 | Circumscribe(histo_one.axes.y_labels[-1], color = YELLOW_D, run_time = 3),
736 | dot.animate(run_time = 3).move_to(histo_one.axes.c2p(11,1)),
737 | )
738 | trace.clear_updaters()
739 | dot.clear_updaters()
740 | self.play(FadeOut(dot), FadeOut(trace))
741 | self.wait()
742 |
743 |
744 | self.play(
745 | Restore(self.camera.frame),
746 | Restore(bars),
747 | FadeOut(histo_one.axes),
748 | run_time = 4
749 | )
750 | self.remove(*group)
751 | self.wait()
752 |
753 | def changing_parameters(self):
754 | num_line = NumberLine(x_range = [0, 1, 0.25], length = 6, include_numbers=True, decimal_number_config={"num_decimal_places": 2})
755 | num_line.to_edge(UP, buff = 1)
756 |
757 | label = MathTex("p", "=").next_to(num_line, RIGHT, buff = 0.75)
758 |
759 | p_val = ValueTracker(0.7)
760 | p_dec = DecimalNumber(p_val.get_value())\
761 | .next_to(label, RIGHT, aligned_edge=UP)\
762 | .shift(0.1*UP)
763 |
764 | dot = Dot(point = num_line.n2p(p_val.get_value()), color = PINK, radius = 0.1)
765 | dot.set_sheen(-0.3, DR)
766 |
767 | self.play(
768 | Create(num_line, run_time = 2),
769 | Write(label),
770 | Write(p_dec),
771 | FadeIn(dot, shift = DOWN, run_time = 2)
772 | )
773 | self.wait()
774 |
775 | p_dec.add_updater(lambda dec: dec.set_value(p_val.get_value()))
776 | dot.add_updater(lambda d: d.move_to(num_line.n2p(p_val.get_value())))
777 |
778 | histo = self.histo
779 | histo.p_val = p_val
780 | histo.n = self.n
781 | def update_histogram(hist):
782 | new_dist = scipy.stats.binom(hist.n, hist.p_val.get_value())
783 | new_data = np.array([new_dist.pmf(x) for x in range(0, hist.n + 1)])
784 | new_bars = hist.get_bars(new_data)
785 | new_bars.match_style(hist.bars)
786 | hist.bars.become(new_bars)
787 |
788 | for prop in [0.5, 0.1, 0.4, 0.8]:
789 | self.play(
790 | p_val.animate.set_value(prop),
791 | UpdateFromFunc(histo, update_histogram, suspend_mobject_updating=False),
792 | run_time = 4.5
793 | )
794 | self.wait(0.5)
795 | self.wait(3)
796 |
797 |
798 | class NoNeedFor320000Calc(Scene):
799 | def construct(self):
800 | panic = Tex("Keine Panik auf der Titanic")
801 | panic.scale(1.75)
802 | panic.to_corner(UL)
803 |
804 | rescue = Tex("Rettung naht...")
805 | rescue.scale(1.25)
806 | rescue.to_edge(DOWN, buff = 0.5)
807 |
808 | self.play(FadeIn(panic, shift = 5*RIGHT), run_time = 1.5)
809 | self.wait(0.5)
810 |
811 | self.play(FadeIn(rescue, shift = 5*LEFT), run_time = 1.5)
812 | self.wait()
813 |
814 | bernoulli = Tex("Bernoulli", "$-$", "Formel")
815 | bernoulli[0].set_color(BLUE)
816 | bernoulli[-1].set_color(YELLOW_D)
817 | def update(mob):
818 | x = random.uniform(-5,5)
819 | y = random.uniform(-2.5,2.5)
820 |
821 | bernoulli.move_to(x * RIGHT + y * UP)
822 | mob.become(bernoulli)
823 |
824 | self.add(bernoulli)
825 | self.play(
826 | UpdateFromFunc(bernoulli, update),
827 | run_time = 2
828 | )
829 | bernoulli.scale(2)
830 | bernoulli.center()
831 |
832 | brain = SVGMobject(SVG_DIR + "BrainBulb")
833 | brain.next_to(bernoulli, RIGHT)
834 | self.play(Create(brain), run_time = 2)
835 | self.play(Indicate(brain), run_time = 1)
836 | self.wait(2)
837 |
838 |
839 | class Thumbnail(HistoScene):
840 | def construct(self):
841 | total_calc = 319152
842 | n = 10
843 | p = 0.7
844 | histo_kwargs = {
845 | "width": config["frame_width"] - 2, "height": config["frame_height"] - 3.25,
846 | "x_tick_freq": 1, "x_label_freq": 1, "y_max_value": 0.3, "y_tick_num": 3,
847 | "bar_colors": [YELLOW, GREEN, BLUE]
848 | }
849 | histo = self.get_histogram(n, p, **histo_kwargs)
850 | histo.center().to_edge(DOWN)
851 | self.add(histo)
852 |
853 |
854 | calc1 = Tex("$319.152$ ")
855 | calc1.scale(2.5)
856 | calc1.move_to(histo.axes.c2p(2.5, 0.25))
857 | calc1.set_color(RED)
858 |
859 | calc2 = Tex("Wiederholungen?!")
860 | calc2.set(width = calc1.width + 1)
861 | calc2.next_to(calc1, DOWN)
862 | calc2.set_color_by_gradient(RED, WHITE)
863 | calc2.add_background_rectangle()
864 | self.add(calc1, calc2)
865 |
866 |
867 | arrow = ArcBetweenPoints(
868 | calc1.get_corner(UR) + 0.25*RIGHT,
869 | histo.bars[6].get_top() + 0.2*UP,
870 | angle = -90*DEGREES,
871 | stroke_width = 6
872 | )
873 | arrow.set_color([histo.bars[6].get_color(), RED])
874 | arrow.add_tip(tip_length = 0.35)
875 | arrow[-1].set_color(histo.bars[6].get_color())
876 | self.add(arrow)
877 |
878 |
879 | title = Tex("Histogramme")
880 | title.scale(4)
881 | title.set_color_by_gradient(YELLOW_E, GREEN, BLUE)
882 | title.set_stroke(color = WHITE, width = 1)
883 | title.to_edge(UP, buff = 0.2)
884 | self.add(title)
885 |
886 |
887 |
888 |
889 |
890 |
891 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/Blood_Donation.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
88 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/BrainBulb.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
273 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/GummyBear.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
72 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/Jakob_Bernoulli.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visual-x/manim-projects/00d8b9f715212c2de35c9c1f8f894b0823167bdc/2022/Binomial Distribution/SVGs and IMGs/Jakob_Bernoulli.jpg
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/Rabbit.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/clubs.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/diamonds.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/emoji_couple_holding_hands.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
82 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/emoji_couple_holding_hands_ww.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
91 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/emoji_heart_eyes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/emoji_middle_finger.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
25 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/emoji_sunglas.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/hearts.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/open-tafelwerk-tables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visual-x/manim-projects/00d8b9f715212c2de35c9c1f8f894b0823167bdc/2022/Binomial Distribution/SVGs and IMGs/open-tafelwerk-tables.png
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/rose_illustration.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
53 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/smartwatch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/spades.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visual-x/manim-projects/00d8b9f715212c2de35c9c1f8f894b0823167bdc/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_100.png
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_10_20_25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visual-x/manim-projects/00d8b9f715212c2de35c9c1f8f894b0823167bdc/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_10_20_25.png
--------------------------------------------------------------------------------
/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visual-x/manim-projects/00d8b9f715212c2de35c9c1f8f894b0823167bdc/2022/Binomial Distribution/SVGs and IMGs/table_binom_cdf_50.png
--------------------------------------------------------------------------------
/2022/TrigFunc-Parameter-d.py:
--------------------------------------------------------------------------------
1 | from manim import *
2 |
3 | XMARK_TEX = "\\ding{55}"
4 |
5 | def p2c(y_value, min, max, colors):
6 | alpha = inverse_interpolate(min, max, y_value)
7 | index, sub_alpha = integer_interpolate(0, len(colors) - 1, alpha)
8 |
9 | return interpolate_color(colors[index], colors[index + 1], sub_alpha)
10 |
11 |
12 | class Intro(Scene):
13 | def construct(self):
14 |
15 | scr = VGroup(*[ScreenRectangle(height = 3, stroke_width = 3, stroke_color = GREY) for x in range(4)])
16 | scr.arrange_in_grid(2,2)
17 | scr.to_edge(DOWN, buff = 0.4)
18 |
19 | func = MathTex("f(x)", "=", "a", "\\cdot", "\\sin", "\\big(", "b", "\\cdot", "(", "x", "+", "c", ")","\\big)", "+", "d", font_size = 80)
20 | func.to_edge(UP, buff = 0.3)
21 | func[2].set_color(RED)
22 | func[6].set_color(BLUE)
23 | func[11].set_color(YELLOW)
24 | func[-1].set_color(GREEN)
25 |
26 | self.play(
27 | Create(scr[:-1], lag_ratio = 0.2, run_time = 3),
28 | Write(func, run_time = 1),
29 | )
30 | self.wait()
31 |
32 | abcd = VGroup(*[func[index].copy() for index in [2, 6, 11, -1]])
33 | for alph, rect, direc in zip(abcd, scr, [LEFT, RIGHT, LEFT, RIGHT]):
34 | alph.generate_target()
35 | alph.target.next_to(rect, direc)
36 |
37 | self.play(
38 | LaggedStart(*[MoveToTarget(alph) for alph in abcd[:-1]], lag_ratio = 0.2),
39 | run_time = 3
40 | )
41 | self.wait()
42 |
43 |
44 | sur = SurroundingRectangle(abcd[-1], color = GREEN)
45 | self.play(Create(sur), run_time = 2)
46 | self.wait(0.5)
47 | self.play(FadeOut(sur, scale = 2))
48 | self.wait()
49 |
50 |
51 | self.play(
52 | MoveToTarget(abcd[-1]),
53 | Create(scr[-1]),
54 | run_time = 2
55 | )
56 | self.wait(3)
57 |
58 |
59 | group = Group(*self.mobjects)
60 | self.play(FadeOut(group, scale = 5), run_time = 1.5)
61 | self.wait()
62 |
63 |
64 | class TableToGraph(Scene):
65 | def construct(self):
66 | self.x_values = np.linspace(0, 2*np.pi, 9)
67 | self.sin_values = [round(np.sin(x), 2) for x in self.x_values]
68 | self.sin_values[-1] = 0.00
69 | self.sind_values = [x + 2 for x in self.sin_values]
70 |
71 | axes = self.axes = NumberPlane(
72 | x_range = [0, 9*PI/4, 1], y_range = [-4, 4, PI/4],
73 | x_length = config["frame_width"] * 2/5, y_length = 7,
74 | background_line_style={"stroke_color": BLUE_E, "stroke_width": 1}
75 | )
76 | axes.to_edge(RIGHT)
77 | self.origin = axes.c2p(0,0)
78 | axes.x_axis.add_tip(tip_length = 0.25)
79 | axes.y_axis.add_tip(tip_length = 0.25)
80 |
81 | self.x_axis_label = MathTex("x", color = GREY, font_size = 24).next_to(axes.x_axis, UP, buff = 0.1, aligned_edge=RIGHT)
82 | self.y_axis_label = MathTex("y", color = GREY, font_size = 24).next_to(axes.y_axis, UP, buff = 0.1)
83 |
84 | self.x_axis_numbers = self.get_x_axis_numbers()
85 | self.y_axis_numbers = self.get_y_axis_numbers()
86 |
87 | self.colors = [PINK, YELLOW, GREEN, RED, BLUE]
88 |
89 | self.myTemplate = TexTemplate()
90 | self.myTemplate.add_to_preamble(r"\usepackage{pifont}")
91 |
92 | self.build_table_and_sin_graph()
93 | self.get_idea_for_new_parameter()
94 | self.explain_parameter()
95 |
96 |
97 | def build_table_and_sin_graph(self):
98 | x_values, sin_values, sind_values = self.x_values, self.sin_values, self.sind_values
99 | axes = self.axes
100 |
101 | x_strings = [
102 | "0", "\\frac{1}{4}\\pi", "\\frac{1}{2}\\pi", "\\frac{3}{4}\\pi", "\\pi",
103 | "\\frac{5}{4}\\pi", "\\frac{3}{2}\\pi", "\\frac{7}{4}\\pi", "2\\pi"
104 | ]
105 |
106 | x_texs = VGroup(*[MathTex(x_str, font_size = 36) for x_str in x_strings])
107 | for index in [1,2,3,5,6,7]:
108 | x_texs[index][0][:3].scale(0.65)
109 | sin_texs = VGroup(*[MathTex(str(sin), font_size = 36) for sin in sin_values])
110 | sind_texs = VGroup(*[MathTex(str(sind), font_size = 36) for sind in sind_values])
111 |
112 |
113 | table = VGroup(*x_texs, *sin_texs, *sind_texs)\
114 | .arrange_in_grid(rows = len(x_texs), cols = 3, col_widths=[1, 2, 3], flow_order = "dr")\
115 | .to_edge(LEFT, buff = 1)\
116 | .shift(0.5*DOWN)
117 |
118 |
119 | x_label = MathTex("x", font_size = 40).next_to(table[0], UP, buff = 0.6)
120 | sin_label = MathTex("\\sin", "(x)", font_size = 40).next_to(table[9], UP, buff = 0.5)
121 | sind_label = MathTex("\\sin", "(x)", "+", "2", font_size = 40).next_to(table[18], UP, buff = 0.5)
122 | for label in sin_label, sind_label:
123 | label.set_color_by_tex_to_color_map({"+": YELLOW, "2": YELLOW, "\\sin": RED})
124 |
125 |
126 | self.play(
127 | Write(x_label),
128 | FadeIn(x_texs, shift = 0.5*DOWN, lag_ratio = 0.1),
129 | run_time = 2
130 | )
131 | self.wait()
132 |
133 | # Create sin_values and transform dots_x into dots_sin
134 | dots_axis = VGroup(*[Dot(axes.c2p(x_val, 0), radius = 0.06) for x_val in x_values])
135 | self.play(
136 | LaggedStartMap(
137 | Create, VGroup(axes, self.x_axis_label, self.y_axis_label, self.x_axis_numbers, self.y_axis_numbers),
138 | lag_ratio = 0.2, run_time = 2
139 | ),
140 | AnimationGroup(
141 | *[Transform(tex.copy(), dot) for tex, dot in zip(x_texs, dots_axis)],
142 | lag_ratio = 0.2, run_time = 3
143 | ),
144 | )
145 | self.wait()
146 |
147 | self.play(
148 | FocusOn(sin_label, run_time = 1),
149 | Write(sin_label, rate_func = squish_rate_func(smooth, 0.5, 1), run_time = 2)
150 | )
151 | self.play(AnimationGroup(*[Write(tex) for tex in sin_texs], lag_ratio = 0.2, run_time = 2))
152 | self.wait()
153 |
154 | dots_sin = VGroup(*[Dot(axes.c2p(x_val, sin_val), radius = 0.06, color = RED) for x_val, sin_val in zip(x_values, sin_values)])
155 | dots_sin2 = dots_sin.copy()
156 | graph_sin = axes.get_graph(lambda x: np.sin(x), x_range = [0, 2*np.pi], color = RED)
157 |
158 | self.play(
159 | AnimationGroup(
160 | *[ReplacementTransform(tex.copy(), dot) for tex, dot in zip(sin_texs, dots_sin)],
161 | lag_ratio = 0.2, run_time = 3
162 | ),
163 | )
164 | self.add(dots_sin2)
165 |
166 | self.play(
167 | TransformFromCopy(dots_axis, dots_sin.copy()),
168 | Create(graph_sin),
169 | run_time = 2
170 | )
171 | self.remove(dots_sin2)
172 | self.wait()
173 |
174 |
175 | self.x_texs, self.sin_texs, self.sind_texs = x_texs, sin_texs, sind_texs
176 | self.sin_label, self.sind_label = sin_label, sind_label
177 | self.graph_sin, self.dots_sin = graph_sin, dots_sin
178 |
179 | def get_idea_for_new_parameter(self):
180 | sind_label = self.sind_label
181 |
182 | zero_zero_rect = SurroundingRectangle(VGroup(self.x_texs[0], self.sin_texs[0]), color = RED)
183 | self.play(FadeIn(zero_zero_rect, scale = 5), run_time = 2)
184 | self.wait()
185 |
186 | xmark = Tex(XMARK_TEX, tex_template = self.myTemplate, color = RED)
187 | xmark.move_to(self.origin)
188 |
189 | self.play(ReplacementTransform(zero_zero_rect, xmark))
190 | self.wait()
191 |
192 | trans_group = VGroup(self.graph_sin, self.dots_sin, xmark)
193 | for c in [-PI, 3*PI/2, -PI/2]:
194 | self.play(
195 | trans_group.animate.shift(c * self.axes.x_axis.unit_size * RIGHT), run_time = 1.5
196 | )
197 | self.wait(0.5)
198 | self.wait()
199 |
200 |
201 | trans_group2 = trans_group.copy().set_color(BLUE)
202 | self.add(trans_group2)
203 | self.bring_to_front(trans_group)
204 | for d in [1, -3, 4]:
205 | self.play(
206 | trans_group2.animate.shift(d * self.axes.y_axis.unit_size * UP), run_time = 1.5
207 | )
208 | self.wait(0.5)
209 | self.wait()
210 |
211 | def explain_parameter(self):
212 | sin_texs = self.sin_texs
213 | dots_sind = self.dots_sind = VGroup(*[
214 | Dot(self.axes.c2p(x_val, sind_val), radius = 0.06, color = BLUE)
215 | for x_val, sind_val in zip(self.x_values, self.sind_values)
216 | ])
217 |
218 |
219 |
220 | graph_arrows = self.get_graph_arrows()
221 | table_arrows = self.table_arrows = self.get_table_arrows()
222 | multiplicators = self.get_multiplicators(number = 2)
223 |
224 |
225 | sur_rect_input = SurroundingRectangle(sin_texs[2])
226 | self.play(Flash(self.dots_sin[2]), run_time = 2)
227 | self.play(Create(sur_rect_input), run_time = 1.5)
228 | self.wait()
229 |
230 | self.play(GrowFromEdge(graph_arrows[2], DOWN), run_time = 2)
231 | self.play(Flash(dots_sind[2]), run_time = 2)
232 | self.wait()
233 |
234 | sur_rect_output = SurroundingRectangle(self.sind_texs[2])
235 | self.play(ReplacementTransform(sur_rect_input, sur_rect_output, path_arc = np.pi/3), run_time = 1)
236 | self.play(Write(self.sind_texs[2]))
237 | self.wait()
238 |
239 | self.play(
240 | GrowFromEdge(table_arrows[2], LEFT, run_time = 2),
241 | Write(multiplicators[2]),
242 | Uncreate(sur_rect_output)
243 | )
244 | self.wait()
245 |
246 |
247 | # Adding all other arrows and multiplicators
248 | self.play(
249 | AnimationGroup(
250 | *[GrowFromEdge(graph_arrows[index], DOWN) for index in range(len(graph_arrows)) if index != 2],
251 | *[GrowFromEdge(table_arrows[index], LEFT) for index in range(len(graph_arrows)) if index != 2],
252 | *[Write(multiplicators[index]) for index in range(len(graph_arrows)) if index != 2],
253 | *[FadeIn(self.sind_texs[index]) for index in range(len(graph_arrows)) if index != 2],
254 | lag_ratio = 0.1
255 | ),
256 | run_time = 8
257 | )
258 | self.wait()
259 |
260 |
261 | # Write equation
262 | self.play(
263 | AnimationGroup(
264 | *[Indicate(number, color = YELLOW, scale_factor = 1.5) for number in multiplicators],
265 | lag_ratio = 0.1
266 | ),
267 | run_time = 3
268 | )
269 |
270 | self.play(
271 | TransformFromCopy(self.sin_label[:2], self.sind_label[:2], path_arc = np.pi/3),
272 | run_time = 2
273 | )
274 | self.play(FadeIn(self.sind_label[2:], shift = 2*LEFT), run_time = 2)
275 | self.play(Circumscribe(self.sind_label, color = BLUE, fade_out=True, run_time = 3))
276 | self.wait(3)
277 |
278 |
279 | # functions
280 | def get_x_axis_numbers(self):
281 | x_axis_nums = [np.pi/2, np.pi, 3/2*np.pi, 2*np.pi]
282 | x_axis_coords = VGroup(*[
283 | MathTex(tex, color = LIGHT_GREY, font_size = 24)\
284 | .add_background_rectangle()\
285 | .next_to(self.axes.c2p(num, 0), DOWN)
286 | for tex, num in zip(
287 | ["\\pi/2", "\\pi", "3\\pi/2", "2\\pi"],
288 | x_axis_nums
289 | )
290 | ])
291 | return x_axis_coords
292 |
293 | def get_y_axis_numbers(self):
294 | y_axis_nums = list(range(-3,4))
295 | y_axis_coords = VGroup(*[
296 | MathTex(tex, color = LIGHT_GREY, font_size = 24).next_to(self.axes.y_axis.n2p(num), LEFT)
297 | for tex, num in zip(
298 | [-3,-2,-1,0,1,2,3],
299 | y_axis_nums
300 | )
301 | ])
302 | return y_axis_coords
303 |
304 | def get_graph_arrows(self):
305 |
306 | graph_arrows = VGroup(*[
307 | Line(start.get_center(), end.get_center(), buff = 0).set_color([RED, BLUE])
308 | for start, end in zip(self.dots_sin, self.dots_sind)
309 | ])
310 | for line in graph_arrows:
311 | line.add_tip(tip_length = 0.2) # adding a tip
312 | line[1].set_color(BLUE) # color the tip
313 |
314 | return graph_arrows
315 |
316 | def get_table_arrows(self):
317 | table_arrows = VGroup(*[
318 | Line(ORIGIN, RIGHT, buff = 0).set_color([BLUE, RED])
319 | for _ in range(len(self.sin_texs))
320 | ])
321 |
322 | for arrow, tex in zip(table_arrows, self.sin_texs):
323 | arrow.add_tip(tip_length = 0.2)
324 | arrow[1].set_color(BLUE)
325 | arrow.next_to(tex, RIGHT, buff = 0.5)
326 |
327 | table_arrows.shift(0.1*RIGHT)
328 | for arrow in table_arrows[1:]:
329 | arrow.align_to(table_arrows[0], LEFT)
330 |
331 | return table_arrows
332 |
333 | def get_multiplicators(self, number, font_size = 24):
334 | mults = VGroup()
335 | if number > 0:
336 | sign = "+"
337 | else:
338 | sign = "-"
339 | for arrow in self.table_arrows:
340 | mult = MathTex(sign, str(abs(number)), font_size = 24, color = YELLOW)
341 | mult.next_to(arrow, UP, buff = 0)
342 | mults.add(mult)
343 |
344 | return mults
345 |
346 |
347 | class DifferentFunctions(Scene):
348 | def construct(self):
349 | self.axes_kwargs = {
350 | "x_length": 5, "y_length": 5 * 9/16,
351 | "background_line_style": {"stroke_color": BLUE_E, "stroke_width": 1}
352 | }
353 | self.part_buff = 0.75
354 | self.colors = [BLUE, RED, YELLOW, GREEN]
355 | self.d_val = ValueTracker(0)
356 |
357 | self.starting_mobs = VGroup()
358 | self.titles = VGroup()
359 |
360 | self.linear()
361 | self.quadratic()
362 | self.power()
363 | self.trig()
364 | self.play_animations()
365 |
366 | def linear(self):
367 | axes = NumberPlane(x_range = [-4, 4, 4], y_range = [-10, 20, 1], **self.axes_kwargs)
368 | axes.to_corner(UL, buff = self.part_buff)
369 | frame = ScreenRectangle(height = axes.height, color = GREY, stroke_width = 2)
370 | frame.move_to(axes)
371 |
372 | title = Tex("Lineare Funktionen")
373 | title.next_to(frame, UP, buff = 0.1)
374 |
375 | graph1 = axes.get_graph(lambda x: x, x_range = [-4, 4], color = RED)
376 | graph2 = always_redraw(lambda: axes.get_graph(
377 | lambda x: x + self.d_val.get_value(),
378 | x_range = [-4,4],
379 | color = p2c(self.d_val.get_value(), -5, 10, self.colors)
380 | ))
381 |
382 | self.starting_mobs.add(axes, frame, graph2, graph1)
383 | self.titles.add(title)
384 |
385 | def quadratic(self):
386 | axes = NumberPlane(x_range = [-4, 4, 4], y_range = [-10, 20, 1], **self.axes_kwargs)
387 | axes.to_corner(UR, buff = self.part_buff)
388 | frame = ScreenRectangle(height = axes.height, color = GREY, stroke_width = 2)
389 | frame.move_to(axes)
390 |
391 | title = Tex("Quadratische Funktionen")
392 | title.next_to(frame, UP, buff = 0.1)
393 |
394 | graph1 = axes.get_graph(lambda x: 1/2 * x**2, x_range = [-4, 4], color = RED)
395 | graph2 = always_redraw(lambda: axes.get_graph(
396 | lambda x: 1/2 * x**2 + self.d_val.get_value(),
397 | x_range = [-4,4],
398 | color = p2c(self.d_val.get_value(), -5, 10, self.colors)
399 | ))
400 |
401 | self.starting_mobs.add(axes, frame, graph2, graph1)
402 | self.titles.add(title)
403 |
404 | def power(self):
405 | axes = NumberPlane(x_range = [-4, 4, 4], y_range = [-10, 20, 1], **self.axes_kwargs)
406 | axes.to_corner(DL, buff = self.part_buff)
407 | frame = ScreenRectangle(height = axes.height, color = GREY, stroke_width = 2)
408 | frame.move_to(axes)
409 |
410 | title = Tex("Potenzfunktionen")
411 | title.next_to(frame, DOWN, buff = 0.1)
412 |
413 | graph1 = axes.get_graph(lambda x: 3*np.sqrt(x), x_range = [0, 4, 0.05], color = RED)
414 | graph2 = always_redraw(lambda: axes.get_graph(
415 | lambda x: 3*np.sqrt(x) + self.d_val.get_value(),
416 | x_range = [0, 4, 0.05],
417 | color = p2c(self.d_val.get_value(), -5, 10, self.colors)
418 | ))
419 |
420 | self.starting_mobs.add(axes, frame, graph2, graph1)
421 | self.titles.add(title)
422 |
423 | def trig(self):
424 | axes = NumberPlane(x_range = [-4, 4, 4], y_range = [-10, 20, 1], **self.axes_kwargs)
425 | axes.to_corner(DR, buff = self.part_buff)
426 | frame = ScreenRectangle(height = axes.height, color = GREY, stroke_width = 2)
427 | frame.move_to(axes)
428 |
429 | title = Tex("Trigonometr. Funktionen")
430 | title.next_to(frame, DOWN, buff = 0.1)
431 |
432 | graph1 = axes.get_graph(lambda x: 5*np.sin(1.75*x), x_range = [-4, 4], color = RED)
433 | graph2 = always_redraw(lambda: axes.get_graph(
434 | lambda x: 5*np.sin(1.75*x) + self.d_val.get_value(),
435 | x_range = [-4,4],
436 | color = p2c(self.d_val.get_value(), -5, 10, self.colors)
437 | ))
438 |
439 | self.starting_mobs.add(axes, frame, graph2, graph1)
440 | self.titles.add(title)
441 |
442 | def play_animations(self):
443 | self.play(Create(self.starting_mobs, lag_ratio = 0.1), run_time = 3)
444 | self.wait()
445 |
446 | self.play(
447 | AnimationGroup(*[Write(title) for title in self.titles], lag_ratio = 0.25),
448 | run_time = 3
449 | )
450 | self.wait()
451 |
452 | eq = MathTex("g(x)", "=", "f(x)", "+", "d", font_size = 90)
453 | eq[0].add_updater(lambda mob: mob.set_color(p2c(self.d_val.get_value(), -5, 10, self.colors)))
454 | eq[3].add_updater(lambda mob: mob.set_color(p2c(self.d_val.get_value(), -5, 10, self.colors)))
455 | eq[4].add_updater(lambda mob: mob.set_color(p2c(self.d_val.get_value(), -5, 10, self.colors)))
456 | eq[2].set_color(RED)
457 | eq.add_background_rectangle(buff = 0.2, stroke_width = 1, stroke_opacity = 0.5)
458 |
459 | self.play(
460 | FadeIn(eq[0]),
461 | Write(eq[1:]),
462 | )
463 | self.wait()
464 |
465 | ds = [10, -5, 12, 5]
466 | for d in ds:
467 | self.play(self.d_val.animate.set_value(d), run_time = 3)
468 | self.wait()
469 |
470 | par_tex = Tex("Parameter ", "$d$")\
471 | .rotate(90*DEGREES)\
472 | .set_fill(opacity = 0)\
473 | .set_stroke(width = 0.75, opacity = 0.75, color = GREY)\
474 | .set(height = 4, color = GREY)\
475 | .move_to(np.array([-1.06481703, 0, 0]))
476 |
477 | d_copy = eq[-1].copy()
478 | self.play(Transform(d_copy, par_tex[-1]), run_time = 2)
479 | self.wait(2)
480 |
481 |
482 | class ParameterInfluence(Scene):
483 | def construct(self):
484 | self.x_min = 0
485 | self.x_max = 2*PI
486 |
487 | self.axes_kwargs = {
488 | "x_range": [self.x_min - 0.25, self.x_max + 0.5, 1], "y_range": [-4.25, 4.25, PI/4],
489 | "x_length": config["frame_width"] * 2/5, "y_length": 7,
490 | "background_line_style": {"stroke_color": GREY_D, "stroke_width": 1}
491 | }
492 | self.axes = NumberPlane(**self.axes_kwargs).to_edge(RIGHT, buff = 1.5)
493 | self.origin = self.axes.c2p(0,0)
494 | self.axes.x_axis.add_tip(tip_length = 0.25)
495 | self.axes.y_axis.add_tip(tip_length = 0.25)
496 |
497 | self.d_val = ValueTracker(0)
498 | self.colors = [PINK, BLUE, RED, YELLOW, GREEN]
499 |
500 |
501 | self.setup_scene()
502 |
503 |
504 | def setup_scene(self):
505 | axes, d_val = self.axes, self.d_val
506 |
507 | x_axis_ticks = self.get_x_axis_ticks([PI/2, PI, 3/2*PI, TAU])
508 | x_axis_numbers = self.get_x_axis_numbers(font_size = 30)
509 | y_axis_ticks = self.get_y_axis_ticks(-4, 4)
510 | y_axis_numbers = self.get_y_axis_numbers(-4, 3, font_size = 30)
511 |
512 | graph_ref = axes.get_graph(lambda x: np.sin(x), x_range = [self.x_min, self.x_max], color = RED, stroke_opacity = 0.5)
513 | graph = always_redraw(lambda: axes.get_graph(
514 | lambda x: np.sin(x) + d_val.get_value(), x_range = [self.x_min, self.x_max],
515 | color = p2c(d_val.get_value(), -3, 3, self.colors)
516 | )
517 | )
518 |
519 | graph_tex = always_redraw(lambda: MathTex("\\sin", "(", "x", ")")\
520 | .add_background_rectangle()\
521 | .next_to(graph.point_from_proportion(1), RIGHT + UP)\
522 | .shift(LEFT)
523 | )
524 | d_graph_dec = always_redraw(lambda: DecimalNumber(d_val.get_value(), num_decimal_places=1, include_sign=True)\
525 | .next_to(graph_tex, RIGHT, buff = 0.1)\
526 | .set_color(p2c(d_val.get_value(), -3, 3, self.colors))
527 | )
528 |
529 | d_line = self.d_line = self.get_d_line(
530 | -4.25, 4.25, x_step = 0.5, line_length = self.axes_kwargs["y_length"],
531 | numbers_to_exclude = [-3.5 + k for k in range(8)]
532 | )
533 | d_dot = self.d_dot = always_redraw(lambda: self.get_d_dot())
534 | d_par_line = always_redraw(lambda: self.get_dot_to_axes_line())
535 |
536 | par_tex = Tex("Parameter ", "$d$")\
537 | .rotate(90*DEGREES)\
538 | .set_fill(opacity = 0)\
539 | .set_stroke(width = 0.75, opacity = 0.75)\
540 | .set(height = 4, color = GREY)\
541 | .move_to(midpoint(d_line.get_center(), axes.y_axis.get_center()))
542 |
543 | brace_up = Brace(Line(d_line.n2p(0), d_line.n2p(+4.25)), LEFT, buff = 0.75)
544 | brace_down = Brace(Line(d_line.n2p(0), d_line.n2p(-4.25)), LEFT, buff = 0.75)
545 |
546 | def update_d_pos(mob):
547 | mob.set_color(p2c(d_val.get_value(), -3, 3, self.colors))
548 | if d_val.get_value() <= 0:
549 | mob.set_color(DARK_GREY)
550 | def update_d_neg(mob):
551 | mob.set_color(p2c(d_val.get_value(), -3, 3, self.colors))
552 | if d_val.get_value() >= 0:
553 | mob.set_color(DARK_GREY)
554 |
555 | brace_up.add_updater(update_d_pos)
556 | brace_down.add_updater(update_d_neg)
557 |
558 | brace_text_up = Tex("Verschiebung\\\\", "nach oben")\
559 | .next_to(brace_up, LEFT)
560 | brace_text_down = Tex("Verschiebung\\\\", "nach unten")\
561 | .next_to(brace_down, LEFT)
562 |
563 | def update_tex_pos(mob):
564 | mob.set_color(WHITE)
565 | if d_val.get_value() <= 0:
566 | mob.set_color(DARK_GREY)
567 | def update_tex_neg(mob):
568 | mob.set_color(WHITE)
569 | if d_val.get_value() >= 0:
570 | mob.set_color(DARK_GREY)
571 |
572 | brace_text_up.add_updater(update_tex_pos)
573 | brace_text_down.add_updater(update_tex_neg)
574 |
575 | # ANIMATIONS
576 | self.add(par_tex[-1])
577 | self.wait(2)
578 |
579 | self.play(
580 | LaggedStartMap(Create, VGroup(axes, x_axis_ticks, x_axis_numbers, y_axis_ticks, y_axis_numbers), lag_ratio = 0.25),
581 | Create(par_tex[:-1]),
582 | FadeIn(d_line, shift = 3*RIGHT, lag_ratio = 0.1),
583 | run_time = 2
584 | )
585 | self.wait()
586 |
587 | self.play(
588 | LaggedStartMap(FadeIn, VGroup(d_par_line, d_dot), shift = 3*RIGHT, lag_ratio = 0.35),
589 | run_time = 3
590 | )
591 | self.play(Create(graph), run_time = 2.5)
592 | self.play(
593 | Create(graph_tex),
594 | FadeIn(d_graph_dec, shift = DOWN)
595 | )
596 | self.add(graph_ref)
597 | self.bring_to_front(graph)
598 | self.wait()
599 |
600 | # d bigger than 0
601 | self.play(d_val.animate.set_value(3), run_time = 4)
602 | self.play(
603 | Create(brace_up),
604 | Write(brace_text_up)
605 | )
606 | self.wait()
607 |
608 | self.play(d_val.animate.set_value(0.5), rate_func = double_smooth, run_time = 3)
609 | self.wait()
610 |
611 | # d smaller than 0
612 | self.play(d_val.animate.set_value(-3), run_time = 3)
613 | self.play(
614 | Create(brace_down),
615 | Write(brace_text_down)
616 | )
617 | self.wait()
618 |
619 | self.play(d_val.animate.set_value(+3), rate_func = linear, run_time = 9)
620 | self.play(d_val.animate.set_value(-3), rate_func = linear, run_time = 9)
621 | self.wait(3)
622 |
623 |
624 | # functions
625 | def get_x_axis_ticks(self, numbers, tick_length = 0.2):
626 | ticks = VGroup()
627 | for num in numbers:
628 | tick = Line(UP, DOWN)\
629 | .set_length(tick_length)\
630 | .move_to(self.axes.c2p(num, 0))
631 | ticks.add(tick)
632 | return ticks
633 |
634 | def get_x_axis_numbers(self, **kwargs):
635 | numbers = [PI/2, PI, 3*PI/2, TAU]
636 | strings = ["\\pi/2", "\\pi", "3\\pi/2", "2\\pi"]
637 |
638 | axis_numbers = VGroup()
639 | for num, string in zip(numbers, strings):
640 | tex = MathTex(string, color = GREY, **kwargs)
641 | tex.next_to(self.axes.c2p(num, 0), DOWN)
642 | axis_numbers.add(tex)
643 | return axis_numbers
644 |
645 | def get_y_axis_ticks(self, start, end, tick_length = 0.2):
646 | ticks = VGroup()
647 | for y in range(start, end + 1):
648 | tick = Line(LEFT, RIGHT)\
649 | .set_length(tick_length)\
650 | .move_to(self.axes.c2p(0, y))
651 | ticks.add(tick)
652 | return ticks
653 |
654 | def get_y_axis_numbers(self, start, end, **kwargs):
655 | axis_numbers = VGroup()
656 | for y in range(start, end + 1):
657 | num = MathTex(str(y), color = GREY, **kwargs)
658 | num.next_to(self.axes.c2p(0, y), LEFT)
659 | axis_numbers.add(num)
660 | return axis_numbers
661 |
662 | def get_d_line(self, x_min, x_max, x_step, line_length, **kwargs):
663 | d_line = NumberLine(
664 | x_range = [x_min, x_max, x_step], length = line_length, rotation = PI/2, color = WHITE,
665 | include_numbers = True, label_direction = LEFT, decimal_number_config = {"num_decimal_places": 0, "color": GREY}, font_size = 30,
666 | **kwargs
667 | )
668 | d_line.shift(2*LEFT)
669 | return d_line
670 |
671 | def get_d_dot(self, **kwargs):
672 | d_line, d_val = self.d_line, self.d_val
673 | d_dot = Dot(
674 | point = d_line.n2p(d_val.get_value()),
675 | color = p2c(d_val.get_value(), -3, 3, self.colors),
676 | **kwargs
677 | )
678 | d_dot.set_sheen(-0.3, DR)
679 | d_dot.set_stroke(width = 1, color = WHITE)
680 |
681 | return d_dot
682 |
683 | def get_dot_to_axes_line(self):
684 | line = Line(
685 | self.d_dot.get_center(),
686 | self.axes.c2p(0, self.d_val.get_value()),
687 | color = p2c(self.d_val.get_value(), -3, 3, self.colors)
688 | )
689 | line.set_stroke(opacity = [0,1,0])
690 | return line
691 |
692 |
693 |
694 |
695 |
696 | class Thumbnail(Scene):
697 | def construct(self):
698 | x_min, x_max = -3*PI, 3*PI
699 | axes = Axes(x_range = [x_min, x_max])
700 |
701 | sin_graph = axes.get_graph(lambda x: np.sin(x), x_range = [x_min, x_max], stroke_width = 8)\
702 | .set_color([RED, RED_E, RED])
703 | sind_graph = axes.get_graph(lambda x: np.sin(x) + 3, x_range = [x_min, x_max], stroke_width = 8)\
704 | .set_color([BLUE, BLUE_E, BLUE])
705 |
706 | dots_sin, dots_sind = VGroup(), VGroup()
707 | for x in np.linspace(0, 1, 21):
708 | dot_sin = Dot(point = sin_graph.point_from_proportion(x), color = sin_graph.get_color(), radius = 0.1)
709 | dot_sind = Dot(point = sind_graph.point_from_proportion(x), color = sind_graph.get_color(), radius = 0.1)
710 |
711 | dot_sin.set_stroke(width = 1, color = BLACK).set_sheen(-0.3, DR)
712 | dot_sind.set_stroke(width = 1, color = BLACK).set_sheen(-0.3, DR)
713 |
714 | dots_sin.add(dot_sin)
715 | dots_sind.add(dot_sind)
716 |
717 |
718 | arrows = VGroup(*[
719 | Line(start.get_center(), end.get_center(), buff = 0.1).set_color([RED, BLUE])
720 | for start, end in zip(dots_sin, dots_sind)
721 | ])
722 | for line in arrows:
723 | line.add_tip(tip_length = 0.2) # adding a tip
724 | line[1].set_color(BLUE) # color the tip
725 |
726 |
727 | eq = MathTex("\\sin", "(", "x", ")", "+", "d", font_size = 160)\
728 | .to_edge(DOWN, buff = 1)
729 | eq[0].set_color(RED)
730 | eq[1:4].set_color(LIGHT_GREY)
731 | eq[4:].set_color(BLUE)
732 |
733 |
734 | self.add(sin_graph, sind_graph, dots_sin, dots_sind, arrows, eq)
735 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # manim-projects
2 |
3 | This project contains the code used to generate the videos found on [my youtube channel!](https://www.youtube.com/c/VisualXAnimation)
4 |
5 | Videos are generated using the library Manim.
6 |
7 | Since june 2021 i'm using the community version of Manim, also called Manim CE. Check out their [official documentation!](https://docs.manim.community/en/latest/#).
8 |
--------------------------------------------------------------------------------