├── .gitignore ├── ArchimedesQuadrature.py ├── CardFromCirc.py ├── CircleInversion.py ├── ComplexRoots.py ├── ComplexTranforms.py ├── CycloidArea.py ├── Discretise.py ├── Divergence.py ├── EulerODE.py ├── EulerWave.py ├── HystCopy.py ├── Hysteresis.py ├── Jacobian.py ├── Murmuration.py ├── NewtonRootFinder.py ├── PartialsOfComponents.py ├── PolygonToEllipse.py ├── PythagorasTree.py ├── README.md ├── RKMethod.py ├── SeriesProof.py ├── SimpsonsRule.py ├── SupThevNor.py ├── ThreePhase.py ├── TrapRule.py ├── TrigPowerSeries.py └── TrippyCircleGif.py /.gitignore: -------------------------------------------------------------------------------- 1 | */ 2 | EulerWave.py 3 | Divergence.py 4 | EulerODE.py 5 | NewtonRootFinder.py 6 | PartialsOfComponents.py 7 | ThreePhase.py 8 | OfficialTestFIle.py 9 | git_branch_procedure.notes 10 | DeleteImmediate.py 11 | tweet.py 12 | WorkingFonts.txt 13 | MyStyle.py 14 | OfficialTestFile2.py 15 | corioliseffect.py 16 | AKBday.py 17 | /Misc/* 18 | -------------------------------------------------------------------------------- /ArchimedesQuadrature.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class ArchimedesQuad(GraphScene, MovingCameraScene): 5 | # super().construct() 6 | CONFIG = { 7 | "x_min": -10, 8 | "x_max": 10, 9 | "x_axis_width": 20, 10 | "x_tick_frequency": 2, 11 | "x_leftmost_tick": None, # Change if different from x_min 12 | "x_labeled_nums": None, 13 | "x_axis_label": "$x$", 14 | "y_min": -40, 15 | "y_max": 40, 16 | "y_axis_height": 10, 17 | "y_tick_frequency": 8, 18 | "y_bottom_tick": None, # Change if different from y_min 19 | "y_labeled_nums": None, 20 | "y_axis_label": "$y$", 21 | "axes_color": GREY, 22 | "graph_origin": ORIGIN, 23 | "exclude_zero_label": True, 24 | "default_graph_colors": [BLUE, GREEN, YELLOW], 25 | "default_derivative_color": GREEN, 26 | "default_input_color": YELLOW, 27 | "default_riemann_start_color": BLUE, 28 | "default_riemann_end_color": GREEN, 29 | "area_opacity": 0.8, 30 | "num_rects": 50, 31 | "dot_kwargs": { 32 | "radius": 0.05, 33 | }, 34 | "line_kwargs": { 35 | "stroke_width": 2, 36 | }, 37 | "fill_triangle_kwargs": { 38 | # "fill_color": BLUE, 39 | "fill_opacity": .5, 40 | "stroke_width": 0, 41 | }, 42 | } 43 | 44 | def setup(self): 45 | GraphScene.setup(self) 46 | MovingCameraScene.setup(self) 47 | 48 | def construct(self): 49 | # ctp = self.coords_to_point 50 | self.camera_frame.scale(.55) 51 | self.setup_axes(animate=True) 52 | parabola = self.get_graph( 53 | lambda x: x**2, 54 | x_min=self.x_min, 55 | x_max=self.x_max, 56 | color=BLUE, 57 | stroke_width=5 58 | ).save_state() 59 | parabola_copy = parabola.copy() 60 | 61 | parabola_left = self.get_graph( 62 | lambda x: x**2, 63 | x_min=-3, 64 | x_max=0, 65 | color=BLUE, 66 | stroke_width=5 67 | ) 68 | parabola_right = self.get_graph( 69 | lambda x: x**2, 70 | x_min=0, 71 | x_max=3, 72 | color=BLUE, 73 | stroke_width=5 74 | ) 75 | lines = VGroup() 76 | self.play(ShowCreation(parabola), run_time=2) 77 | self.wait() 78 | self.play( 79 | self.x_axis.fade, 1, 80 | self.y_axis.fade, 1, 81 | ) 82 | 83 | tgt_point_1 = 3 84 | tgt_point_2 = -3 85 | tangent_line_scale = 5.5 86 | 87 | def get_tangent(tgt_point): 88 | tangent = Line(ORIGIN, RIGHT, color=GREEN, **self.line_kwargs) 89 | tangent.scale(tangent_line_scale) 90 | tangent.rotate( 91 | self.angle_of_tangent(tgt_point, parabola) - tangent.get_angle() 92 | ) 93 | return tangent 94 | 95 | def get_intersection_point(line1, line2): 96 | endpoints1, endpoints2 = np.array([line1.points[0], line1.points[-1]]), np.array([line2.points[0], line2.points[-1]]) 97 | return line_intersection(endpoints1, endpoints2) 98 | 99 | self.a, self.b = 1, -1 100 | 101 | def tempA_updater(temp_A, dt): 102 | if temp_A.get_center()[0] <= 3: 103 | self.a += dt * 2 104 | dot = Dot(self.input_to_graph_point(self.a, parabola), **self.dot_kwargs) 105 | temp_A.become(dot) 106 | 107 | def tempB_updater(temp_B, dt): 108 | if temp_B.get_center()[0] >= -3: 109 | self.b -= dt * 2 110 | dotb = Dot(self.input_to_graph_point(self.b, parabola), **self.dot_kwargs) 111 | temp_B.become(dotb) 112 | 113 | temp_A_point = self.input_to_graph_point(self.a, parabola) 114 | # temp_A_point.add_updater(tempA_updater) 115 | temp_B_point = self.input_to_graph_point(self.b, parabola) 116 | # temp_B_point.add_updater(tempB_updater) 117 | temp_A, temp_B = Dot(temp_A_point, **self.dot_kwargs).save_state(), Dot(temp_B_point, **self.dot_kwargs).save_state() 118 | temp_chord = Line(temp_A_point, temp_B_point, color=YELLOW, **self.line_kwargs) 119 | temp_chord.add_updater(lambda x: x.put_start_and_end_on(temp_A.get_center(), temp_B.get_center())) 120 | 121 | def tang_A_updater(temp_A_tang, dt): 122 | new_tang_A = get_tangent(temp_A.get_center()[0]).move_to(temp_A) 123 | temp_A_tang.become(new_tang_A) 124 | 125 | def tang_B_updater(temp_B_tang, dt): 126 | new_tang_B = get_tangent(temp_B.get_center()[0]).move_to(temp_B) 127 | temp_B_tang.become(new_tang_B) 128 | 129 | area = VMobject(fill_color=YELLOW, fill_opacity=.5, stroke_width=0) 130 | area_points = [self.input_to_graph_point(i, parabola) for i in np.arange(temp_B_point[0], temp_A_point[0], 0.1)] 131 | area_points.append(temp_A_point) 132 | area.set_points_as_corners(area_points) 133 | 134 | def area_updater(area, dt): 135 | new_area = VMobject(fill_color=YELLOW, fill_opacity=.5, stroke_width=0) 136 | new_area_points = [self.input_to_graph_point(i, parabola) for i in np.arange(temp_B.get_center()[0], temp_A.get_center()[0], 0.1)] 137 | new_area_points.append(temp_A.get_center()) 138 | new_area.set_points_as_corners(new_area_points) 139 | area.become(new_area) 140 | 141 | self.play( 142 | *[FadeIn(i) for i in [temp_A, temp_B]], 143 | *[Write(j) for j in [temp_chord]] # , temp_A_tang, temp_B_tang]] 144 | ) 145 | self.play(FadeIn(area)) 146 | temp_A.add_updater(tempA_updater) 147 | area.add_updater(area_updater) 148 | self.add(temp_A, temp_B, temp_chord, area) # , temp_A_tang, temp_B_tang) 149 | question_mark = TextMobject("Area=?").move_to(area).shift(UP * .5) 150 | self.play(Write(question_mark)) 151 | self.wait(1.5) 152 | temp_A.clear_updaters() 153 | temp_B.add_updater(tempB_updater) 154 | self.add(temp_B) 155 | self.wait(1.5) 156 | self.play(FadeOut(question_mark)) 157 | temp_B.clear_updaters() 158 | self.play(temp_B.restore) 159 | 160 | # temp_A.move_to(self.input_to_graph_point(3, parabola)) 161 | 162 | temp_A_tang = get_tangent(temp_A.get_center()[0]).move_to(temp_A).add_updater(tang_A_updater) 163 | temp_B_tang = get_tangent(temp_B.get_center()[0]).move_to(temp_B).add_updater(tang_B_updater) 164 | 165 | self.play(Write(temp_A_tang), Write(temp_B_tang)) 166 | temp_arch_tri = VMobject(fill_color=RED, **self.fill_triangle_kwargs) 167 | temp_arch_tri.set_points_as_corners([temp_A.get_center(), temp_B.get_center(), get_intersection_point(temp_B_tang, temp_A_tang)]) 168 | temp_arch_tri_copy = temp_arch_tri.copy().scale(.35) 169 | area_copy = area.copy() 170 | area_copy.clear_updaters() 171 | area_copy.scale(.35) 172 | badcode = TexMobject("= \\,\\dfrac{2}{3} \\times").scale(.5) 173 | ffs = VGroup(area_copy, badcode, temp_arch_tri_copy).arrange_submobjects(direction=RIGHT, buff=.1).shift(1 * DOWN) 174 | trim_tang_A = Line(temp_A.get_center(), get_intersection_point(temp_B_tang, temp_A_tang), color=GREEN) 175 | trim_tang_B = Line(temp_B.get_center(), get_intersection_point(temp_B_tang, temp_A_tang), color=GREEN) 176 | 177 | # self.camera_frame.save_state() 178 | # self.play(FadeOut(temp_B_tang), FadeOut(temp_A_tang)) 179 | # self.play(FadeIn(trim_tang_B), FadeIn(trim_tang_A), run_time=2) 180 | self.play( 181 | ReplacementTransform(temp_B_tang, trim_tang_B), 182 | ReplacementTransform(temp_A_tang, trim_tang_A) 183 | ) 184 | self.wait(2) 185 | self.play(FadeIn(ffs[0])) 186 | self.wait() 187 | self.play(Write(badcode)) 188 | self.play(FadeOut(area), run_time=2) 189 | self.play(FadeIn(temp_arch_tri_copy), FadeIn(temp_arch_tri)) 190 | initial_exp = VGroup(temp_chord, temp_A, temp_B, trim_tang_B, trim_tang_A, temp_arch_tri) 191 | self.play(FadeOut(initial_exp), FadeOut(ffs), run_time=2) 192 | self.wait() 193 | 194 | tangent_line_scale = 10 195 | x2 = TexMobject("\\times 2") 196 | 197 | PGroup, AGroup, BGroup, MGroup, QGroup, A1Group, B1Group = [VGroup() for i in range(7)] 198 | loopGroup = VGroup(PGroup, AGroup, BGroup, MGroup, QGroup, A1Group, B1Group) 199 | linesGroup, parents, children = [VGroup() for i in range(3)] 200 | self.camera_frame.save_state() 201 | 202 | def timestwo(mobj1, mobj2, q=0): 203 | x2.move_to(mobj1.get_center() + q * DOWN) 204 | mobj2_copy = mobj2.copy() 205 | self.wait() 206 | # child_triangle.add(x2) 207 | self.play(Write(x2)) 208 | self.play( 209 | TransformFromCopy(mobj1, mobj2_copy), 210 | FadeOut(mobj2), 211 | FadeOut(x2), 212 | run_time=2 213 | ) 214 | return mobj2_copy 215 | 216 | def are_equal(mobj1, mobj2, f=True): 217 | d = .075 218 | line1, line2 = Line(d * RIGHT, d * LEFT), Line(d * RIGHT, d * LEFT) 219 | line1.shift(UP * .025) 220 | line2.shift(DOWN * .025) 221 | equals = VGroup(line1, line2) 222 | equals_copy = equals.copy() 223 | equals.rotate(mobj1.get_angle() + 90 * DEGREES).move_to(mobj1) 224 | equals_copy.rotate(mobj2.get_angle() + 90 * DEGREES).move_to(mobj2) 225 | 226 | self.play(FadeIn(mobj1), FadeIn(mobj2)) 227 | # AnimationGroup(WiggleOutThenIn(mobj1), WiggleOutThenIn(mobj2)) 228 | self.play(AnimationGroup(WiggleOutThenIn(mobj1), WiggleOutThenIn(mobj2), lag_ratio=.5)) 229 | self.play(FadeIn(equals), FadeIn(equals_copy)) 230 | self.wait() 231 | if f: 232 | self.play(*[FadeOut(i) for i in [equals, equals_copy, line1, line2]]) 233 | equal_signs = VGroup(equals, equals_copy) 234 | self.remove(mobj1, mobj2) 235 | 236 | return equal_signs 237 | 238 | def are_similar(tri1, tri2, f=True): 239 | similar_triangle1 = get_triangle(tri1, fill_color=PURPLE, **self.fill_triangle_kwargs) 240 | similar_triangle2 = get_triangle(tri2, fill_color=PURPLE, **self.fill_triangle_kwargs) 241 | self.play(Write(similar_triangle2)) 242 | self.wait(1) 243 | self.play(ReplacementTransform(similar_triangle2, similar_triangle1)) 244 | if f: 245 | self.play(FadeOut(similar_triangle1)) 246 | return similar_triangle1 247 | 248 | for x in range(3): 249 | if x == 1: 250 | self.play(FadeIn(parabola_left)) 251 | if x == 2: 252 | self.play(FadeIn(parabola_right)) 253 | # print(f"================={x}===================") 254 | tangent_1 = get_tangent(tgt_point_1) 255 | tangent_2 = get_tangent(tgt_point_2) 256 | A_point = self.input_to_graph_point(tgt_point_1, parabola) 257 | B_point = self.input_to_graph_point(tgt_point_2, parabola) 258 | A, B = Dot(A_point, **self.dot_kwargs), Dot(B_point, **self.dot_kwargs) 259 | 260 | if x != 0: 261 | A.scale(.5) 262 | B.scale(.5) 263 | tangent_1.move_to(A_point) 264 | tangent_2.move_to(B_point) 265 | chord = Line(A_point, B_point, color=YELLOW, **self.line_kwargs) 266 | 267 | def get_triangle(corners, **kwargs): 268 | tri = VMobject(**kwargs) 269 | tri.set_points_as_corners(corners) 270 | return tri 271 | 272 | P_point = get_intersection_point(tangent_1, tangent_2) 273 | 274 | P = Dot(P_point, **self.dot_kwargs, color=PURPLE) 275 | 276 | P_point_GR = self.point_to_coords(P_point) # GR~Graph Referenced 277 | 278 | Q_point = self.input_to_graph_point(P_point_GR[0], parabola) 279 | Q = Dot(Q_point, **self.dot_kwargs) 280 | AQ_line, BQ_line = Line(A_point, Q_point, color=YELLOW, **self.line_kwargs), Line(B_point, Q_point, color=YELLOW, **self.line_kwargs) 281 | vertex_tangent = get_tangent(Q_point[0]) 282 | vertex_tangent.move_to(Q_point) 283 | 284 | PM_pseudo_line = Line(P_point, np.array([P_point[0], 1, 0])).scale(tangent_line_scale) 285 | M_point = get_intersection_point(PM_pseudo_line, chord) 286 | AM_line, BM_line = Line(A_point, M_point, color=YELLOW, **self.line_kwargs), Line(M_point, B_point, color=YELLOW, **self.line_kwargs) 287 | M = Dot(M_point, **self.dot_kwargs) 288 | PM_line = Line(P_point, M_point, color=RED, **self.line_kwargs) 289 | 290 | A1_point, B1_point = get_intersection_point(vertex_tangent, tangent_1), get_intersection_point(vertex_tangent, tangent_2) 291 | A1, B1 = Dot(A1_point, **self.dot_kwargs), Dot(B1_point, **self.dot_kwargs) 292 | if x == 0: 293 | permanent_P_point = P_point 294 | permanent_A_point = A_point 295 | permanent_B_point = B_point 296 | permanent_A1_point = A1_point 297 | permanent_B1_point = B1_point 298 | 299 | dots = VGroup(P, A, B, M, Q, A1, B1) 300 | for l, m in zip(dots, loopGroup): 301 | m.add(l) 302 | 303 | for y in [A, B, P, Q, M, A1, B1]: 304 | if x != 0: 305 | if y != A and y != B: 306 | y.scale(.5) 307 | else: 308 | y.scale(.75) 309 | 310 | labels = TextMobject("A", "B", "P", "M", "Q", "A1", "B1") 311 | for i, j, k in zip(range(7), [A, B, P, M, Q, A1, B1], [DR, DL, DOWN, UP, UR, DR, DL]): 312 | labels[i].scale(.5).next_to(j, direction=k, buff=.02) 313 | # self.add(labels[i]) 314 | 315 | trimmed_tangent_1, trimmed_tangent_2 = Line(A_point, P_point, color=GREEN, **self.line_kwargs), Line(B_point, P_point, color=GREEN, **self.line_kwargs) 316 | trimmed_vertex_tangent = Line(B1_point, A1_point, color=GREEN, **self.line_kwargs) 317 | tangents, trimmed_tangents = VGroup(tangent_1, tangent_2, vertex_tangent), VGroup(trimmed_tangent_1, trimmed_tangent_2, trimmed_vertex_tangent) 318 | temp_lines_group = VGroup(tangents, trimmed_tangents, PM_line, chord, AQ_line, BQ_line) 319 | # temp_lines_group.set_stroke(width=.95) 320 | 321 | if x != 0: 322 | self.play(ShowCreation(A), ShowCreation(B)) 323 | self.play(ShowCreation(chord)) 324 | 325 | if x == 0: 326 | archimedes_triangle = get_triangle([A_point, B_point, P_point, A_point], color=YELLOW) 327 | question = VMobject(fill_color=YELLOW, fill_opacity=.5, stroke_width=0) 328 | question_points = [self.input_to_graph_point(i, parabola) for i in np.arange(B_point[0], A_point[0], 0.1)] 329 | question_points.append(A_point) 330 | question.set_points_as_corners(question_points) 331 | 332 | self.play(ShowCreation(A), ShowCreation(B)) 333 | self.play(Write(chord)) 334 | self.play(Write(labels[0]), Write(labels[1]), run_time=2) 335 | # self.play(Write(archimedes_triangle)) 336 | 337 | self.play(FadeIn(question), run_time=2) 338 | self.wait(2) 339 | self.play(FadeOut(question)) # , FadeOut(archimedes_triangle)) 340 | 341 | self.play(ShowCreation(tangent_1), ShowCreation(tangent_2)) 342 | # self.add(P) 343 | # self.add(chord) 344 | # self.add(vertex_tangent) 345 | # self.add(PM_line) 346 | # self.add(M, Q) 347 | # self.add(A1, B1) 348 | self.play(ShowCreation(P)) 349 | if x == 0: 350 | self.play(Write(labels[2])) 351 | self.play(ShowCreation(PM_line)) 352 | self.play(ShowCreation(M), ShowCreation(Q)) 353 | if x == 0: 354 | self.play(Write(labels[3]), Write(labels[4])) 355 | self.wait(2) 356 | if x == 0: 357 | are_equal(AM_line, BM_line) 358 | self.wait() 359 | self.play(ShowCreation(vertex_tangent)) 360 | self.play(ShowCreation(A1), ShowCreation(B1)) 361 | if x == 0: 362 | self.play(Write(labels[5]), Write(labels[6])) 363 | self.play(ShowCreation(AQ_line), ShowCreation(BQ_line)) 364 | self.play(*[Transform(i, j) for i, j in zip(tangents, trimmed_tangents)]) 365 | 366 | if x == 0: 367 | self.play(parabola.fade, .75) 368 | self.wait() 369 | self.play(FadeIn(parabola_right), run_time=2) 370 | self.wait(2) 371 | 372 | tempvertical = Line(A1_point, np.array([A1_point[0], 1, 0]), color=RED, **self.line_kwargs).scale(3) 373 | L_point = get_intersection_point(tempvertical, AQ_line) 374 | L = Dot(L_point, **self.dot_kwargs).scale(.75) 375 | L_label = TextMobject("L").scale(.5).next_to(L, direction=UL, buff=.02) 376 | AL_line = Line(L_point, A_point, color=YELLOW, **self.line_kwargs) 377 | QL_line = Line(L_point, Q_point, color=YELLOW, **self.line_kwargs) 378 | MQ_line = Line(M_point, Q_point, color=RED, **self.line_kwargs) 379 | PQ_line = Line(Q_point, P_point, color=RED, **self.line_kwargs) 380 | A1L_line = Line(A1_point, L_point, color=RED, **self.line_kwargs) 381 | 382 | self.play(Write(tempvertical)) 383 | self.play(FadeIn(L)) 384 | self.play(Write(L_label)) 385 | 386 | equal_signs = are_equal(AL_line, QL_line, f=False) 387 | 388 | self.play(WiggleOutThenIn(PQ_line)) 389 | self.play(WiggleOutThenIn(A1L_line)) 390 | self.remove(PQ_line) 391 | # similar_triangle1 = are_similar([A_point, L_point, A1_point], [A_point, P_point, Q_point], f=False) 392 | AA1_line = Line(A1_point, A_point, color=GREEN, **self.line_kwargs) 393 | PA1_line = Line(A1_point, P_point, color=GREEN, **self.line_kwargs) 394 | 395 | are_equal(AA1_line, PA1_line) 396 | self.play(*[FadeOut(i) for i in [tempvertical, L, L_label, AL_line, QL_line, equal_signs, A1L_line]]) # similar_triangle1, 397 | self.play(FadeOut(parabola_right)) 398 | self.play(parabola.restore) 399 | 400 | BB1_line = Line(B1_point, B_point, color=GREEN, **self.line_kwargs) 401 | PB1_line = Line(B1_point, P_point, color=GREEN, **self.line_kwargs) 402 | 403 | are_equal(BB1_line, PB1_line) 404 | 405 | tangent_2_copy = tangent_2.copy() 406 | PB1_line_copy = PB1_line.copy().save_state() 407 | PB1_line_copy.shift(DL * .35) 408 | ninety_deg = VGroup(*[Elbow(angle=180 * DEGREES) for _ in range(2)]) 409 | ninety_deg[1].move_to(M_point).align_to(M_point, direction=RIGHT).align_to(M_point, direction=UP) 410 | 411 | are_similar([Q_point, B1_point, P_point], [M_point, B_point, P_point]) 412 | 413 | self.play(tangent_2_copy.shift, DL * .35) 414 | self.play(ReplacementTransform(tangent_2_copy, PB1_line_copy)) 415 | self.play(PB1_line_copy.restore) 416 | self.play(FadeOut(PB1_line_copy)) 417 | self.remove(PB1_line_copy, BB1_line) 418 | QB1_line = Line(Q_point, B1_point, color=GREEN, **self.line_kwargs) 419 | 420 | self.play(TransformFromCopy(BM_line, QB1_line)) 421 | self.play(Write(ninety_deg)) 422 | self.play(FadeOut(ninety_deg), FadeOut(QB1_line)) 423 | self.wait() 424 | self.remove(QB1_line) 425 | 426 | for q in range(2): 427 | MP_line = Line(M_point, P_point, color=RED, **self.line_kwargs).save_state() 428 | PQ_line_copy = PQ_line.copy().shift(.5 * RIGHT) 429 | 430 | if q == 0: 431 | self.play(ApplyMethod(MP_line.shift, .5 * RIGHT)) 432 | self.play(ApplyMethod(MP_line.become, PQ_line_copy)) 433 | self.play(ReplacementTransform(MP_line, PQ_line)) 434 | self.remove(MP_line) 435 | are_equal(MQ_line, PQ_line) 436 | else: 437 | self.play(ApplyMethod(MP_line.shift, .5 * RIGHT), run_time=.5) 438 | self.play(ApplyMethod(MP_line.become, PQ_line_copy), run_time=.5) 439 | self.play(ReplacementTransform(MP_line, PQ_line), run_time=.5) 440 | self.remove(MP_line) 441 | self.remove(PQ_line_copy) 442 | self.wait() 443 | 444 | A1B1_line = Line(A1_point, B1_point, color=GREEN, **self.line_kwargs) 445 | chord_copy = chord.copy() 446 | 447 | self.play(ReplacementTransform(chord_copy, A1B1_line)) 448 | self.remove(A1B1_line) 449 | 450 | sim_tri1 = get_triangle([A1_point, B1_point, P_point], fill_color=PURPLE, **self.fill_triangle_kwargs) 451 | sim_tri2 = get_triangle([A_point, B_point, P_point], fill_color=PURPLE, **self.fill_triangle_kwargs) 452 | tri_text1 = TexMobject("\\Delta (APB) =", " 4 \\times \\Delta(A1\\,P\\,B1)").scale(.5).shift(2 * DOWN) 453 | 454 | self.play(Write(sim_tri2), Write(tri_text1[0]), run_time=2) 455 | self.wait(2) 456 | self.play(ReplacementTransform(sim_tri2, sim_tri1), Write(tri_text1[1]), run_time=2) 457 | self.play(FadeOut(sim_tri1), tri_text1.shift, 2.25 * LEFT + .75 * UP) 458 | 459 | MP_line.restore() 460 | MQ_line_copy = MQ_line.copy().shift(.5 * RIGHT) 461 | 462 | self.play(ApplyMethod(MP_line.shift, .5 * RIGHT)) 463 | self.play(ApplyMethod(MP_line.become, MQ_line_copy), run_time=2) 464 | self.play(ReplacementTransform(MP_line, MQ_line)) 465 | self.remove(MP_line) 466 | 467 | sim_tri1 = get_triangle([A_point, B_point, Q_point], fill_color=PURPLE, **self.fill_triangle_kwargs) 468 | sim_tri2 = get_triangle([A_point, B_point, P_point], fill_color=PURPLE, **self.fill_triangle_kwargs) 469 | tri_text = TexMobject("\\Delta (APB) =", " 2 \\times \\Delta(AQB)").scale(.5).shift(2 * DOWN) 470 | 471 | self.play(Write(sim_tri2), Write(tri_text[0]), run_time=2) 472 | self.wait(2) 473 | self.play(ReplacementTransform(sim_tri2, sim_tri1), Write(tri_text[1]), run_time=2) 474 | self.play(FadeOut(sim_tri1), tri_text.next_to, tri_text1, {"direction": DOWN}) 475 | 476 | tri_textgrp = VGroup(tri_text, tri_text1) 477 | proof = TexMobject("\\Delta (AQB) =", " 2 \\times \\Delta(A1\\,P\\,B1)").scale(.5).move_to(tri_textgrp) 478 | self.wait(2) 479 | 480 | parent_triangle = get_triangle([A_point, B_point, Q_point], fill_color=YELLOW, **self.fill_triangle_kwargs) 481 | child_triangle = get_triangle([A1_point, B1_point, P_point], fill_color=GREEN, **self.fill_triangle_kwargs) 482 | parents.add(parent_triangle) 483 | children.add(child_triangle) 484 | # checkwork 485 | self.play(FadeIn(parent_triangle)) 486 | self.play(FadeIn(child_triangle)) 487 | # parent_copy = parent_triangle.copy() 488 | self.wait() 489 | if x != 0: 490 | parent_copy = timestwo(child_triangle, parent_triangle, q=0.15) 491 | # x2.move_to(child_triangle.get_center() + 0.15 * DOWN) 492 | else: 493 | self.play(ReplacementTransform(tri_textgrp, proof)) 494 | parent_copy = timestwo(child_triangle, parent_triangle) 495 | self.play(FadeOut(proof)) 496 | # x2.move_to(child_triangle.get_center()) 497 | # child_triangle.add(x2) 498 | # self.play(Write(x2)) 499 | # self.play( 500 | # TransformFromCopy(child_triangle, parent_copy), 501 | # FadeOut(parent_triangle), 502 | # FadeOut(x2), 503 | # run_time=2 504 | # ) 505 | 506 | self.play( 507 | FadeOut(child_triangle), 508 | # FadeOut(parent_triangle), 509 | FadeOut(parent_copy) 510 | ) 511 | for n in loopGroup: 512 | self.play(FadeOut(n[x]), run_time=.1) 513 | 514 | lines = VGroup(tangents, PM_line, chord, chord_copy, AQ_line, BQ_line, MQ_line, PQ_line) 515 | # for mobj in self.mobjects: 516 | # if isinstance(mobj, Line): 517 | # lines.add(mobj) 518 | 519 | lines.save_state() 520 | linesGroup.add(lines) 521 | parabola.save_state() 522 | self.play(lines.fade, .75,) 523 | 524 | self.play( 525 | # tangents.fade, .75, 526 | # PM_line.fade, .75, 527 | 528 | parabola.fade, .5 529 | ) 530 | 531 | if x == 0: 532 | self.play(FadeOut(labels)) 533 | self.play( 534 | self.camera_frame.scale, .75, 535 | self.camera_frame.move_to, permanent_B1_point, 536 | ) 537 | 538 | elif x == 1: 539 | self.play(self.camera_frame.restore) 540 | self.play(FadeOut(parabola_left)) 541 | self.play( 542 | self.camera_frame.scale, .75, 543 | self.camera_frame.move_to, permanent_A1_point, 544 | ) 545 | # self.wait(2) 546 | tangent_line_scale = 7 547 | if x == 0: 548 | tgt_point_1 = permanent_P_point[0] 549 | tgt_point_2 = permanent_B_point[0] 550 | x2.scale(.25) 551 | # print(f"=========={tgt_point_1}....{tgt_point_2}============") 552 | if x == 1: 553 | tgt_point_1 = permanent_A_point[0] 554 | tgt_point_2 = permanent_P_point[0] 555 | 556 | if x == 2: 557 | self.play(FadeOut(parabola_right)) 558 | # parabola.fade(0) 559 | # self.play(parabola.set_stroke, {"width": 5}, run_time=2) 560 | self.play(FadeIn(parabola_copy)) 561 | # print(f"=========={tgt_point_1}....{tgt_point_2}============") 562 | 563 | # for i, j in zip(list(range(7)), [A, B, P, M, Q, A1, B1]): 564 | # labels[i].scale(.5).next_to(j, direction=UR, buff=.02) 565 | # self.remove(labels[i]) 566 | 567 | self.play(self.camera_frame.restore) 568 | for o in linesGroup: 569 | self.play(o.restore) 570 | self.play( 571 | FadeIn(parents), 572 | FadeIn(children), 573 | run_time=2 574 | ) 575 | self.wait(2) 576 | x2.scale(4).move_to(children) 577 | parents_copy = timestwo(children, parents) 578 | # parents_copy = parents.copy() 579 | # self.play(Write(x2)) 580 | # self.play( 581 | # TransformFromCopy(children, parents_copy), 582 | # FadeOut(parents), 583 | # FadeOut(x2), 584 | # run_time=2 585 | # ) 586 | inverse_question = VMobject(fill_color=GREEN, fill_opacity=.5, stroke_width=0) 587 | inverse_question_points = [self.input_to_graph_point(i, parabola) for i in np.arange(permanent_B_point[0], permanent_A_point[0], 0.1)] 588 | inverse_question_points.insert(0, permanent_P_point) 589 | inverse_question_points.append(permanent_P_point) 590 | inverse_question.set_points_as_corners(inverse_question_points) 591 | limit = TexMobject("\\text{In the } limiting \\text{ case}").scale(.5).shift(1.5 * UP) 592 | linesGroup_for_archimedes_triangle = linesGroup.remove(AQ_line, BQ_line, chord) 593 | 594 | self.play( 595 | Write(limit) 596 | ) 597 | self.play(FadeOut(linesGroup_for_archimedes_triangle), FadeIn(archimedes_triangle),) 598 | 599 | self.play( 600 | FadeOut(parents_copy), 601 | FadeIn(question), 602 | run_time=2 603 | ) 604 | self.wait() 605 | self.play( 606 | FadeOut(children), 607 | FadeIn(inverse_question), 608 | run_time=2 609 | ) 610 | self.wait() 611 | question_copy_from_timestwo = timestwo(inverse_question, question, q=0.5) 612 | self.play(FadeOut(question_copy_from_timestwo)) 613 | archimedes_triangle = get_triangle([permanent_A_point, permanent_B_point, permanent_P_point, permanent_A_point]) 614 | archimedes_triangle.set_fill(color=RED, opacity=.75).set_stroke(color=YELLOW) 615 | # archimedes_triangle.add_to_back(parabola) 616 | # self.play(archimedes_triangle.fade, 0, run_time=3) 617 | 618 | # parabola.set_stroke(width=5) 619 | # self.add(parabola) 620 | 621 | inverse_question_copy = inverse_question.copy().scale(.5) 622 | question_copy = question.copy().scale(.5) 623 | archimedes_triangle_copy = archimedes_triangle.copy().set_fill(opacity=1).set_stroke(width=0).scale(.5) 624 | plus_n_equal = TexMobject("=", "+", "2", "\\dfrac{3}{2} \\times", "\\dfrac{2}{3} \\times") 625 | dividedby = Line(.5 * LEFT, .5 * RIGHT) 626 | answer = VGroup( 627 | archimedes_triangle_copy, 628 | plus_n_equal[0], 629 | question_copy, 630 | plus_n_equal[1], 631 | inverse_question_copy 632 | ).arrange_submobjects(buff=.1).scale(.5).move_to(1.75 * DOWN) 633 | plus_n_equal[2].scale(.5) 634 | twicequestion = VGroup(question_copy.copy(), dividedby, plus_n_equal[2])\ 635 | .arrange_submobjects(direction=DOWN, buff=.15).move_to(inverse_question_copy.get_center()) 636 | 637 | plus_n_equal[3].scale(.5) 638 | threesecondsquestion = VGroup(plus_n_equal[3], question_copy.copy())\ 639 | .arrange_submobjects(buff=.1).next_to(plus_n_equal[0], direction=RIGHT) 640 | # twothirds_archimedes_triangle = VGroup(plus_n_equal[3], question_copy.copy())\ 641 | # .arrange_submobjects(buff=.1).next_to(plus_n_equal[0]) 642 | # self.camera_frame.scale(2) 643 | # self.add(answer) 644 | self.play( 645 | *[FadeOut(p) for p in [inverse_question]], 646 | FadeIn(archimedes_triangle), 647 | FadeIn(archimedes_triangle_copy), 648 | run_time=2 649 | ) 650 | self.wait(2) 651 | # self.play(Write(archimedes_triangle), Write(archimedes_triangle_copy), run_time=2) 652 | self.play(archimedes_triangle.set_fill, {"opacity": 0}) 653 | self.play(Write(plus_n_equal[0])) 654 | self.play(FadeIn(question), FadeIn(question_copy)) 655 | self.play(Write(plus_n_equal[1])) 656 | self.play(FadeIn(inverse_question), FadeIn(inverse_question_copy)) 657 | self.wait(2) 658 | self.play(ReplacementTransform(inverse_question_copy, twicequestion)) 659 | self.wait() 660 | 661 | plus_n_equal[4].scale(.5).next_to(archimedes_triangle_copy, direction=LEFT, buff=.1).shift(RIGHT * .5) 662 | tempgrp = VGroup( 663 | # plus_n_equal[0], 664 | question_copy, 665 | plus_n_equal[1], 666 | twicequestion 667 | ) 668 | tempgrp2 = VGroup( 669 | archimedes_triangle_copy, 670 | plus_n_equal[0]) 671 | self.play(ReplacementTransform(tempgrp, threesecondsquestion)) 672 | self.wait(2) 673 | self.play(tempgrp2.shift, RIGHT * .5, ReplacementTransform(plus_n_equal[3], plus_n_equal[4])) 674 | self.wait(2) 675 | 676 | swapgrp1, swapgrp2 = VGroup(plus_n_equal[-1], archimedes_triangle_copy), VGroup(threesecondsquestion[-1]) 677 | self.play( 678 | Swap(swapgrp1, swapgrp2), 679 | plus_n_equal[0].shift, LEFT * .15, 680 | run_time=2 681 | ) 682 | final_answer = VGroup(threesecondsquestion[-1], plus_n_equal[0], plus_n_equal[-1], archimedes_triangle_copy) 683 | self.wait(2) 684 | # self.play(Indicate(final_answer)) 685 | self.play( 686 | ShowCreationThenFadeAround(final_answer), 687 | # Flash(final_answer) 688 | ) 689 | self.wait(2) 690 | #checking working 691 | # self.play() 692 | # for i in range(2): 693 | 694 | # def loop(P_point): 695 | # P_point_GR = self.point_to_coords(P_point) # GR~Graph Referenced 696 | 697 | # Q_point = self.input_to_graph_point(P_point_GR[0], parabola) 698 | # Q = Dot(Q_point, **self.dot_kwargs) 699 | 700 | # PM_pseudo_line = Line(P_point, np.array([P_point[0], 1, 0])).scale(tangent_line_scale) 701 | # M_point = get_intersection_point(PM_pseudo_line, chord) 702 | # M = Dot(M_point, **self.dot_kwargs) 703 | # PM_line = Line(P_point, M_point, color=RED) 704 | 705 | # first_set = VGroup(labels, tangent_1, tangent_2) 706 | 707 | 708 | """ 709 | https://www.youtube.com/watch?v=tdvII0x0Y58 710 | https://math.stackexchange.com/questions/1804694/area-of-parabola-using-weighted-average 711 | """ 712 | -------------------------------------------------------------------------------- /CardFromCirc.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class Cardiod(Scene): 5 | # CONFIG = {"camera_config": {"background_color": GREEN}} 6 | 7 | def construct(self): 8 | water_mark = Text("@the_rookie_nerds", stroke_width=0.01, fill_opacity=0.25).scale(0.5).move_to(np.array([4.5, -8.5, 0])) 9 | self.add(water_mark) 10 | cam_adjust = 2 11 | circ = Circle(stroke_width=3).scale(cam_adjust) 12 | self.add(circ) 13 | base = circ.get_right() 14 | self.add(Dot(base, color=YELLOW)) 15 | 16 | # ################################################## 17 | dot_list = [1, 2, 3, 4, 5, 7, 9, 15] 18 | for i in dot_list: 19 | dots = VGroup() 20 | pseudo_circs = VGroup() 21 | step = TAU / i 22 | for _ in range(i): 23 | dot = Dot().move_to(rotate_vector(circ.get_right(), _ * step)) 24 | dots.add(dot) 25 | 26 | def update_pseudo_circ(c, dt): 27 | new_c = Circle(radius=np.linalg.norm(c.dot.get_center() - base), color=WHITE).move_to(c.dot) 28 | c.become(new_c) 29 | 30 | for _, dot in enumerate(dots): 31 | pseudo_circ = Circle(radius=np.linalg.norm(dot.get_center() - base), color=WHITE, stroke_width=1.5).move_to(dot) 32 | pseudo_circ.dot = dot 33 | pseudo_circ.add_updater(update_pseudo_circ) 34 | pseudo_circs.add(pseudo_circ) 35 | 36 | self.play(FadeIn(pseudo_circs), FadeIn(dots)) 37 | for dot in dots: 38 | always_rotate(dot, about_point=ORIGIN, rate=PI) 39 | self.wait(2) 40 | tempgrp = VGroup(dots, pseudo_circs) 41 | self.play(FadeOut(tempgrp)) 42 | 43 | # self.play(*[FadeOut(mobj) for mobj in self.mobjects]) 44 | -------------------------------------------------------------------------------- /CircleInversion.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class CircleInvert(ThreeDScene): 5 | def construct(self): 6 | axes = ThreeDAxes(stroke_width=.25) 7 | self.set_camera_orientation(phi=60 * DEGREES, theta=-55 * DEGREES) 8 | self.begin_ambient_camera_rotation(rate=0.04) 9 | grid = NumberPlane() 10 | unit_circle = Circle(radius=1, stroke_width=2, color=PURPLE) 11 | 12 | def func(u, v): 13 | return np.array([ 14 | 1 * np.cos(u) * np.cos(v), 15 | 1 * np.cos(u) * np.sin(v), 16 | 1 * np.sin(u)]) 17 | 18 | sphere = ParametricSurface(func, 19 | v_min=0, 20 | v_max=TAU, 21 | u_min=0, 22 | u_max=PI / 2, 23 | fill_opacity=0, 24 | resolution=15, 25 | stroke_width=1, 26 | ) 27 | self.add(sphere, unit_circle) # ), axes) 28 | dot_radius = .05 29 | # path = Circle(radius=.25).shift(UR * .35) 30 | path = VMobject() 31 | path_pts = [] 32 | x_samps = np.arange(-.95, .95, .125) 33 | # def get_circ(pt1, pt2): 34 | 35 | for x, i in zip(x_samps, range(len(x_samps))): 36 | if i % 2 == 0: 37 | path_pts.append(np.array([x, -(1 - x**2)**.5, 0])) 38 | if i % 2 != 0: 39 | path_pts.append(np.array([x, (1 - x**2)**.5, 0])) 40 | 41 | path.set_points_as_corners(path_pts).make_smooth() 42 | # self.add(path) 43 | 44 | in_dot = Dot(path.points[0], radius=dot_radius, color=BLUE) 45 | 46 | in_trace = VMobject(color=BLUE, stroke_width=1) 47 | in_trace.set_points_as_corners([in_dot.get_center(), in_dot.get_center() + UP * 0.01]) 48 | 49 | def update_in_trace(in_trace): 50 | previous_in_trace = in_trace.copy() 51 | previous_in_trace.add_points_as_corners([in_dot.get_center()]) 52 | in_trace.become(previous_in_trace) 53 | 54 | in_ray = Line(ORIGIN, in_dot.get_center(), stroke_width=0) 55 | 56 | in_ray.add_updater(lambda x: x.put_start_and_end_on(ORIGIN, in_dot.get_center() + UP * 0.000000001)) 57 | 58 | in_trace.add_updater(update_in_trace) 59 | self.add(in_dot, in_ray, in_trace,) 60 | 61 | # inverted_length = 1 / (in_point[0]**2 + in_point[1]**2) 62 | inverted_length = 1 / in_ray.get_length() 63 | 64 | out_ray = Line(ORIGIN, RIGHT, stroke_width=1) 65 | out_ray.scale_about_point(inverted_length, ORIGIN).set_angle(in_ray.get_angle()) 66 | 67 | def out_ray_updater(out_ray, dt): 68 | inverted_length = 1 / in_ray.get_length() 69 | new_out_ray = Line(ORIGIN, RIGHT, stroke_width=0) 70 | new_out_ray.scale_about_point(inverted_length, ORIGIN).set_angle(in_ray.get_angle()) 71 | out_ray.become(new_out_ray) 72 | 73 | out_ray.add_updater(out_ray_updater) 74 | 75 | out_dot = Dot(out_ray.points[-1], radius=dot_radius, color=RED) 76 | 77 | out_dot.add_updater(lambda x: x.move_to(out_ray.points[-1])) 78 | 79 | self.add(out_ray, out_dot) 80 | 81 | out_trace = VMobject(color=RED, stroke_width=1) 82 | out_trace.set_points_as_corners([out_dot.get_center(), out_dot.get_center() + UP * 0.01]) 83 | 84 | def update_out_trace(out_trace): 85 | previous_out_trace = out_trace.copy() 86 | previous_out_trace.add_points_as_corners([out_dot.get_center()]) 87 | out_trace.become(previous_out_trace) 88 | 89 | out_trace.add_updater(update_out_trace) 90 | self.add(out_trace) 91 | 92 | # in_trace.add_updater(update_in_trace) 93 | 94 | # in_ray.add_updater(lambda x: x.put_start_and_end_on(ORIGIN, in_dot.get_center() + UP * 0.000000001)) 95 | 96 | # out_ray.add_updater(out_ray_updater) 97 | 98 | # out_dot.add_updater(lambda x: x.move_to(out_ray.points[-1])) 99 | 100 | # out_trace.add_updater(update_out_trace) 101 | 102 | x, y = in_dot.get_center()[0], in_dot.get_center()[1] 103 | 104 | pt_on_sphere = np.array([x, y, (1 - x**2 - y**2)**.5]) 105 | in_sphere_line = Line(in_dot.get_center(), pt_on_sphere, stroke_width=1) 106 | 107 | def update_in_sphere_line(in_sphere_line, dt): 108 | # pt_on_sphere = func(np.arctan(in_dot.get_center()[1] / in_dot.get_center()[0]), in_ray.get_angle()) 109 | x, y = in_dot.get_center()[0], in_dot.get_center()[1] 110 | pt_on_sphere = np.array([x, y, (1 - x**2 - y**2)**.5]) 111 | new_in_sphere_line = Line(in_dot.get_center(), pt_on_sphere, stroke_width=1) 112 | in_sphere_line.become(new_in_sphere_line) 113 | 114 | # in_sphere_line.add_updater(lambda x: x.put_start_and_end_on(in_dot.get_center(), func(in_dot.get_center()[0], in_dot.get_center()[1]))) 115 | in_sphere_line.add_updater(update_in_sphere_line) 116 | self.add(in_sphere_line) 117 | 118 | out_sphere_line = Line(in_sphere_line.points[-1], out_dot.get_center(), stroke_width=1) 119 | 120 | def update_out_sphere_line(out_sphere_line, dt): 121 | new_out_sphere_line = Line(in_sphere_line.points[-1], out_dot.get_center(), stroke_width=1) 122 | out_sphere_line.become(new_out_sphere_line) 123 | 124 | # out_sphere_line.add_updater(lambda x: x.put_start_and_end_on(in_sphere_line.points[-1], out_dot.get_center())) 125 | out_sphere_line.add_updater(update_out_sphere_line) 126 | 127 | # on_sphere_dot = Sphere(radius=.025, color=None).move_to(in_sphere_line.points[-1]) 128 | # on_sphere_dot.add_updater(lambda x: x.move_to(in_sphere_line.points[-1])) 129 | self.add(out_sphere_line) 130 | # self.add(in_dot, in_trace, in_ray, out_dot, out_ray, out_trace, in_sphere_line, out_sphere_line, on_sphere_dot) 131 | 132 | # in_number = DecimalNumber(in_ray.get_length()).scale(.5).add_updater(lambda x: x.next_to(in_dot)).add_updater(lambda x: x.set_value(in_ray.get_length())) 133 | # self.add(in_number) 134 | # out_number = DecimalNumber(out_ray.get_length()).scale(.5).add_updater(lambda x: x.next_to(out_dot)).add_updater(lambda x: x.set_value(out_ray.get_length())) 135 | # self.add(out_number) 136 | 137 | self.play(MoveAlongPath(in_dot, path, rate_func=linear), run_time=20) 138 | # out_dot.move_to(ORIGIN) 139 | # self.move_camera(distance=1.5) 140 | # self.camera_frame.scale(.5) 141 | # for m in self.mobjects: 142 | # m.scale_about_point(2, ORIGIN) 143 | self.wait() 144 | -------------------------------------------------------------------------------- /ComplexRoots.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class CompRoot(GraphScene): 5 | CONFIG = { 6 | 7 | "common_plane_kwargs": { 8 | "x_min": -2.5, 9 | "x_max": 2.5, 10 | "y_min": -2.5, 11 | "y_max": 2.5, 12 | "x_line_frequency": 1, 13 | "y_line_frequency": 1, 14 | }, 15 | "z_plane_center": LEFT * 3.5, 16 | "w_plane_center": RIGHT * 3.5, 17 | 18 | } 19 | 20 | def construct(self): 21 | zpc = self.z_plane_center 22 | wpc = self.w_plane_center 23 | z_freq = 2 24 | w_freq = 2 25 | 26 | z_plane = NumberPlane(**self.common_plane_kwargs) # .move_to(zpc) 27 | w_plane = NumberPlane(**self.common_plane_kwargs).move_to(wpc) 28 | 29 | text = TextMobject("Input Space", "Output Space") 30 | 31 | self.play(Write(z_plane)) 32 | self.play(z_plane.move_to, zpc) 33 | text[0].next_to(z_plane, direction=DOWN) 34 | self.play(Write(text[0])) 35 | 36 | def get_transform_obj(): 37 | path = VMobject() 38 | path_pts = [] 39 | x_samps = np.arange(-.95, 0, .125) 40 | 41 | for x, i in zip(x_samps, range(len(x_samps))): 42 | if i % 2 == 0: 43 | path_pts.append(np.array([x, -.25 * x, 0])) 44 | if i % 2 != 0: 45 | path_pts.append(np.array([x, .25 * x, 0])) 46 | 47 | path.set_points_as_corners(path_pts).make_smooth() 48 | head = VMobject(fill_opacity=1, color=WHITE)\ 49 | .set_points_as_corners([UP, RIGHT, DOWN, UP]).scale(.0725).move_to(path.points[-1]).shift(UP * .025 + RIGHT * .035) 50 | path.add(head) 51 | return path 52 | 53 | trans = get_transform_obj().shift(RIGHT * .5) 54 | self.play(FadeIn(trans)) 55 | self.play(Write(w_plane)) 56 | # self.play(w_plane.move_to, zpc) 57 | text[1].next_to(w_plane, direction=DOWN) 58 | self.play(Write(text[1])) 59 | eqns = TexMobject("z=re^{i \\theta}", "w=f(z)", "w=z^n", "w=r^ne^{i n \\theta}") 60 | eqns[0].next_to(text[0], direction=DOWN, buff=0.05) 61 | for eq in eqns[1:]: 62 | eq.next_to(text[1], direction=DOWN, buff=0.05) 63 | 64 | self.play(*[Write(eqns[i]) for i in range(0, 2)]) 65 | for i in range(1, 3): 66 | self.play(ReplacementTransform(eqns[i], eqns[i + 1])) 67 | self.wait() 68 | self.wait() 69 | 70 | self.play(*[FadeOut(mobj) for mobj in eqns[0::len(eqns) - 1]]) 71 | 72 | z = Dot(zpc) 73 | z_tracker = Line(zpc, z.get_center(), stroke_width=5, color=RED).add_updater(lambda x: x.put_start_and_end_on(zpc, z.get_center() + UP * .0001)) 74 | # self.add(z, z_tracker) 75 | ztl = z_tracker.get_length() 76 | 77 | w_tracker = Line(wpc, wpc + RIGHT, stroke_width=0, color=YELLOW) 78 | if ztl != 0: 79 | w_tracker.scale(ztl**w_freq, about_point=wpc).set_angle(w_freq * z_tracker.get_angle()) 80 | else: 81 | w_tracker.scale(0.02, about_point=wpc) 82 | 83 | def update_w_tracker(w_tracker, dt): 84 | ztl = z_tracker.get_length() 85 | new_w_tracker = Line(wpc, wpc + RIGHT, stroke_width=5, color=YELLOW) 86 | if ztl != 0: 87 | new_w_tracker.scale(ztl**w_freq, about_point=wpc).set_angle(w_freq * z_tracker.get_angle()) 88 | else: 89 | new_w_tracker.scale(0.02, about_point=wpc) 90 | w_tracker.become(new_w_tracker) 91 | 92 | w_tracker.add_updater(update_w_tracker) 93 | w = Dot(w_tracker.points[-1]).add_updater(lambda x: x.move_to(w_tracker.points[-1])) 94 | 95 | # ############################ 96 | 97 | z_trace = VMobject() 98 | z_trace.set_points_as_corners([z.get_center(), z.get_center() + UP * 0.01]) 99 | 100 | def update_z_trace(z_trace): 101 | previous_z_trace = z_trace.copy() 102 | previous_z_trace.add_points_as_corners([z.get_center()]) 103 | z_trace.become(previous_z_trace) 104 | z_trace.add_updater(update_z_trace) 105 | self.add(z_trace) 106 | 107 | w_trace = VMobject() 108 | w_trace.set_points_as_corners([w.get_center(), w.get_center() + UP * 0.01]) 109 | 110 | def update_w_trace(w_trace): 111 | previous_w_trace = w_trace.copy() 112 | previous_w_trace.add_points_as_corners([w.get_center()]) 113 | w_trace.become(previous_w_trace) 114 | w_trace.add_updater(update_w_trace) 115 | self.add(w_trace) 116 | 117 | z_angle = Arc(z_tracker.get_angle(), radius=.25, arc_center=zpc) 118 | 119 | def update_z_angle(z_angle, dt): 120 | new_z_angle = Arc(start_angle=0, angle=z_tracker.get_angle(), radius=.25, arc_center=zpc) 121 | z_angle.become(new_z_angle) 122 | 123 | z_angle.add_updater(update_z_angle) 124 | z_angle_value = DecimalNumber(start_angle=0, angle=z_tracker.get_angle() * (180 / PI)).scale(.75)\ 125 | .add_updater(lambda x: x.next_to(z_angle, direction=UR, buff=0.1)).add_updater(lambda x: x.set_value(z_tracker.get_angle() * (180 / PI))) 126 | 127 | w_angle = Arc(start_angle=0, angle=w_tracker.get_angle(), radius=.25, arc_center=wpc) 128 | 129 | def update_w_angle(w_angle, dt): 130 | new_w_angle = Arc(start_angle=0, angle=w_tracker.get_angle(), radius=.25, arc_center=wpc) 131 | w_angle.become(new_w_angle) 132 | 133 | w_angle.add_updater(update_w_angle) 134 | w_angle_value = DecimalNumber(w_tracker.get_angle() * (180 / PI)).scale(.75)\ 135 | .add_updater(lambda x: x.next_to(w_angle, direction=UR, buff=0.1)).add_updater(lambda x: x.set_value(w_tracker.get_angle() * (180 / PI))) 136 | 137 | # self.add(z_angle, w_angle, z_angle_value, w_angle_value) 138 | path = Square().move_to(zpc).rotate(-45 * DEGREES) 139 | mobjects = VGroup(z, z_tracker, w_tracker, w, z_angle, w_angle, z_angle_value, w_angle_value) 140 | self.play(*[FadeIn(mobj) for mobj in mobjects]) 141 | self.add(mobjects) 142 | 143 | eqn = TexMobject("w=", "z").next_to(trans, direction=UP, buff=0.1) 144 | power = DecimalNumber(w_freq, num_decimal_places=0).scale(.5).next_to(eqn[1], direction=UR, buff=0.05) 145 | mapping = VGroup(eqn, power).scale(.75) 146 | 147 | eg = TexMobject("\\text{For Example}", "w=r^2e^{i2\\theta}", "|w| = |z|^2", "Arg(w) = 2Arg(z)") 148 | eg[0].to_edge(UP) 149 | eg[1].move_to(mapping).scale(.75).save_state() 150 | eg[2].move_to(mapping).scale(.5) 151 | eg[3].next_to(eg[2], direction=UP, buff=0.1).scale(.5) 152 | 153 | self.play(FadeIn(mapping), Write(eg[0])) 154 | self.play(ReplacementTransform(mapping, eg[1])) 155 | self.play(ReplacementTransform(eg[1], eg[2:])) 156 | # self.play(FadeOut(eg[2:])) 157 | self.play(z.move_to, path.points[0]) 158 | 159 | z_tracker_copy = z_tracker.copy().clear_updaters() 160 | w_tracker_copy = w_tracker.copy().clear_updaters() 161 | z_angle_value_copy = z_angle_value.copy().clear_updaters() 162 | w_angle_value_copy = w_angle_value.copy().clear_updaters() 163 | 164 | self.play(Transform(z_tracker_copy, eg[2].copy())) 165 | self.play(Transform(z_tracker_copy, w_tracker_copy)) 166 | 167 | self.play(Transform(z_angle_value_copy, eg[3].copy())) 168 | self.play(Transform(z_angle_value_copy, w_angle_value_copy)) 169 | 170 | self.remove(z_tracker_copy, z_angle_value_copy) 171 | 172 | self.play(MoveAlongPath(z, path, rate_func=linear), run_time=5) 173 | self.wait() 174 | tempgrp = VGroup(z_trace, w_trace, eg[0], z_angle, w_angle) # , z_angle_value, w_angle_value) 175 | eqn = TexMobject("z", "\\,\\,=w").next_to(trans, direction=UP, buff=0.1) 176 | power = DecimalNumber(w_freq, num_decimal_places=0).scale(.5).next_to(eqn[0], direction=UR, buff=0.05) 177 | mapping = VGroup(eqn[0:2], power).scale(.75) 178 | 179 | z_angle.clear_updaters() 180 | w_angle.clear_updaters() 181 | self.play( 182 | *[FadeOut(mobj) for mobj in tempgrp], FadeOut(eg[2:]), FadeIn(mapping), 183 | *[ApplyMethod(i.scale, 0.000001) for i in [z_angle_value, w_angle_value]] 184 | ) 185 | 186 | ############################### 187 | 188 | roots = VGroup() 189 | dummy = Dot(zpc + RIGHT, fill_opacity=0) 190 | 191 | def kill_dups(roots): 192 | dups = [] 193 | for_check = True 194 | 195 | for i in range(len(roots)): 196 | a = roots[i].get_center() 197 | nth_dups = [] 198 | something_happened = False 199 | for j in range(len(roots)): 200 | 201 | if i != j: 202 | if j not in dups: 203 | b = roots[j].get_center() 204 | dist = np.linalg.norm(a - b) 205 | print(f"a is {a}") 206 | print(f"b is {b} and dist is {dist}") 207 | print() 208 | if dist < .5: 209 | # if for_check: 210 | print("##########yes##################") 211 | # print(b) 212 | if i not in dups: 213 | dups.append(i) 214 | something_happened = True 215 | dups.append(j) 216 | for_check = False 217 | if something_happened: 218 | dups.append(1000000) 219 | 220 | print(dups) 221 | nth_dups = [] 222 | mark = 0 223 | for index, dup in enumerate(dups): 224 | if dup > 10000: 225 | nth_dups.append(list(range(mark, index))) 226 | mark = index 227 | dups.remove(dup) 228 | print(nth_dups) 229 | new_roots = VGroup() 230 | for dup in nth_dups: 231 | new_roots.add(roots[dup[0]]) 232 | 233 | return new_roots 234 | 235 | def update_dummy(dummy, dt): 236 | if w_angle_value.get_value() > -0.2 and w_angle_value.get_value() < 0.25: # or (location > 0.998 and location < 1): # or (location > 0.997 and location < 1): # or (location > 0.995 and location < 1): 237 | # print(w_angle_value.get_value()) 238 | mark = Dot(z.get_center(), color=PURPLE) 239 | roots.add(mark) 240 | dummy.become(mark) 241 | 242 | dummy.add_updater(update_dummy) 243 | 244 | self.add(dummy) 245 | 246 | path = Circle().move_to(zpc) 247 | 248 | self.play(z.move_to, path.points[0]) 249 | equals_one = TexMobject("=1", "1") 250 | equals_one[0].move_to(eqn[-1]).scale(0.75) 251 | equals_one[1].next_to(wpc + RIGHT, direction=UR, buff=0.1) 252 | 253 | self.play(Transform(eqn[1], equals_one[0]), FadeIn(equals_one[1])) 254 | # self.play(z.shift, UP) 255 | 256 | w_freqs = range(2, 7) 257 | # check = False 258 | for w_freq in w_freqs: 259 | self.play(Indicate(mapping)) 260 | self.play(power.set_value, w_freq) 261 | self.play(Flash(power)) 262 | self.play(MoveAlongPath(z, path, rate_func=linear), run_time=10) 263 | self.wait() 264 | # print(len(roots)) 265 | # for root in roots: 266 | # print(root.get_center()) 267 | # roots = kill_dups(roots) 268 | # print(len(roots)) 269 | # print() 270 | self.add(roots) 271 | 272 | # self.play(Indicate(roots)) 273 | self.wait() 274 | ngon = VMobject(stroke_width=1, color=YELLOW).set_points_as_corners([*[root.get_center() for root in roots], roots[0].get_center()]) 275 | self.play(ShowCreation(ngon)) 276 | self.wait() 277 | self.play(FadeOut(roots), FadeOut(ngon)) 278 | roots = VGroup() 279 | # check = True 280 | -------------------------------------------------------------------------------- /ComplexTranforms.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | from cmath import phase, polar 3 | import itertools 4 | 5 | 6 | class TransSymbol(VMobject): 7 | def __init__(self, text=None, text_direction=UP, *args, **kwargs): 8 | VMobject.__init__(self) 9 | path_pts = [] 10 | x_samps = np.arange(-.95, 0, .125) 11 | 12 | for x, i in zip(x_samps, range(len(x_samps))): 13 | if i % 2 == 0: 14 | path_pts.append(np.array([x, -.25 * x, 0])) 15 | if i % 2 != 0: 16 | path_pts.append(np.array([x, .25 * x, 0])) 17 | 18 | self.set_points_as_corners(path_pts).make_smooth() 19 | head = VMobject(fill_opacity=1, color=WHITE)\ 20 | .set_points_as_corners([UP, RIGHT, DOWN, UP]).scale(.0725).move_to(self.points[-1]).shift(UP * .025 + RIGHT * .035) 21 | self.add(head) 22 | self.move_to(ORIGIN) 23 | # if text is not None: 24 | # tex = TexMobject(text) 25 | # tex.next_to(self, direction=UP) 26 | # tex_length = np.linalg.norm(tex.get_left() - tex.get_right()) 27 | # if > np.linalg.norm(self.get_left() - self.get_right()): 28 | # tex.scale(abdsnp.linalg.norm(tex.get_left() - tex.get_right()) - np.linalg.norm(self.get_left() - self.get_right())) 29 | # self.add(tex) 30 | # return path 31 | 32 | 33 | class Intro(GraphScene): 34 | CONFIG = { 35 | "x_min": -1, 36 | "x_max": 10, 37 | "x_axis_width": 9, 38 | "x_tick_frequency": 1, 39 | "x_leftmost_tick": None, # Change if different from x_min 40 | "x_labeled_nums": None, 41 | "x_axis_label": "$x$", 42 | "y_min": -1, 43 | "y_max": 10, 44 | "y_axis_height": 6, 45 | "y_tick_frequency": 1, 46 | "y_bottom_tick": None, # Change if different from y_min 47 | "y_labeled_nums": None, 48 | "y_axis_label": "$y$", 49 | "axes_color": GREY, 50 | "graph_origin": 2.5 * DOWN + 4 * LEFT, 51 | "exclude_zero_label": True, 52 | "default_graph_colors": [BLUE, GREEN, YELLOW], 53 | "default_derivative_color": GREEN, 54 | "default_input_color": YELLOW, 55 | "default_riemann_start_color": BLUE, 56 | "default_riemann_end_color": GREEN, 57 | "area_opacity": 0.8, 58 | "num_rects": 50, 59 | "x_axis_label_color": WHITE, 60 | "y_axis_label_color": WHITE 61 | } 62 | 63 | def construct(self): 64 | self.setup_axes() 65 | 66 | def func(t): 67 | return .05 * t**3 - .55 * t**2 + t + 7 68 | graph = self.get_graph(func) 69 | 70 | self.add(graph) 71 | 72 | def get_mid_rects(graph, a=1, b=9, dx=0.1, start_color=RED, end_color=PURPLE, op=1): 73 | x_samps = np.arange(a, b, dx) 74 | go = self.graph_origin 75 | graph_dx = abs(self.coords_to_point(dx, 0)[0] - go[0]) 76 | colors = color_gradient([start_color, end_color], len(x_samps)) 77 | return VGroup( 78 | *[ 79 | 80 | Rectangle( 81 | height=self.input_to_graph_point((x_samps[_] + x_samps[_ + 1]) / 2, graph)[1] - go[1], 82 | width=graph_dx, 83 | fill_opacity=op, 84 | fill_color=color, 85 | stroke_width=2, 86 | stroke_color=YELLOW 87 | ) 88 | .align_to(self.coords_to_point(x_samps[_], 0), direction=DL) 89 | for _, color in zip(range(len(x_samps) - 1), colors) 90 | ] 91 | ) 92 | 93 | def get_dotted_rects(graph, a=1, b=9, dx=0.1, start_color=RED, end_color=PURPLE, op=1): 94 | c2p = self.coords_to_point 95 | i2p = self.input_to_graph_point 96 | x_samps = np.arange(a, b, dx) 97 | # go = self.graph_origin 98 | # graph_dx = abs(self.coords_to_point(dx, 0)[0] - go[0]) 99 | colors = color_gradient([start_color, end_color], len(x_samps)) 100 | rects = VGroup() 101 | for _, color in zip(range(len(x_samps) - 1), colors): 102 | pts = [ 103 | c2p(x_samps[_], 0), 104 | c2p(x_samps[_ + 1], 0), 105 | i2p(x_samps[_ + 1], graph), 106 | np.array([c2p(x_samps[_], 0)[0], i2p(x_samps[_ + 1], graph)[1], 0]), 107 | c2p(x_samps[_], 0) 108 | ] 109 | rect = VGroup() 110 | for i in range(len(pts) - 1): 111 | rect.add(DashedLine(pts[i], pts[i + 1])) 112 | rect.align_to(self.coords_to_point(x_samps[_], 0), direction=DL) 113 | rects.add(rect) 114 | 115 | return rects 116 | 117 | rects = [get_mid_rects( 118 | graph, 119 | a=1, 120 | b=9, 121 | dx=_, 122 | start_color=RED, 123 | end_color=ORANGE, 124 | # fill_opacity=0 125 | op=0 126 | ) for _ in np.arange(2, 1, -0.5)] # np.arange(2, 0, -0.25)] 127 | self.add(rects[0]) 128 | for i in range(len(rects) - 1): 129 | self.play(ReplacementTransform(rects[i], rects[i + 1])) 130 | # self.play(FadeOut(rects[-1])) 131 | 132 | rects = [get_dotted_rects( 133 | graph, 134 | a=1, 135 | b=9, 136 | dx=_, 137 | start_color=RED, 138 | end_color=ORANGE, 139 | # fill_opacity=0 140 | op=0 141 | ) for _ in np.arange(2, 1, -0.5)] 142 | 143 | self.add(rects[0]) 144 | for i in range(len(rects) - 1): 145 | self.play(ReplacementTransform(rects[i], rects[i + 1])) 146 | 147 | self.wait() 148 | 149 | self.play(*[FadeOut(_) for _ in self.mobjects]) 150 | # x_line, y_line = [ 151 | # NumberLine( 152 | # x_min=-2.5, 153 | # x_max=2.5, 154 | # numbers_with_elongated_ticks=[], 155 | # # tip_width=0.2, 156 | # # include_tip=True, 157 | # ).move_to(j * 3.5).move_to(j * 3.5) # .add_tip(at_start=True, tip_length=0.2) 158 | # for i, j in zip(range(2), [LEFT, RIGHT]) 159 | # ] 160 | z_plane, w_plane = [ 161 | Axes(x_min=-2.5, x_max=2.5, y_min=-2.5, y_max=2.5,).move_to(j * 3.5).save_state() 162 | for _, j in zip(range(2), [LEFT, RIGHT]) 163 | ] 164 | x_line, y_line = [_.x_axis.copy() for _ in [z_plane, w_plane]] 165 | temp = VGroup(x_line, TransSymbol(), y_line) 166 | self.play(FadeIn(temp)) 167 | 168 | z_plane.stretch(0, 1) 169 | w_plane.stretch(0, 1) 170 | # self.play(*[ReplacementTransform(i, j) for i, j in zip([x_line, y_line], [z_plane, w_plane])]) 171 | self.play(*[_.restore for _ in [z_plane, w_plane]]) 172 | self.wait() 173 | 174 | 175 | class CTransform(MovingCameraScene): 176 | CONFIG = { 177 | "number_plane_kwargs": { 178 | "x_min": -2.5, 179 | "x_max": 2.5, 180 | "y_min": -2.5, 181 | "y_max": 2.5, 182 | "x_Line_frequency": 1, 183 | "y_Line_frequency": 1, 184 | }, 185 | "axes_kwargs": { 186 | "x_min": -4, 187 | "x_max": 4, 188 | "y_min": -4, 189 | "y_max": 4, 190 | "x_Line_frequency": 1, 191 | "y_Line_frequency": 1, 192 | }, 193 | "z_origin": 3 * UL + 5 * LEFT, 194 | "w_origin": 3 * UR + 1.0 * RIGHT, 195 | # "temp_origin": 4 * DR + 0 * RIGHT + DOWN, 196 | "integtal_origin": 3 * DR + 4 * DOWN + RIGHT * 8, 197 | # "temp_origin": 3 * DOWN + 1.5 * RIGHT, 198 | # "integtal_origin": 3 * DR + 3 * DOWN + RIGHT * 2, 199 | # "w_origin": ORIGIN, 200 | # "temp_origin": 5.5 * DOWN 201 | } 202 | 203 | def z_dec(self, mobj): 204 | for m in mobj: 205 | m.move_to(self.z_origin) 206 | 207 | def w_dec(self, mobj): 208 | for m in mobj: 209 | m.move_to(self.w_origin) 210 | 211 | def int_dec(self, mobj): 212 | for m in mobj: 213 | m.move_to(self.temp_origin) 214 | 215 | def construct(self): 216 | # self.integral_intro() 217 | ip = self.z_dec 218 | op = self.w_dec 219 | 220 | zo = self.z_origin 221 | wo = self.w_origin 222 | temp_o = self.temp_origin = midpoint(zo, wo) + DOWN * 5.5 223 | int_o = self.integtal_origin 224 | colors = itertools.cycle(["#FFAA1D", "#FFF700", "#87FF2A", "#5DADEC", "#FFCBA4", "#DB91EF", "#6F2DA8"]) 225 | 226 | z_plane, w_plane = [Axes(**self.number_plane_kwargs) for _ in range(2)] 227 | 228 | rad = 2.25 229 | contour = Circle(radius=rad) 230 | 231 | # self.play(Write(z_plane)) 232 | z_plane.move_to(LEFT * 3.5) 233 | 234 | trans = TransSymbol() 235 | # trans_tex = TexMobject("w=1/z").scale(0.75).next_to(trans, direction=UP) 236 | 237 | w_plane.move_to(RIGHT * 3.5) 238 | self.add(z_plane, trans, w_plane) 239 | 240 | trans_tex = self.show_example(trans) 241 | trans_arrow = VGroup(trans, trans_tex) 242 | self.play(*[FadeOut(_) for _ in [w_plane, trans_arrow]]) 243 | self.explain_division(z_plane, w_plane) 244 | trans_tex = TexMobject("w=1/z").scale(0.5).next_to(trans, direction=UP) 245 | 246 | # # self.explain_inversion() 247 | 248 | # plane_grp = VGroup(z_plane, trans_arrow, w_plane) 249 | # # self.play() 250 | # z_plane_axes, w_plane_axes, int_plane = [Axes(**self.axes_kwargs) for _ in range(3)] 251 | # ip([z_plane_axes]) 252 | # op([w_plane_axes]) 253 | # self.play( 254 | # self.camera_frame.scale, 2, 255 | # # plane_grp.shift, UP * 3, 256 | # z_plane.become, z_plane_axes, 257 | # # z_plane.scale, rad, 258 | # trans.move_to, midpoint(zo, wo), 259 | # # trans.rotate, -PI / 2, 260 | # trans.scale, rad / 2, 261 | # trans_tex.next_to, midpoint(zo, wo), 262 | # trans_tex.scale, rad, 263 | # w_plane.become, w_plane_axes, 264 | # # w_plane.scale, rad, 265 | # ) 266 | # # self.play(plane_grp.arrange_submobjects) 267 | # ip([z_plane, contour]) 268 | # op([w_plane]) 269 | # self.int_dec([int_plane]) 270 | 271 | # self.add(z_plane, w_plane, int_plane) 272 | # self.add(contour) 273 | 274 | # for i in range(6, 7): 275 | # step = PI / i 276 | # deltas = VGroup() 277 | # preimg_pts = [rad * rotate_vector(RIGHT, step / 2)] 278 | 279 | # for _ in np.arange(0, 2 * PI, step): 280 | # deltas.add(Line(rad * rotate_vector(RIGHT, _), rad * rotate_vector(RIGHT, _ + step), color=next(colors), stroke_width=3)) # .add_tip(tip_length=0.2)) 281 | # if _ != 0: 282 | # preimg_pts.append(rotate_vector(preimg_pts[0], _)) 283 | 284 | # ip([deltas]) 285 | 286 | # self.add(deltas) 287 | 288 | # def func(x): 289 | # if x != 0: 290 | # return rad**2 / x 291 | # else: 292 | # return 0 293 | 294 | # image = contour.copy().set_color(YELLOW).move_to(ORIGIN).apply_function(lambda point: complex_to_R3(func(R3_to_complex(point))) + wo) 295 | # self.play( 296 | # TransformFromCopy(contour, image) 297 | # ) 298 | # deltas_copy = deltas.copy() 299 | 300 | # integral = VGroup(*[TexMobject(f"w_{k} \\Delta_{k}+") for k in range(len(deltas))]).arrange_submobjects() 301 | # # self.add(integral) 302 | # for _, z in zip(range(len(deltas_copy)), preimg_pts): 303 | # self.play(ApplyMethod(deltas_copy[_].shift, temp_o - deltas_copy[_].points[0])) 304 | 305 | # w = complex_to_R3( 306 | # 1 / rad * func(R3_to_complex(z)) * R3_to_complex(deltas_copy[_].get_vector()) 307 | # ) 308 | # w += temp_o[0] * RIGHT + temp_o[1] * UP 309 | 310 | # img = Line(temp_o, w, color=deltas_copy[_].get_color(), stroke_width=3) # .add_tip(tip_length=0.2) 311 | 312 | # self.play(deltas_copy[_].become, img) 313 | # if _ != 0: 314 | # self.play(deltas_copy[_].shift, deltas_copy[_ - 1].points[-1] - temp_o) 315 | # else: 316 | # self.play(deltas_copy[0].shift, int_o - deltas_copy[0].points[0]) 317 | # self.add(Dot(int_o)) 318 | 319 | # self.play(*[FadeOut(_) for _ in [deltas_copy, deltas]]) 320 | 321 | def integral_intro(self): 322 | axes = Axes(x_min=-1, 323 | x_max=10, 324 | y_min=-1, 325 | y_max=10,).shift(2.5 * DOWN + 4 * LEFT) 326 | self.play(ShowCreation(axes)) 327 | tex1 = TexMobject( 328 | "\\int", 329 | "_K", 330 | "f(z)dz \\,\\,=", 331 | "\\,\\,?", 332 | "\\sum_{i=0}^n f(z_i) \\Delta_i" 333 | ).scale(1.5) 334 | # tex1[4].next_to(tex1[2]) 335 | # self.play(Write(tex1[0]), Write(tex1[2:4])) 336 | # self.play(ReplacementTransform(tex1[3], tex1[4])) 337 | # self.play(FadeOut(tex1)) 338 | 339 | def show_example(self, trans): 340 | zpc = LEFT * 3.5 341 | wpc = RIGHT * 3.5 342 | w_freq = 2 343 | z = Dot(zpc + UP * 0.75) 344 | z_tracker = Line(zpc, z.get_center(), stroke_width=5, color=RED).add_updater(lambda x: x.put_start_and_end_on(zpc, z.get_center() + UP * .0001)) 345 | # self.add(z, z_tracker) 346 | ztl = z_tracker.get_length() 347 | 348 | w_tracker = Line(wpc, wpc + RIGHT, stroke_width=0, color=YELLOW) 349 | if ztl != 0: 350 | w_tracker.scale(ztl**w_freq, about_point=wpc).set_angle(w_freq * z_tracker.get_angle()) 351 | else: 352 | w_tracker.scale(0.02, about_point=wpc) 353 | 354 | def update_w_tracker(w_tracker, dt): 355 | ztl = z_tracker.get_length() 356 | new_w_tracker = Line(wpc, wpc + RIGHT, stroke_width=5, color=YELLOW) 357 | if ztl != 0: 358 | new_w_tracker.scale(1 / ztl, about_point=wpc).set_angle(- z_tracker.get_angle()) 359 | else: 360 | new_w_tracker.scale(0.02, about_point=wpc) 361 | w_tracker.become(new_w_tracker) 362 | 363 | w_tracker.add_updater(update_w_tracker) 364 | w = Dot(w_tracker.points[-1]).add_updater(lambda x: x.move_to(w_tracker.points[-1])) 365 | 366 | # ############################ 367 | 368 | z_trace = VMobject() 369 | z_trace.set_points_as_corners([z.get_center(), z.get_center() + UP * 0.01]) 370 | 371 | def update_z_trace(z_trace): 372 | previous_z_trace = z_trace.copy() 373 | previous_z_trace.add_points_as_corners([z.get_center()]) 374 | z_trace.become(previous_z_trace) 375 | z_trace.add_updater(update_z_trace) 376 | self.add(z_trace) 377 | 378 | w_trace = VMobject() 379 | w_trace.set_points_as_corners([w.get_center(), w.get_center() + UP * 0.01]) 380 | 381 | def update_w_trace(w_trace): 382 | previous_w_trace = w_trace.copy() 383 | previous_w_trace.add_points_as_corners([w.get_center()]) 384 | w_trace.become(previous_w_trace) 385 | w_trace.add_updater(update_w_trace) 386 | self.add(w_trace) 387 | 388 | z_angle = Arc(z_tracker.get_angle(), radius=.25, arc_center=zpc) 389 | 390 | def update_z_angle(z_angle, dt): 391 | new_z_angle = Arc(start_angle=0, angle=z_tracker.get_angle(), radius=.25, arc_center=zpc) 392 | z_angle.become(new_z_angle) 393 | 394 | z_angle.add_updater(update_z_angle) 395 | z_angle_value = DecimalNumber(start_angle=0, angle=z_tracker.get_angle() * (180 / PI)).scale(.75)\ 396 | .add_updater(lambda x: x.next_to(z_angle, direction=UR, buff=0.1)).add_updater(lambda x: x.set_value(z_tracker.get_angle() * (180 / PI))) 397 | 398 | w_angle = Arc(start_angle=0, angle=w_tracker.get_angle(), radius=.25, arc_center=wpc) 399 | 400 | def update_w_angle(w_angle, dt): 401 | new_w_angle = Arc(start_angle=0, angle=w_tracker.get_angle(), radius=.25, arc_center=wpc) 402 | w_angle.become(new_w_angle) 403 | 404 | w_angle.add_updater(update_w_angle) 405 | w_angle_value = DecimalNumber(w_tracker.get_angle() * (180 / PI)).scale(.75)\ 406 | .add_updater(lambda x: x.next_to(w_angle, direction=UR, buff=0.1)).add_updater(lambda x: x.set_value(w_tracker.get_angle() * (180 / PI))) 407 | 408 | # self.add(z_angle, w_angle, z_angle_value, w_angle_value) 409 | path = Circle(radius=0.75).move_to(zpc).rotate(PI / 2) 410 | mobjects = VGroup(z, z_tracker, w_tracker, w, z_angle, w_angle, z_angle_value, w_angle_value) 411 | self.play(*[FadeIn(mobj) for mobj in mobjects]) 412 | self.add(mobjects) 413 | 414 | eqn = TexMobject("w=", "1/z").next_to(trans, direction=UP, buff=0.1) 415 | mapping = VGroup(eqn).scale(.75) 416 | 417 | eg = TexMobject("\\text{For Example}", "w=\\frac{1}{z}e^{i(-\\theta)}", "|w| = 1/|z|", "Arg(w) = -Arg(z)") 418 | eg[0].to_edge(UP) 419 | eg[1].move_to(mapping.get_center() + UP * 0.25).scale(.75).save_state() 420 | eg[2].move_to(mapping).scale(.5) 421 | eg[3].next_to(eg[2], direction=UP, buff=0.1).scale(.5) 422 | 423 | self.play(FadeIn(mapping), Write(eg[0])) 424 | self.play(ReplacementTransform(mapping, eg[1])) 425 | self.play(ReplacementTransform(eg[1], eg[2:])) 426 | 427 | z_tracker_copy = z_tracker.copy().clear_updaters() 428 | w_tracker_copy = w_tracker.copy().clear_updaters() 429 | z_angle_value_copy = z_angle_value.copy().clear_updaters() 430 | w_angle_value_copy = w_angle_value.copy().clear_updaters() 431 | 432 | self.play(Transform(z_tracker_copy, eg[2].copy())) 433 | self.play(Transform(z_tracker_copy, w_tracker_copy)) 434 | 435 | self.play(Transform(z_angle_value_copy, eg[3].copy())) 436 | self.play(Transform(z_angle_value_copy, w_angle_value_copy)) 437 | 438 | self.remove(z_tracker_copy, z_angle_value_copy) 439 | 440 | # self.play(MoveAlongPath(z, path, rate_func=linear), run_time=5) 441 | self.wait() 442 | tempgrp = VGroup(z_trace, w_trace, eg[0], z_angle, w_angle, z, w, z_tracker, w_tracker) 443 | eqn = TexMobject("w\\, =\\, 1 / z").next_to(trans, direction=UP, buff=0.1).scale(0.75) 444 | # power = DecimalNumber(w_freq, num_decimal_places=0).scale(.5).next_to(eqn[0], direction=UR, buff=0.05) 445 | # mapping = VGroup(eqn[0:2], power).scale(.75) 446 | 447 | z_angle.clear_updaters() 448 | w_angle.clear_updaters() 449 | self.play( 450 | *[FadeOut(mobj) for mobj in tempgrp], FadeOut(eg[2:]), FadeIn(eqn), 451 | *[ApplyMethod(i.scale, 0.000001) for i in [z_angle_value, w_angle_value]] 452 | ) 453 | return eqn 454 | # def explain_inversion(self): 455 | 456 | def explain_division(self, z_plane, w_plane): 457 | self.camera_frame.save_state() 458 | self.play( 459 | self.camera_frame.move_to, z_plane.get_center(), 460 | self.camera_frame.scale, 0.75 461 | ) 462 | # contour = 463 | -------------------------------------------------------------------------------- /CycloidArea.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class MeasureDistance(VGroup): 5 | CONFIG = { 6 | "color": RED_B, 7 | "buff": 0.3, 8 | "lateral": 0.3, 9 | "invert": False, 10 | "dashed_segment_length": 0.09, 11 | "dashed": True, 12 | "ang_arrows": 30 * DEGREES, 13 | "size_arrows": 0.2, 14 | "stroke": 2.4, 15 | } 16 | 17 | def __init__(self, mob, **kwargs): 18 | VGroup.__init__(self, **kwargs) 19 | if self.dashed == True: 20 | medicion = DashedLine(ORIGIN, mob.get_length() * RIGHT, dashed_segment_length=self.dashed_segment_length).set_color(self.color) 21 | else: 22 | medicion = Line(ORIGIN, mob.get_length() * RIGHT) 23 | 24 | medicion.set_stroke(None, self.stroke) 25 | 26 | pre_medicion = Line(ORIGIN, self.lateral * RIGHT).rotate(PI / 2).set_stroke(None, self.stroke) 27 | pos_medicion = pre_medicion.copy() 28 | 29 | pre_medicion.move_to(medicion.get_start()) 30 | pos_medicion.move_to(medicion.get_end()) 31 | 32 | angulo = mob.get_angle() 33 | matriz_rotacion = rotation_matrix(PI / 2, OUT) 34 | vector_unitario = mob.get_unit_vector() 35 | direccion = np.matmul(matriz_rotacion, vector_unitario) 36 | self.direccion = direccion 37 | 38 | self.add(medicion, pre_medicion, pos_medicion) 39 | self.rotate(angulo) 40 | self.move_to(mob) 41 | 42 | if self.invert == True: 43 | self.shift(-direccion * self.buff) 44 | else: 45 | self.shift(direccion * self.buff) 46 | self.set_color(self.color) 47 | self.tip_point_index = -np.argmin(self.get_all_points()[-1, :]) 48 | 49 | def add_tips(self): 50 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 51 | vector_unitario = linea_referencia.get_unit_vector() 52 | 53 | punto_final1 = self[0][-1].get_end() 54 | punto_inicial1 = punto_final1 - vector_unitario * self.size_arrows 55 | 56 | punto_inicial2 = self[0][0].get_start() 57 | punto_final2 = punto_inicial2 + vector_unitario * self.size_arrows 58 | 59 | lin1_1 = Line(punto_inicial1, punto_final1).set_color(self[0].get_color()).set_stroke(None, self.stroke) 60 | lin1_2 = lin1_1.copy() 61 | lin2_1 = Line(punto_inicial2, punto_final2).set_color(self[0].get_color()).set_stroke(None, self.stroke) 62 | lin2_2 = lin2_1.copy() 63 | 64 | lin1_1.rotate(self.ang_arrows, about_point=punto_final1, about_edge=punto_final1) 65 | lin1_2.rotate(-self.ang_arrows, about_point=punto_final1, about_edge=punto_final1) 66 | 67 | lin2_1.rotate(self.ang_arrows, about_point=punto_inicial2, about_edge=punto_inicial2) 68 | lin2_2.rotate(-self.ang_arrows, about_point=punto_inicial2, about_edge=punto_inicial2) 69 | 70 | return self.add(lin1_1, lin1_2, lin2_1, lin2_2) 71 | 72 | def add_tex(self, text, scale=1, buff=-1, **moreargs): 73 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 74 | texto = TexMobject(text, **moreargs) 75 | ancho = texto.get_height() / 2 76 | texto.rotate(linea_referencia.get_angle()).scale(scale).move_to(self) 77 | texto.shift(self.direccion * (buff + 1) * ancho) 78 | return self.add(texto) 79 | 80 | def add_text(self, text, scale=1, buff=0.1, **moreargs): 81 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 82 | texto = TextMobject(text, **moreargs) 83 | ancho = texto.get_height() / 2 84 | texto.rotate(linea_referencia.get_angle()).scale(scale).move_to(self) 85 | texto.shift(self.direccion * (buff + 1) * ancho) 86 | return self.add(texto) 87 | 88 | def add_size(self, text, scale=1, buff=0.1, **moreargs): 89 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 90 | texto = TextMobject(text, **moreargs) 91 | ancho = texto.get_height() / 2 92 | texto.rotate(linea_referencia.get_angle()) 93 | texto.shift(self.direccion * (buff + 1) * ancho) 94 | return self.add(texto) 95 | 96 | def add_letter(self, text, scale=1, buff=0.1, **moreargs): 97 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 98 | texto = TexMobject(text, **moreargs).scale(scale).move_to(self) 99 | ancho = texto.get_height() / 2 100 | texto.shift(self.direccion * (buff + 1) * ancho) 101 | return self.add(texto) 102 | 103 | def get_text(self, text, scale=1, buff=0.1, invert_dir=False, invert_texto=False, remove_rot=False, **moreargs): 104 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 105 | texto = TextMobject(text, **moreargs) 106 | ancho = texto.get_height() / 2 107 | if invert_texto: 108 | inv = PI 109 | else: 110 | inv = 0 111 | if remove_rot: 112 | texto.scale(scale).move_to(self) 113 | else: 114 | texto.rotate(linea_referencia.get_angle()).scale(scale).move_to(self) 115 | texto.rotate(inv) 116 | if invert_dir: 117 | inv = -1 118 | else: 119 | inv = 1 120 | texto.shift(self.direccion * (buff + 1) * ancho * inv) 121 | return texto 122 | 123 | def get_tex(self, tex, scale=1, buff=1, invert_dir=False, invert_texto=False, remove_rot=True, **moreargs): 124 | linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) 125 | texto = TexMobject(tex, **moreargs) 126 | ancho = texto.get_height() / 2 127 | if invert_texto: 128 | inv = PI 129 | else: 130 | inv = 0 131 | if remove_rot: 132 | texto.scale(scale).move_to(self) 133 | else: 134 | texto.rotate(linea_referencia.get_angle()).scale(scale).move_to(self) 135 | texto.rotate(inv) 136 | if invert_dir: 137 | inv = -1 138 | else: 139 | inv = 1 140 | texto.shift(self.direccion * (buff + 1) * ancho) 141 | return texto 142 | 143 | 144 | class CycCirc(MovingCameraScene): 145 | def construct(self): 146 | 147 | self.camera_frame.move_to(UP).scale(0.60) 148 | a = 1 149 | k = 1 150 | nol = 1 151 | parameter = np.arange(np.arccos(a), 2 * nol * PI - np.arccos(a), 0.05) 152 | 153 | cycloid = VMobject() 154 | cycloid_pts = [] 155 | 156 | for t in parameter: 157 | x = a * t - k * np.sin(t) 158 | y = a - k * np.cos(t) 159 | cycloid_pts.append(np.array([x, y, 0])) # equation of cycloid 160 | cycloid.set_points_as_corners(cycloid_pts) 161 | 162 | disp = cycloid.get_top()[0] 163 | cycloid.shift(LEFT * disp) 164 | 165 | mid_line = rad = cycloid.get_top()[1] / 2 166 | 167 | circle = Circle(radius=mid_line, color=RED).shift(mid_line * UP).flip(axis=LEFT) 168 | # self.add(circle) 169 | circle_copy = circle.copy().move_to(cycloid.points[0]).shift(UP * rad) 170 | dot = Dot(circle_copy.get_bottom()).scale(0.5) 171 | circle_copy.add(dot) 172 | 173 | cyc_wait_time = 5 174 | cyc_step = 2 * rad * PI / (cyc_wait_time * self.camera.frame_rate) 175 | cyc_angle_step = 2 * PI / (cyc_wait_time * self.camera.frame_rate) 176 | 177 | def update_circ(circ, dt): 178 | circ.shift(cyc_step * RIGHT) 179 | circ.rotate(-cyc_angle_step) 180 | main_path = VMobject(stroke_width=4, color=WHITE) 181 | main_path.set_points_as_corners([dot.get_center(), dot.get_center() + UP * 0.01]) 182 | 183 | def update_main_path(main_path): 184 | previus_path = main_path.copy() 185 | previus_path.add_points_as_corners([dot.get_center()]) 186 | main_path.become(previus_path) 187 | 188 | circle_copy.add_updater(update_circ) 189 | main_path.add_updater(update_main_path) 190 | self.add(circle_copy, main_path) 191 | 192 | self.wait(cyc_wait_time) 193 | circle_copy.clear_updaters() 194 | self.add(cycloid) 195 | self.remove(main_path) 196 | self.play(self.camera_frame.scale, 0.85) 197 | 198 | self.play(FadeOut(circle_copy)) 199 | self.wait() 200 | area = cycloid.copy().add(Line(cycloid.points[0], cycloid[-1], stroke_width=0.001)) 201 | area.set_fill(color=YELLOW, opacity=0.75) 202 | obj = TexMobject("\\text{Area} = ?").move_to(area) 203 | self.play(AnimationGroup(FadeIn(area), Write(obj)), lag_ratio=0.5) 204 | self.wait() 205 | self.play(FadeOut(area), FadeOut(obj), FadeIn(circle_copy)) 206 | self.wait() 207 | self.play(ReplacementTransform(circle_copy, circle)) 208 | self.wait() 209 | circle.save_state() 210 | self.play(circle.set_fill, {"opacity": 0.5, "color": YELLOW}) 211 | circ_area = TexMobject("\\pi r^2").move_to(circle) 212 | self.play(Write(circ_area)) 213 | self.wait() 214 | self.play( 215 | # circ_area.next_to, circle.get_bottom(), {"direction": DOWN}, 216 | circle.restore, 217 | FadeOut(circ_area) 218 | ) 219 | self.wait() 220 | # self.play(FadeOut(circ_area)) 221 | # ####################################################### 222 | 223 | def get_cyc_pt(y): 224 | t = np.arccos((a - y) / k) 225 | x = a * t - k * np.sin(t) - disp 226 | return np.array([x, y, 0]) 227 | 228 | semi_circle = ArcBetweenPoints(circle.get_bottom(), circle.get_top(), angle=-PI) 229 | # self.add(semi_circle) 230 | 231 | def get_circ_pt(y): 232 | return np.array([-(1 - (y - 1)**2)**0.5, y, 0]) 233 | 234 | divisions = VGroup() 235 | n = 5 236 | area_color = YELLOW 237 | area_opacity = 1 238 | for n in [5, 10, 30, 50, 100, 500, 1000]: 239 | step = 2 * rad / n 240 | rects = VGroup( 241 | *[ 242 | Rectangle( 243 | width=abs( 244 | np.linalg.norm(get_cyc_pt(i) - get_circ_pt(i)) 245 | ), 246 | height=mid_line * 2 / n, 247 | stroke_width=1, 248 | stroke_color=area_color, 249 | stroke_opacity=area_opacity 250 | ) 251 | for i in np.arange(0, 2 * rad, step) 252 | ]) 253 | 254 | rects.arrange_submobjects(direction=UP, buff=0.0000001) 255 | rects.align_to(ORIGIN, direction=DOWN).align_to(cycloid.points[0], direction=LEFT) 256 | 257 | for i in range(len(rects)): 258 | rects[i].align_to(cycloid.points[0], direction=LEFT) 259 | 260 | rects.save_state() 261 | for i in range(len(rects)): 262 | mid = midpoint(get_cyc_pt(rects[i].get_center()[1]), get_circ_pt(rects[i].get_center()[1])) 263 | rects[i].move_to(mid) 264 | 265 | divisions.add(rects) 266 | 267 | self.play(ShowCreation(divisions[0])) 268 | for i in range(len(divisions) - 1): 269 | self.play(ReplacementTransform(divisions[i], divisions[i + 1])) 270 | # rects.restore() 271 | self.play(divisions[-1].restore) 272 | self.wait() 273 | 274 | hyp = DashedLine(ORIGIN, np.array([cycloid.points[0][0], 2 * rad, 0]), color=TEAL) 275 | self.play(ShowCreation(hyp)) 276 | 277 | self.wait() 278 | 279 | tri = VMobject(fill_opacity=area_opacity, fill_color=area_color, stroke_width=0.1)\ 280 | .set_points_as_corners([ORIGIN, cycloid.points[0], np.array([cycloid.points[0][0], 2 * rad, 0])]) 281 | self.play(FadeOut(rects), FadeIn(tri)) 282 | self.wait() 283 | temp = VGroup(cycloid, circle) 284 | 285 | base = Line(ORIGIN, cycloid.points[0]) 286 | base_measure = MeasureDistance(base, size_arrows=0.1, lateral=0.2).add_tips() 287 | base_text = TexMobject("\\dfrac{2 \\pi r}{2}").scale(0.5).next_to(base_measure, direction=DOWN, buff=SMALL_BUFF) 288 | 289 | height = Line(cycloid.points[0], np.array([cycloid.points[0][0], 2 * rad, 0])) 290 | height_measure = MeasureDistance(height, size_arrows=0.1, lateral=0.2).add_tips().shift(RIGHT * 0.15) 291 | height_text = TexMobject("2 r").scale(0.5).next_to(height_measure, direction=LEFT, buff=0.005) 292 | 293 | self.play(ShowCreation(base_measure), Write(base_text)) 294 | self.play(ShowCreation(height_measure), Write(height_text)) 295 | self.play( 296 | self.camera_frame.scale, 1.25, 297 | # self.camera_frame.move_to, ORIGIN, 298 | FadeOut(cycloid), FadeOut(circle) 299 | ) 300 | 301 | eqn = TexMobject("=", "\\dfrac{1}{2}", "\\times", "\\pi r", "\\times", "2 r").next_to(tri) 302 | eqn2 = TexMobject("\\pi r^2").next_to(eqn[0]).shift(0.1 * UP) 303 | self.play(Write(eqn)) 304 | self.wait() 305 | self.play(ReplacementTransform(eqn[1:], eqn2)) 306 | self.wait() 307 | self.play( 308 | FadeIn(cycloid), FadeIn(circle), 309 | self.camera_frame.scale, 0.75, 310 | *[FadeOut(i) for i in [eqn[0], base_measure, base_text, height_measure, height_text, hyp]], 311 | eqn2.move_to, base_text.get_center() + UP * 0.5, 312 | eqn2.scale, 0.75 313 | ) 314 | 315 | self.play(FadeOut(tri), FadeIn(rects)) 316 | anims = [] 317 | for i in range(len(rects)): 318 | mid = midpoint(get_cyc_pt(rects[i].get_center()[1]), get_circ_pt(rects[i].get_center()[1])) 319 | anims.append(ApplyMethod(rects[i].move_to, mid)) 320 | 321 | self.play(*anims) 322 | self.wait() 323 | rects_copy = rects.copy() 324 | self.play( 325 | rects_copy.move_to, np.array([-rects.get_center()[0], rects.get_center()[1], 0]), 326 | rects_copy.flip, 327 | ) 328 | base_loc = np.array([-eqn2.get_center()[0], eqn2.get_center()[1], 0]) 329 | eqn2_copy = eqn2.copy().move_to(base_loc) 330 | self.play(Write(eqn2_copy)) 331 | self.wait() 332 | circ_area.scale(0.75).next_to(circle.get_bottom(), direction=DOWN).shift(0.1 * UP) 333 | self.play(FadeIn(circ_area), FadeIn(circle.copy().set_fill(opacity=1, color=YELLOW).set_stroke(width=0.001))) 334 | self.wait() 335 | plus = TexMobject("+", "+") 336 | temp = [eqn2, circ_area, eqn2_copy] 337 | for i in range(len(temp) - 1): 338 | mid = midpoint(temp[i].get_center(), temp[i + 1].get_center()) 339 | plus[i].move_to(mid) 340 | 341 | self.play(FadeIn(plus)) 342 | temp_grp = VGroup(*temp, plus) 343 | area_cyc = TexMobject("\\text{Area of Cycloid} = ").scale(0.75).next_to(eqn2, direction=DOWN) # .shift(LEFT * 0.25) 344 | equation = TexMobject("3 \\pi r^2").next_to(circle.get_bottom(), direction=DOWN).shift(UP * 0.15) 345 | self.play(ReplacementTransform(temp_grp, equation)) 346 | self.play(Write(area_cyc)) 347 | self.play(equation.next_to, area_cyc) 348 | self.wait() 349 | wordy_eqn = TexMobject("3 \\times \\text{Area of Rolling }").scale(0.75).next_to(area_cyc) 350 | temp = TexMobject("\\text{Circle}").scale(0.75).next_to(wordy_eqn, direction=DOWN, buff=SMALL_BUFF) 351 | wordy_eqn.add(temp) 352 | self.play(ReplacementTransform(equation, wordy_eqn)) 353 | self.wait() 354 | self.play(*[FadeOut(i) for i in self.mobjects]) 355 | -------------------------------------------------------------------------------- /Discretise.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class Divide(GraphScene): 5 | def construct(self): 6 | GraphScene.setup(self) 7 | self.setup_axes() 8 | 9 | def func(x): 10 | return np.sin(x) + 2 * np.cos(20 / 11 * x) + 4 11 | 12 | def get_x_value(input_tracker): 13 | return input_tracker.get_value() 14 | 15 | def get_y_value(input_tracker): 16 | return graph.underlying_function(get_x_value(input_tracker)) 17 | 18 | def get_graph_point(input_tracker): 19 | return self.coords_to_point(get_x_value(input_tracker), get_y_value(input_tracker)) 20 | graph = self.get_graph(func, x_min=0, x_max=10).set_color("#14aaeb") 21 | self.play(ShowCreation(graph), run_time=1.5) 22 | lines = [] 23 | dist = 10 24 | num = 9 25 | text = TextMobject("\# of lines:").move_to([4, 2.5, 0]) 26 | number = TexMobject(str(1)).next_to(text, RIGHT) 27 | for i in range(num): 28 | lines.append([]) 29 | for j in range(2**i): 30 | COLOR = YELLOW 31 | wid = 2 32 | start = ValueTracker(j * (10 / (2**i))) 33 | end = ValueTracker((j + 1) * (10 / (2**i))) 34 | lines[i].append(Line(get_graph_point(start), get_graph_point(end)).set_color(COLOR).set_stroke(width=wid)) 35 | lines[i].append(Line(get_graph_point(start), (get_graph_point(start) + get_graph_point(end)) / 2).set_color(COLOR).set_stroke(width=wid)) 36 | lines[i].append(Line((get_graph_point(start) + get_graph_point(end)) / 2, get_graph_point(end)).set_color(COLOR).set_stroke(width=wid)) 37 | self.play(FadeIn(lines[0][0]), FadeIn(text), FadeIn(number)) 38 | for i in range(num - 1): 39 | temp = TexMobject(str(2**(i + 1))).next_to(text, RIGHT) 40 | for j in range(2**i): 41 | self.remove(lines[i][3 * j]) 42 | self.add(lines[i][3 * j + 1]) 43 | self.add(lines[i][3 * j + 2]) 44 | self.play( 45 | *[ReplacementTransform(lines[i][3 * j + 1], lines[i + 1][6 * j]) for j in range(2**i)], 46 | *[ReplacementTransform(lines[i][3 * j + 2], lines[i + 1][6 * j + 3]) for j in range(2**i)], 47 | ReplacementTransform(number, temp), 48 | ) 49 | self.wait(0.5) 50 | number = temp 51 | self.play(*[FadeOut(lines[num - 1][3 * i]) for i in range(2**(num - 1))], run_time=2) 52 | self.wait() 53 | -------------------------------------------------------------------------------- /EulerODE.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | def four_swirls_function(point): 5 | x, y = point[:2] 6 | result = 1 * RIGHT + (x**2 - y**2) * UP 7 | result *= 0.05 8 | norm = get_norm(result) 9 | if norm == 0: 10 | return result 11 | # result *= 2 * sigmoid(norm) / norm 12 | return result 13 | 14 | 15 | class EulerODE(MovingCameraScene): 16 | CONFIG = { 17 | "dot_kwargs": { 18 | "radius": .035, 19 | "color": BLUE, 20 | "fill_opacity": .75, 21 | }, 22 | "vectorfield_kwargs": { 23 | # "x_min": -2, 24 | # "x_max": 2, 25 | # "y_min": -2, 26 | # "y_max": 2, 27 | # #"delta_x": .25, 28 | # #"delta_y": .25, 29 | # # "length_func": lambda norm: .45 * sigmoid(norm), 30 | # #"opacity": 1.0, 31 | }, 32 | "grid_kwargs": { 33 | "axis_config": { 34 | "stroke_color": WHITE, 35 | "stroke_width": 1, 36 | "include_ticks": False, 37 | "include_tip": False, 38 | "line_to_number_buff": SMALL_BUFF, 39 | "label_direction": DR, 40 | "number_scale_val": 0.5, 41 | }, 42 | "y_axis_config": { 43 | "label_direction": DR, 44 | }, 45 | "background_line_style": { 46 | "stroke_color": BLUE_D, 47 | "stroke_width": 2, 48 | "stroke_opacity": 1, 49 | }, 50 | # Defaults to a faded version of line_config 51 | "faded_line_style": None, 52 | "x_line_frequency": 1, 53 | "y_line_frequency": 1, 54 | "faded_line_ratio": 1, 55 | "make_smooth_after_applying_functions": True, 56 | }, 57 | "number_line_kwargs": { 58 | "color": LIGHT_GREY, 59 | "x_min": -FRAME_X_RADIUS, 60 | "x_max": FRAME_X_RADIUS, 61 | "unit_size": 1, 62 | "include_ticks": True, 63 | "tick_size": 0.1, 64 | "tick_frequency": 1, 65 | # Defaults to value near x_min s.t. 0 is a tick 66 | # TODO, rename this 67 | "leftmost_tick": None, 68 | # Change name 69 | "numbers_with_elongated_ticks": [0], 70 | "include_numbers": False, 71 | "numbers_to_show": None, 72 | "longer_tick_multiple": 2, 73 | "number_at_center": 0, 74 | "number_scale_val": 0.75, 75 | "label_direction": DOWN, 76 | "line_to_number_buff": MED_SMALL_BUFF, 77 | "include_tip": False, 78 | "tip_width": 0.25, 79 | "tip_height": 0.25, 80 | "decimal_number_config": { 81 | "num_decimal_places": 0, 82 | }, 83 | "exclude_zero_from_default_numbers": False, 84 | } 85 | 86 | } 87 | 88 | def construct(self): 89 | 90 | title = TextMobject("Euler's Method - A numerical method for solving ODE").to_edge(UP).add_background_rectangle(opacity=0.85) 91 | diff_eqn = TexMobject("\\dfrac{dy}{dx}=", "x^2-y^2").next_to(title, direction=DOWN).shift(LEFT * 4).add_background_rectangle(opacity=0.55) 92 | init_text = TexMobject("y(0)=0").move_to(UL).add_background_rectangle() 93 | self.play(Write(title)) 94 | 95 | grid = NumberPlane(**self.grid_kwargs) 96 | grid.add_coordinates() 97 | self.play(Write(grid)) 98 | self.wait() 99 | self.play(Write(diff_eqn)) 100 | self.wait() 101 | 102 | field = VectorField(four_swirls_function) 103 | # self.add(field) 104 | initial_condition = ORIGIN # * 3 105 | demo_dot = Dot(initial_condition, color=WHITE) 106 | demo_vect = field.get_vector(demo_dot.get_center()) 107 | 108 | def func(x, y): 109 | return x**2 - y**2 110 | 111 | slope_field = VGroup() 112 | x_rad = 7 113 | for i in list(range(-x_rad, x_rad + 1, 1)): 114 | for j in list(range(-x_rad, x_rad + 1, 1)): 115 | slope_line = Line(ORIGIN, RIGHT, color=YELLOW).scale(.5).rotate(np.arctan(func(i, j))) 116 | slope_line.move_to(np.array([i, j, 0])) 117 | slope_field.add(slope_line) 118 | 119 | coords = TexMobject("(0,0)", "(1,0)", "(2,0)") 120 | for k, l in zip(coords, [ORIGIN, RIGHT, RIGHT * 2]): 121 | k.move_to(l) 122 | 123 | samples = VGroup( 124 | *[Line(ORIGIN, RIGHT, color=YELLOW) 125 | .scale(.5) 126 | .rotate(np.arctan(func(*x))).move_to(np.array([x[0], x[1], 0])) 127 | for x in [[0, 0], [1, 0], [2, 0]] 128 | ] 129 | ) 130 | for coord, sample in zip(coords, samples): 131 | self.play(Write(coord)) 132 | self.play( 133 | coord.move_to, diff_eqn, 134 | coord.scale, .01 135 | ) 136 | self.wait(.5) 137 | self.play(TransformFromCopy(diff_eqn[2], sample)) 138 | self.wait() 139 | 140 | slope_field.add_to_back() # [title, diff_eqn, init_text, demo_dot, demo_vect]) 141 | self.play( 142 | ShowCreation(slope_field), 143 | FadeOut(title), 144 | FadeOut(diff_eqn), 145 | grid.fade, .7, 146 | ) 147 | self.wait(.5) 148 | self.play(Write(init_text)) 149 | self.play(ShowCreation(demo_dot), ShowCreation(demo_vect)) 150 | self.wait() 151 | self.play(FadeOut(init_text)) 152 | 153 | step_size = TextMobject("Step Size =").to_corner(UL) 154 | step = DecimalNumber(1).next_to(step_size) 155 | step_text = VGroup(step_size, step).add_background_rectangle() 156 | self.play(Write(step_text)) 157 | 158 | def get_demo_vect(): 159 | return field.get_vector(demo_dot.get_center()) 160 | 161 | def update_vector(obj): 162 | obj.become(get_demo_vect()) 163 | 164 | demo_vect.add_updater(update_vector) 165 | 166 | # self.play(FadeIn(demo_dot), FadeIn(demo_vect)) 167 | self.add(demo_vect) 168 | # self.wait(2) 169 | 170 | path = VMobject(stroke_width=2) 171 | path.set_points_as_corners([demo_dot.get_center(), demo_dot.get_center() + UP * 0.01]) 172 | 173 | def update_path(path): 174 | previus_path = path.copy() 175 | previus_path.add_points_as_corners([demo_dot.get_center()]) 176 | path.become(previus_path) 177 | path.add_updater(update_path) 178 | self.add(path) 179 | 180 | # self.wait() 181 | 182 | def get_intersection_point(line1, line2): 183 | endpoints1, endpoints2 = np.array([line1.points[0], line1.points[-1]]), \ 184 | np.array([line2.points[0], line2.points[-1]]) 185 | return line_intersection(endpoints1, endpoints2) 186 | 187 | intervals = [5, 8, 16] 188 | widths = [1, .5, .25] 189 | 190 | intersection_point = initial_condition 191 | intersection_line = Line(DOWN * 10, UP * 10, stroke_width=1, color=GREEN) 192 | demo_dot.save_state() 193 | intersection_line.save_state() 194 | for interval, width in zip(intervals, widths): 195 | step.set_value(width) 196 | for i in range(interval): 197 | self.play(ApplyMethod(demo_dot.move_to, intersection_point)) 198 | intersection_line.shift(RIGHT * width) 199 | # self.add(intersection_line) 200 | tangent_line = Line(LEFT * 10, RIGHT * 10, stroke_width=3, color=PURPLE).rotate(np.arctan(func(intersection_point[0], intersection_point[1]))) 201 | tangent_line.move_to(intersection_point) 202 | # self.add(tangent_line) 203 | intersection_point = get_intersection_point(intersection_line, tangent_line) 204 | self.wait(.5) 205 | 206 | path.suspend_updating() 207 | intersection_point = initial_condition 208 | intersection_line.restore() 209 | self.play( 210 | demo_dot.restore, 211 | FadeOut(path) 212 | ) 213 | self.remove(path) 214 | path = VMobject(stroke_width=2) 215 | path.set_points_as_corners([demo_dot.get_center(), demo_dot.get_center() + UP * 0.01]) 216 | path.add_updater(update_path) 217 | self.add(path) 218 | 219 | self.wait(2) 220 | 221 | self.play( 222 | *[FadeOut(mob)for mob in self.mobjects], 223 | run_time=2 224 | ) 225 | -------------------------------------------------------------------------------- /EulerWave.py: -------------------------------------------------------------------------------- 1 | #from big_ol_pile_of_manim_imports import * 2 | from manimlib.imports import * 3 | line_1_rate_prev=0 4 | line_1_rate_pres=2 5 | line_2_rate_prev=0 6 | line_2_rate_pres=2 7 | subline_1_rate_prev=0 8 | subline_1_rate_pres=2 9 | subline_2_rate_prev=0 10 | subline_2_rate_pres=2 11 | #circle 12 | #dot oscillating 13 | #2 lines rotating 14 | #dotted lines 15 | #sine wave 16 | 17 | 18 | class CheckFormulaByTXT(Scene): 19 | CONFIG={ 20 | "camera_config":{"background_color": BLACK}, 21 | "svg_type":"text", 22 | "text": TexMobject(""), 23 | "file":"", 24 | "svg_scale":0.9, 25 | "angle":0, 26 | "flip_svg":False, 27 | "fill_opacity": 1, 28 | "remove": [], 29 | "stroke_color": WHITE, 30 | "fill_color": WHITE, 31 | "stroke_width": 3, 32 | "numbers_scale":0.5, 33 | "show_numbers": True, 34 | "animation": False, 35 | "direction_numbers": UP, 36 | "color_numbers": RED, 37 | "space_between_numbers":0, 38 | "show_elements":[], 39 | "color_element":BLUE, 40 | "set_size":"width", 41 | "remove_stroke":[], 42 | "show_stroke":[], 43 | "warning_color":RED, 44 | "stroke_":1 45 | } 46 | def construct(self): 47 | self.imagen=self.text 48 | self.imagen.set_width(FRAME_WIDTH) 49 | if self.imagen.get_height()>FRAME_HEIGHT: 50 | self.imagen.set_height(FRAME_HEIGHT) 51 | self.imagen.scale(self.svg_scale) 52 | if self.flip_svg==True: 53 | self.imagen.flip() 54 | if self.show_numbers==True: 55 | self.print_formula(self.imagen.copy(), 56 | self.numbers_scale, 57 | self.direction_numbers, 58 | self.remove, 59 | self.space_between_numbers, 60 | self.color_numbers) 61 | 62 | self.return_elements(self.imagen.copy(),self.show_elements) 63 | for st in self.remove_stroke: 64 | self.imagen[st].set_stroke(None,0) 65 | for st in self.show_stroke: 66 | self.imagen[st].set_stroke(None,self.stroke_) 67 | if self.animation==True: 68 | self.play(DrawBorderThenFill(self.imagen)) 69 | else: 70 | c=0 71 | for j in range(len(self.imagen)): 72 | permission_print=True 73 | for w in self.remove: 74 | if j==w: 75 | permission_print=False 76 | if permission_print: 77 | self.add(self.imagen[j]) 78 | c = c + 1 79 | self.personalize_image() 80 | self.wait() 81 | 82 | def personalize_image(self): 83 | pass 84 | 85 | def print_formula(self,text,inverse_scale,direction,exception,buff,color): 86 | text.set_color(self.warning_color) 87 | self.add(text) 88 | c = 0 89 | for j in range(len(text)): 90 | permission_print=True 91 | for w in exception: 92 | if j==w: 93 | permission_print=False 94 | if permission_print: 95 | self.add(text[j].set_color(self.stroke_color)) 96 | c = c + 1 97 | 98 | c=0 99 | for j in range(len(text)): 100 | permission_print=True 101 | element = TexMobject("%d" %c,color=color) 102 | element.scale(inverse_scale) 103 | element.next_to(text[j],direction,buff=buff) 104 | for w in exception: 105 | if j==w: 106 | permission_print=False 107 | if permission_print: 108 | self.add_foreground_mobjects(element) 109 | c = c + 1 110 | 111 | def return_elements(self,formula,adds): 112 | for i in adds: 113 | self.add_foreground_mobjects(formula[i].set_color(self.color_element), 114 | TexMobject("%d"%i,color=self.color_element,background_stroke_width=0).scale(self.numbers_scale).next_to(formula[i],self.direction_numbers,buff=self.space_between_numbers)) 115 | 116 | class Check_Formula(CheckFormulaByTXT): 117 | CONFIG={ 118 | "text": TextMobject( 119 | "if", 120 | r"$\theta$", 121 | "increases with time", 122 | #"time", 123 | #"increases", 124 | #r"$\theta$", 125 | #"increases", 126 | #r"$\newline$", 127 | "then, the Complex Number", 128 | "z", 129 | "Rotates", 130 | "about the origin", 131 | 132 | ) 133 | } 134 | 135 | class Introduction(Scene): 136 | def construct(self): 137 | intro_text_1=TextMobject("Geometric intuition behind") 138 | intro_text_2 = TexMobject( 139 | 140 | "\\,\\,\\,{", 141 | "e", 142 | "^{", 143 | "i", 144 | "\\theta", 145 | "}", 146 | "-", 147 | "e", 148 | "^{", 149 | "i", 150 | "(", 151 | "-", 152 | "\\theta", 153 | ")", 154 | "}", 155 | "\\over", 156 | "{", 157 | "2", 158 | "i", 159 | "}", 160 | "}", 161 | "=", 162 | "sin", 163 | "(", 164 | "\\theta", 165 | ")", 166 | ) 167 | intro_text_1.scale(2) 168 | intro_text_2.scale(2) 169 | intro_text_2.move_to(intro_text_1.get_center()+DOWN) 170 | #color_theta = [5,13,25] 171 | #color_e = [1,2,8] 172 | #color_i=[3,4,9,10,19] 173 | 174 | 175 | #for i in color_theta: 176 | #intro_text[i].set_color(RED) 177 | #for i in color_e: 178 | #intro_text[i].set_color(BLUE) 179 | #for i in color_i: 180 | #intro_text[i].set_color(PURPLE) 181 | #intro_text[17].set_color("#49A88F") #color 2 182 | #intro_text[18].set_color("#49A88F") #color 2 183 | #intro_text[23].set_color(YELLOW) #color sin 184 | self.play(Write(intro_text_1)) 185 | self.play(ApplyMethod(intro_text_1.shift,UP)) 186 | self.wait(.5) 187 | self.play(Write(intro_text_2[0:40]), run_time = 3, lag_ratio=0.2) 188 | self.wait(2) 189 | 190 | class Graph(GraphScene): 191 | CONFIG={ 192 | "x_min":0, 193 | "x_max":5, 194 | "y_min":0, 195 | "y_max":3, 196 | "x_axis_width": 10, 197 | "y_axis_width": 7.5, 198 | "x_axis_label": 'Real', 199 | "y_axis_label": 'Img', 200 | "x_tick_frequency": .5, 201 | "y_tick_frequency": .5, 202 | "graph_origin": np.array([-5.5,-3,0]), 203 | "axes_color": YELLOW, 204 | "x_label_color": RED, 205 | "y_label_color": PURPLE, 206 | "label_nums_color": YELLOW, 207 | "x_labeled_nums" :range(0,6,1), 208 | "y_labeled_nums" :range(0,4,1), 209 | "y_label_direction": LEFT, 210 | } 211 | def construct(self): 212 | 213 | wordings=TextMobject("Consider the", "Argand plane") 214 | wordings.to_edge(UP) 215 | wordings[1].set_color(PURPLE) 216 | 217 | self.play(Write(wordings)) 218 | self.setup_axes(animate=True) 219 | 220 | complex_point = Dot(color = RED) 221 | complex_point.move_to(self.coords_to_point(2.5,2.5)) 222 | 223 | complex_r = Line(self.graph_origin, self.coords_to_point(2.5,2.5), color= BLUE) 224 | 225 | complex_theta = Arc(complex_r.get_angle(), radius= .9, start_angle= 0,arc_center=self.graph_origin,) 226 | 227 | theta = TexMobject("\\theta").next_to(complex_theta, buff = 0.1) 228 | 229 | 230 | self.play(ShowCreation(complex_point)) 231 | self.play( 232 | ApplyMethod(complex_point.move_to, self.coords_to_point(2.5,2.5)), 233 | ShowCreation(complex_r), 234 | ShowCreation(complex_theta), 235 | 236 | ) 237 | self.wait() 238 | 239 | def update_theta(complex_theta, dt): 240 | new_theta = Arc(complex_r.get_angle(), radius= .9, start_angle= 0,arc_center=self.graph_origin,) 241 | complex_theta.become(new_theta) 242 | 243 | #indicate theta 244 | def update_point(complex_point, dt): 245 | new_point = complex_point.move_to(complex_r.points[-1]) 246 | complex_point.become(new_point) 247 | 248 | complex_point.add_updater(update_point) 249 | complex_theta.add_updater(update_theta) 250 | 251 | self.play(ApplyMethod(complex_r.set_angle,PI/3)) 252 | self.play(ApplyMethod(complex_r.set_angle,PI/6)) 253 | self.play(ApplyMethod(complex_r.set_angle,PI/4)) 254 | self.play(WiggleOutThenIn(complex_theta)) 255 | self.play(ShowCreation(theta)) 256 | complex_theta.remove_updater(update_theta) 257 | complex_point.remove_updater(update_point) 258 | 259 | #indicate r 260 | r=TexMobject("r").move_to(complex_r.get_center()+.5*UP) 261 | complex_r.add_updater(lambda x:x.put_start_and_end_on(self.graph_origin,complex_point.get_center())) 262 | follow_line_1 = Line(complex_r.points[-1],complex_r.points[-1]+RIGHT+UP ) 263 | follow_line_2 = Line(complex_r.points[-1]+RIGHT+UP,complex_r.points[-1]+DOWN+LEFT ) 264 | follow_line_3 = Line(complex_r.points[-1]+DOWN+LEFT,complex_r.points[-1] ) 265 | self.play(MoveAlongPath(complex_point,follow_line_1, run_time=.5)) 266 | self.play(MoveAlongPath(complex_point,follow_line_2, run_time=.5)) 267 | self.play(MoveAlongPath(complex_point,follow_line_3, run_time=.5)) 268 | self.play(WiggleOutThenIn(complex_r)) 269 | self.play(ShowCreation(r)) 270 | 271 | self.wait() 272 | 273 | z=TexMobject("z","=r \\,{e}^{i \\theta}") 274 | z.move_to(complex_point.get_center()+RIGHT) 275 | self.play(ReplacementTransform(r,z[0]), ReplacementTransform(theta,z[1])) 276 | self.wait(2) 277 | 278 | class IntroToSpinnning(GraphScene): 279 | CONFIG={ 280 | "x_min":-10, 281 | "x_max":10, 282 | "y_min":-10, 283 | "y_max":10, 284 | "x_axis_width": 13, 285 | "y_axis_height": 7.5, 286 | "x_axis_label": 'Real', 287 | "y_axis_label": 'Img', 288 | "x_tick_frequency": 10, 289 | "y_tick_frequency": 10, 290 | "graph_origin":ORIGIN, 291 | "axes_color": YELLOW, 292 | "x_label_color": RED, 293 | "y_label_color": PURPLE, 294 | "label_nums_color": YELLOW, 295 | #"x_labeled_nums" :range(-5,11,2), 296 | #"y_labeled_nums" :range(-5,11,2), 297 | "y_label_direction": LEFT, 298 | "color_a":RED, 299 | "color_b":GREEN, 300 | } 301 | def construct(self): 302 | def update_theta(z_theta,dt): 303 | new_theta= Arc(z_r.get_angle(), start_angle=0,radius=.5) 304 | z_theta.become(new_theta) 305 | 306 | self.setup_axes(animate=True) 307 | 308 | z = Dot(color= self.color_a).move_to(self.graph_origin) 309 | 310 | z_r= Line(self.graph_origin,z.get_center(),color= self.color_b) 311 | 312 | z_theta=Arc(z_r.get_angle(), radius=.5) 313 | 314 | theta=TexMobject("\\theta =").move_to(z_theta.points[1]+RIGHT*.5+.5*UP) 315 | theta.scale(.75) 316 | 317 | Exp_1=TexMobject( 318 | "\\text{Suppose} \\,", 319 | "\\theta \\, \\text{increases}", 320 | "\\text{over time}", 321 | "\\text{the Complex Number} \\, Z", 322 | "\\text{Rotates about the origin}", 323 | "\\text{in Anti-Clockwise direction}" 324 | ).move_to(3*UP+2.5*LEFT) 325 | Exp_1.scale(.75) 326 | Exp_1a=TexMobject("\\theta \\, \\text{decreases}","\\text{in Clockwise direction}").scale(.75) 327 | Exp_arcAC= CurvedArrow(LEFT+UP,RIGHT+UP,angle=-TAU/4,color=MAROON_A) 328 | Exp_arcC= CurvedArrow(LEFT+DOWN,RIGHT+DOWN,angle=TAU/4,color=MAROON_A) 329 | Exp_1[1].set_color(BLUE) 330 | Exp_1[5].set_color(BLUE) 331 | #Exp_1[2].set_color_by_tex("Rotates", GREEN) 332 | VGroup(*Exp_1).arrange_submobjects(DOWN,buff=.075,aligned_edge=LEFT) 333 | Exp_1.to_corner(UL) 334 | #Exp_1[1].next_to(Exp_1[0]) 335 | #Exp_1[2].next_to(Exp_1[1]) 336 | Exp_1a[0].move_to(Exp_1[1].get_center()) 337 | Exp_1a[0].set_color(RED) 338 | Exp_1a[1].move_to(Exp_1[5].get_center()+LEFT*.435) 339 | Exp_1a[1].set_color(RED) 340 | 341 | #Exp_1[0].move_to(Exp_1[5].get_center()+.5*DOWN) 342 | #Exp_1[8].next_to(Exp_1[7]) 343 | #Exp_1[9].next_to(Exp_1[8]) 344 | 345 | z_label=TextMobject("z") 346 | z_label.add_updater(lambda x:x.next_to(z)) 347 | theta_var = DecimalNumber(z_r.get_angle(),show_ellipsis=False, include_sign = False).next_to(theta) 348 | theta_var.scale(.75) 349 | self.play(ShowCreation(z), ShowCreation(z_r),ShowCreation(z_label)) 350 | z_r.add_updater(lambda x:x.put_start_and_end_on(self.graph_origin, z.get_center())) 351 | self.play(ApplyMethod(z.move_to,self.coords_to_point(2,4))) 352 | self.play(ShowCreation(z_theta),ShowCreation(theta)) 353 | self.add(theta_var) 354 | z_theta.add_updater(update_theta) 355 | theta_var.add_updater(lambda x: x.set_value(z_r.get_angle()*(180/PI))) 356 | z.add_updater(lambda x:x.move_to(z_r.points[-1])) 357 | 358 | self.play(ShowCreation(Exp_1[0])) 359 | self.play(ShowCreation(Exp_1[1]),ShowCreation(Exp_1[2]), run_time=2) 360 | self.play(ShowCreation(Exp_1[3])) 361 | self.play(ShowCreation(Exp_1[4:]), run_time=2) 362 | self.play(WiggleOutThenIn(Exp_1[1])) 363 | self.play(WiggleOutThenIn(Exp_1[5]),ShowCreation(Exp_arcAC)) 364 | self.play(Uncreate(Exp_arcAC)) 365 | self.play(Rotating(z_r,radians= TAU+0.61730789, about_point= self.graph_origin, run_time=1)) 366 | self.play(Transform(Exp_1[5], Exp_1a[1]), Transform(Exp_1[1],Exp_1a[0]), run_time=3) 367 | self.play(WiggleOutThenIn(Exp_1[1])) 368 | self.play(WiggleOutThenIn(Exp_1[5]),ShowCreation(Exp_arcC)) 369 | self.play(Uncreate(Exp_arcC)) 370 | self.play(Rotating(z_r,radians= -TAU-0.41730789, start_angle=z_r.get_angle(),about_point= self.graph_origin),run_time=1) 371 | self.wait(2) 372 | 373 | class Spin(GraphScene): 374 | CONFIG={ 375 | "x_min":-10, 376 | "x_max":10, 377 | "y_min":-10, 378 | "y_max":10, 379 | "x_axis_width": 13, 380 | "y_axis_height": 7.5, 381 | "x_axis_label": 'Real', 382 | "y_axis_label": 'Img', 383 | "x_tick_frequency": 10, 384 | "y_tick_frequency": 10, 385 | "graph_origin":ORIGIN, 386 | "axes_color": WHITE, 387 | #"x_labeled_nums" :range(-5,11,2), 388 | #"y_labeled_nums" :range(-5,11,2), 389 | "y_label_direction": LEFT, 390 | "color_a":RED, 391 | "color_b":GREEN, 392 | } 393 | def construct(self): 394 | intro_1=TextMobject("Consider Two Complex Numbers").to_corner(UR) 395 | #intro_2= TexMobject("{e}^{i \\, \\theta} \\,","\\text{and} \\, \\,","{e}^{i \\, (-\\theta)}").move_to(intro_1.get_center()+.75*DOWN) 396 | #intro_2. scale(2) 397 | 398 | #self.play(ShowCreation(intro_1)) 399 | #self.play(ShowCreation(intro_2)) 400 | self.setup_axes(animate=False) 401 | 402 | z1=Dot(self.graph_origin,color= self.color_a) 403 | z1_shadow=Dot(self.graph_origin,color=GREY) 404 | 405 | z1_r=Line(self.graph_origin, self.coords_to_point(1,0), color=self.color_a) 406 | z1_r_shadow=Line(self.graph_origin, self.coords_to_point(1,0), color=GREY) 407 | 408 | z1_theta= Arc(z1_r.get_angle(), radius=0.5 ,start_angle = 0) 409 | z1_theta_shadow = Arc(z1_r_shadow.get_angle(),radius=0.5, start_angle = 0, color= GREY) 410 | 411 | z2=Dot(self.graph_origin,color= self.color_b) 412 | z2_r=Line(self.graph_origin, self.coords_to_point(-1,0), color =self.color_b) 413 | 414 | z1_r.add_updater(lambda x:x.put_start_and_end_on(self.graph_origin, z1.get_center())) 415 | z1_r_shadow.add_updater(lambda x:x.put_start_and_end_on(self.graph_origin, z1_shadow.get_center())) 416 | 417 | def update_theta(z1_theta,dt): 418 | new_theta=Arc(z1_r.get_angle(), start_angle = 0) 419 | z1_theta.become(new_theta) 420 | 421 | def update_theta_shadow(z1_theta,dt): 422 | new_theta=Arc(z1_r_shadow.get_angle(), start_angle = 0,color = GREY) 423 | z1_theta_shadow.become(new_theta) 424 | 425 | z1_theta.add_updater(update_theta) 426 | z1_theta_shadow.add_updater(update_theta_shadow) 427 | z2_r.add_updater(lambda x:x.put_start_and_end_on(self.graph_origin, z2.get_center())) 428 | 429 | self.play(ShowCreation(z1),ShowCreation(z1_r)) 430 | self.play(ApplyMethod(z1.move_to, self.coords_to_point(3,3))) 431 | self.play(ShowCreation(z1_theta)) 432 | z1_label=TexMobject("z = {e}^{i \\theta}",color = self.color_a).next_to(z1, buff= .05) 433 | self.play(ShowCreation(z1_label)) 434 | 435 | z1_shadow.move_to(z1.get_center()) 436 | self.add(z1_r_shadow,z1_shadow,z1_theta_shadow) 437 | self.play(ApplyMethod(z1_shadow.move_to, self.coords_to_point(3,-3)), run_time=2) 438 | z1_shadow_label=TexMobject("z = {e}^{i (-\\theta)}", color = GREY).next_to(z1_shadow, buff = .05) 439 | self.play(ShowCreation(z1_shadow_label)) 440 | self.play(Uncreate(z1_shadow),Uncreate(z1_r_shadow),Uncreate(z1_theta_shadow),Uncreate(z1_theta)) 441 | self.play(ShowCreation(z2),ShowCreation(z2_r)) 442 | self.play( ApplyMethod(z2.move_to, self.coords_to_point(-3,3))) 443 | 444 | z2_label= TexMobject("z_2 = - {e}^{i (-\\theta)}", color=self.color_b).move_to(z2.get_center()+LEFT*1.5) 445 | 446 | z1_sublabel=TexMobject("z_1 = {e}^{i \\theta}", color=self.color_a).next_to(z1) 447 | self.play(ReplacementTransform(z1_shadow_label,z2_label)) 448 | self.play(ReplacementTransform(z1_label, z1_sublabel)) 449 | self.play( ApplyMethod(z2.move_to, self.coords_to_point(-1.5,1.5)),ApplyMethod(z1.move_to, self.coords_to_point(1.5,1.5))) 450 | z1_label2= TexMobject("z_1 = \\dfrac{{e}^{i (\\theta)}}{2}", color=self.color_a).next_to(z1, buff = .05) 451 | z1_label2.scale(.75) 452 | z2_label2= TexMobject("z_2 = - \\dfrac{{e}^{i (-\\theta)}}{2}", color=self.color_b).move_to(z2.get_center()+LEFT*1.5) 453 | z2_label2.scale(.75) 454 | self.play(Transform(z1_sublabel, z1_label2), Transform(z2_label,z2_label2)) 455 | self.wait(2) 456 | 457 | class Stroboscope(Scene): 458 | CONFIG={ 459 | "radians_1": 0, #starting angle of line 1 460 | "radians_2": PI, #starting angle of line 2 461 | "amp": 2, 462 | "t_offset": 0, 463 | "rate": 0.05, 464 | "x_min":10, #xmin and max are to define the bounds of the horizontal graph 465 | "x_max": 9.427, 466 | "color_1": RED, 467 | "color_2": GREEN, 468 | "color_3": BLUE, 469 | "flash": True, 470 | "add_dot_copies": True, 471 | } 472 | 473 | def construct(self): 474 | total_time = 10 475 | flash_rect = FullScreenRectangle(stroke_width=0,fill_color=WHITE,fill_opacity=0.2,) 476 | flash=FadeOut( 477 | flash_rect, 478 | rate_func=squish_rate_func(smooth, 0, 0.1) 479 | ) 480 | time_label = TextMobject("Time = ") 481 | time_label.shift(MED_SMALL_BUFF * LEFT) 482 | time_tracker = ValueTracker(0) 483 | time = DecimalNumber(0) 484 | time.next_to(time_label, RIGHT) 485 | time.add_updater(lambda d, dt: d.set_value(time_tracker.get_value())) 486 | time_group = VGroup(time_label, time) 487 | time_group.center().to_edge(UP) 488 | times=np.arange(0, total_time + 1, .75) 489 | self.play(ShowCreation(time_group)) 490 | dot_copies = VGroup() 491 | z_sum_copies = VGroup() 492 | def update_line_1(line_1,dt): 493 | global line_1_rate_prev 494 | global line_1_rate_pres 495 | 496 | line_1.put_start_and_end_on(circle.get_center(), circle.get_center()+RIGHT*(self.amp/2)) 497 | a=dot.get_center()[1] 498 | b=line_1.get_length() 499 | alpha_la=4*np.arctan((2*b-np.sqrt(4*(b**2)-a**2))/(a+0.00001)) 500 | beta_la=PI/2-alpha_la/2 501 | ap=PI-alpha_la/2 502 | bp=PI/2-beta_la 503 | line_1.set_angle(bp) 504 | line_1_rate_pres = dot.get_center()[1] 505 | 506 | if line_1_rate_pres>line_1_rate_prev: 507 | line_1.set_color(self.color_1) 508 | if line_1_rate_presline_2_rate_prev: 527 | line_2.set_color(self.color_2) 528 | if line_2_rate_pressubline_1_rate_prev: 538 | subline_1.put_start_and_end_on(line_1.points[-1], dot.get_center()) 539 | 540 | if subline_1_rate_pressubline_2_rate_prev: 551 | subline_2.put_start_and_end_on(line_2.points[-1], dot.get_center()) 552 | if subline_2_rate_pres boundary.get_right()[0]: 56 | mobj.velocity[0] = -abs(mobj.velocity[0]) 57 | 58 | if mobj.get_bottom()[1] < boundary.get_bottom()[1]: 59 | mobj.velocity[1] = abs(mobj.velocity[1]) 60 | 61 | if mobj.get_top()[1] > boundary.get_top()[1]: 62 | mobj.velocity[1] = -abs(mobj.velocity[1]) 63 | 64 | def update_pseudo_lead(leader, dt): 65 | leader.shift(leader.velocity * dt) 66 | # if leader is leaders[0]: 67 | # leader.shift(leader.velocity * 20 * dt) 68 | # else: 69 | # direc = (leaders[0].get_center() - leader.get_center()) / np.linalg.norm(leaders[0].get_center() - leader.get_center()) 70 | # leader.velocity = self.common_v_weight * direc * 2 71 | # leader.shift(leader.velocity * dt) 72 | 73 | # l_positions = [] 74 | # for plp in self.previous_leader_positions: 75 | # if not np.array_equal(plp, leader.get_center()): 76 | # if np.linalg.norm(plp - leader.get_center()) < (self.local_rad + 0): 77 | # l_positions.append(plp) 78 | 79 | # local_centroid = np.mean(l_positions, axis=0) 80 | 81 | # local_direc = (local_centroid - leader.get_center()) * self.local_v_weight / 100 82 | # if leader is not leaders[0]: 83 | # leader.velocity += local_direc 84 | 85 | check_boundary(leader) 86 | 87 | if leader is leaders[-1]: 88 | self.previous_leader_positions = [l.get_center() for l in leaders] 89 | 90 | def get_dist(v1, v2): 91 | return np.linalg.norm(v1.get_center() - v2.get_center()) 92 | 93 | def dist_check(bird): 94 | for b in birds: 95 | if b != bird: 96 | dist = get_dist(b, bird) 97 | if dist < self.stay_away: 98 | bird.velocity += - (b.get_center() - bird.get_center()) * ((-self.push_v_weight * 10 * dist / self.stay_away) + self.push_v_weight * 10) 99 | 100 | def update_bird(bird, dt): 101 | 102 | bird_index = 0 103 | for index, b in enumerate(birds): 104 | if b is bird: 105 | bird_index = index 106 | # print(bird_index) 107 | exists = False 108 | for i in range(len(boxes)): 109 | if bird_index < last_bird_of_nth_group[i]: 110 | direc = (leaders[0].get_center() - bird.get_center()) / np.linalg.norm(leaders[0].get_center() - bird.get_center()) 111 | exists = True 112 | break 113 | 114 | if not exists: 115 | direc = (leaders[0].get_center() - bird.get_center()) / np.linalg.norm(leaders[0].get_center() - bird.get_center()) 116 | 117 | # if bird.get_center()[1] >= self.pseudo_lead_right[1]: 118 | # bird.rotate(-angle_between(bird.get_vertices()[0] - bird.get_center(), direc)) 119 | # else: 120 | # bird.rotate(angle_between(bird.get_vertices()[0] - bird.get_center(), direc)) 121 | 122 | bird.velocity = self.common_v_weight * direc 123 | lb_positions = [] 124 | for pbp in self.previous_bird_positions: 125 | if not np.array_equal(pbp, bird.get_center()): 126 | if np.linalg.norm(pbp - bird.get_center()) < self.local_rad: 127 | lb_positions.append(pbp) 128 | 129 | local_centroid = np.mean(lb_positions, axis=0) 130 | 131 | local_direc = (local_centroid - bird.get_center()) * self.local_v_weight 132 | bird.velocity += local_direc 133 | 134 | dist_check(bird) 135 | check_boundary(bird) 136 | 137 | bird.shift(bird.velocity * dt) 138 | 139 | if bird is last_bird: 140 | self.previous_bird_positions = [b.get_center() for b in birds] 141 | 142 | last_bird = Dot(np.random.uniform(-3., -1., size=3), radius=0.05, color=RED) 143 | 144 | leaders = VGroup() 145 | for i in range(1): 146 | random.seed() 147 | leader = Dot(boxes[i].get_center(), radius=0.001) 148 | # leader.velocity = rotate_vector(RIGHT, 2 * PI * random.random()) * self.leader_v_weight 149 | leader.velocity = UR * self.leader_v_weight 150 | leaders.add(leader) 151 | self.previous_leader_positions = [leader.get_center() for leader in leaders] 152 | 153 | for leader in leaders: 154 | leader.add_updater(update_pseudo_lead) 155 | self.add(leader) 156 | 157 | for i in range(total_birds): 158 | bird = Dot(bird_positions[i], radius=0.05, color=RED) 159 | # bird = Triangle(color=BLUE, fill_opacity=1, fill_color=BLUE).rotate(-PI / 2).scale(0.5).move_to(bird_positions[i]) 160 | birds.add(bird) 161 | 162 | birds.add(last_bird) 163 | last_bird.add_updater(update_bird) 164 | 165 | for bird in birds: 166 | bird.velocity = RIGHT 167 | bird.add_updater(update_bird) 168 | # self.add(bird) 169 | 170 | self.add(birds) 171 | self.wait(15) 172 | # print(self.pseudo_lead_right) 173 | # print(birds[0].get_center()) 174 | # self.wait() 175 | -------------------------------------------------------------------------------- /NewtonRootFinder.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class NewtonRoot(GraphScene, MovingCameraScene): 5 | CONFIG = { 6 | "x_min": -8, 7 | "x_max": 8, 8 | "x_axis_width": 40, 9 | "x_tick_frequency": .5, 10 | "x_leftmost_tick": None, # Change if different from x_min 11 | "x_labeled_nums": list(range(-10, 11)), 12 | "x_axis_label": "$x$", 13 | "y_min": -10, 14 | "y_max": 10, 15 | "y_axis_height": 14, 16 | "y_tick_frequency": 1, 17 | "y_bottom_tick": None, # Change if different from y_min 18 | "y_labeled_nums": list(range(-10, 11, 2)), 19 | "y_axis_label": "$y$", 20 | "axes_color": GREY, 21 | } 22 | 23 | def setup(self): 24 | GraphScene.setup(self) 25 | MovingCameraScene.setup(self) 26 | 27 | def construct(self): 28 | title = TextMobject("Newton's root-finding Algorithm").add_background_rectangle() 29 | title.to_edge(UP) 30 | 31 | root = TexMobject("\\sqrt{2}=?", "\\sqrt{2}=x", "x^2=2", "f(x)=x^2-2") 32 | for i in range(4): 33 | root[i].add_background_rectangle().next_to(title, direction=DOWN) 34 | 35 | self.play(Write(title)) 36 | self.play(Write(root[0])) 37 | for i in range(3): 38 | self.play(ReplacementTransform(root[i], root[i + 1])) 39 | self.wait(1.5) 40 | 41 | tangent_line_scale = 5 42 | 43 | def get_tangent(tgt_point): 44 | tangent = Line(ORIGIN, RIGHT, color=RED) 45 | tangent.scale(tangent_line_scale) 46 | tangent.rotate( 47 | self.angle_of_tangent(tgt_point, parabola) - tangent.get_angle() 48 | ) 49 | return tangent 50 | 51 | def get_intersection_point(line1, line2): 52 | endpoints1, endpoints2 = np.array([line1.points[0], line1.points[-1]]), np.array([line2.points[0], line2.points[-1]]) 53 | return line_intersection(endpoints1, endpoints2) 54 | 55 | self.setup_axes(animate=True) 56 | self.play(*[FadeOut(i) for i in (title, root[-1])]) 57 | parabola = self.get_graph( 58 | lambda x: x**2 - 2, 59 | x_min=self.x_min, 60 | x_max=self.x_max, 61 | color=GREEN 62 | ) 63 | 64 | self.play(ShowCreation(parabola)) 65 | self.wait() 66 | guess_arrow = Arrow(self.coords_to_point(1, 4), self.coords_to_point(1, 0.5)) 67 | guess = TextMobject("Initial guess").next_to(guess_arrow, direction=UP) 68 | 69 | nth_approx = self.coords_to_point(1, 0) 70 | approx = DecimalNumber(1, show_ellipsis=True, num_decimal_places=5).scale(.5).move_to(RIGHT * 3 + UP) \ 71 | .next_to(nth_approx, direction=UP) 72 | self.play(ShowCreation(guess_arrow), Write(guess), Write(approx)) 73 | self.add(approx) 74 | self.wait() 75 | self.play(FadeOut(guess_arrow), FadeOut(guess)) 76 | 77 | nth_dot = Dot(nth_approx) 78 | self.add(nth_dot) 79 | self.play( 80 | self.camera_frame.scale, .5, 81 | self.camera_frame.move_to, self.coords_to_point(1, 0), 82 | nth_dot.scale, .5, 83 | self.x_axis.fade, 0.5, 84 | self.y_axis.fade, 0.5, 85 | ) 86 | 87 | vert_line = self.get_vertical_line_to_graph(1, parabola, line_class=DashedLine) 88 | self.play(ShowCreation(vert_line)) 89 | x_line = Line(LEFT * 10, RIGHT * 10) 90 | tangent = get_tangent(1).move_to(self.input_to_graph_point(1, parabola)) 91 | self.play(ShowCreation(tangent)) 92 | self.wait(2) 93 | 94 | for i in range(1, 4): 95 | nplus1th_approx_pseudo = get_intersection_point(x_line, tangent) 96 | nplus1th_dot = Dot(nplus1th_approx_pseudo).scale(.5 / (i)) 97 | nplus1th_approx = self.point_to_coords(get_intersection_point(x_line, tangent)) 98 | # approx.add_updater(lambda x: x.next_to(nplus1th_approx_pseudo, direction=UP)) 99 | self.add(approx) 100 | # self.play(WiggleOutThenIn(nplus1th_dot)) 101 | if i == 2: 102 | self.play( 103 | ReplacementTransform(nth_dot, nplus1th_dot), 104 | Uncreate(vert_line), 105 | self.camera_frame.move_to, nplus1th_approx_pseudo, 106 | self.camera_frame.scale, .5, 107 | approx.next_to, nplus1th_approx_pseudo, {"direction": UP} 108 | # nplus1th_dot, 109 | ) 110 | 111 | elif i == 3: 112 | self.play( 113 | # ReplacementTransform(nth_dot, nplus1th_dot), 114 | # Uncreate(vert_line), 115 | self.camera_frame.move_to, nplus1th_approx_pseudo, 116 | # self.camera_frame.scale, .75, 117 | approx.next_to, nplus1th_approx_pseudo, {"direction": UP} 118 | # nplus1th_dot, 119 | ) 120 | else: 121 | self.play( 122 | ReplacementTransform(nth_dot, nplus1th_dot), 123 | Uncreate(vert_line), 124 | self.camera_frame.move_to, nplus1th_approx_pseudo, 125 | self.camera_frame.scale, .75, 126 | approx.next_to, nplus1th_approx_pseudo, {"direction": UP} 127 | # nplus1th_dot, 128 | ) 129 | approx.set_value(nplus1th_approx[0]) 130 | # print(f"---------------HERE================{nplus1th_approx[0]}") 131 | vert_line = self.get_vertical_line_to_graph(nplus1th_approx[0], parabola, line_class=DashedLine) 132 | self.play(Uncreate(tangent)) 133 | tangent = get_tangent(nplus1th_approx[0]).move_to(self.input_to_graph_point(nplus1th_approx[0], parabola)) 134 | self.play(ShowCreation(vert_line)) 135 | self.play(ShowCreation(tangent)) 136 | self.wait(2) 137 | nth_approx, nth_dot = nplus1th_approx, nplus1th_dot 138 | -------------------------------------------------------------------------------- /PolygonToEllipse.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class PolyToEl(MovingCameraScene): 5 | def construct(self): 6 | n = 10 7 | mat = np.zeros(shape=(n, n)) 8 | 9 | for i in range(n): 10 | mat[i] = [1 / 2 if j == i or j == (i + 1) % n else 0 for j in range(n)] 11 | 12 | lims = FRAME_HEIGHT - 4 13 | coords = [np.array([random.randrange(-lims, lims), random.randrange(-lims, lims), 0]) for j in range(n)] 14 | dots = VGroup(*[Dot(_) for _ in coords]) 15 | lines = VGroup(*[Line(coords[i], coords[(i + 1) % n]) for i in range(n)]) 16 | self.add(dots, lines) 17 | 18 | # pseudo_coords = [np.array([i[0], i[1]]) for i in coords] 19 | pseudo_one = 1 20 | for _ in range(500): 21 | if _ != 0: 22 | if _ % 30 == 0: 23 | scale_fac = 0.4 24 | pseudo_one *= scale_fac 25 | 26 | zoom_rect = Square(side_length=1 / scale_fac * FRAME_HEIGHT * pseudo_one) 27 | self.play(ShowCreation(zoom_rect)) 28 | self.play(self.camera_frame.scale, scale_fac, 29 | self.camera_frame.move_to, center_of_mass(coords), 30 | # dots.scale_in_place, scale_fac, 31 | # lines.scale, pseudo_one 32 | ) 33 | coords = mat.dot(coords) 34 | # coords = [np.array([i[0], i[1], 0]) for i in new_pseudo_coords] 35 | pseudo_coords = [np.array([i[0], i[1]]) for i in coords] 36 | 37 | new_dots_temp = VGroup(*[Dot(_, radius=0.075 * pseudo_one, color=YELLOW) for _ in coords]) 38 | new_lines_temp = VGroup(*[Line(coords[i], coords[(i + 1) % n], color=YELLOW) for i in range(n)]) 39 | 40 | self.play(FadeIn(new_dots_temp)) 41 | self.play(FadeIn(new_lines_temp)) 42 | 43 | new_dots = VGroup(*[Dot(_, radius=0.075 * pseudo_one) for _ in coords]) 44 | new_lines = VGroup(*[Line(coords[i], coords[(i + 1) % n]) for i in range(n)]) 45 | # self.add(dots, lines) 46 | # dots.become(new_dots) 47 | # lines.become(new_lines) 48 | 49 | self.play( 50 | dots.become, new_dots, 51 | lines.become, new_lines, 52 | # ReplacementTransform(dots, new_dots), 53 | # ReplacementTransform(lines, new_lines), 54 | FadeOut(new_dots_temp), 55 | FadeOut(new_lines_temp), 56 | run_time=1 57 | ) 58 | -------------------------------------------------------------------------------- /PythagorasTree.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class PyTree(Scene): 5 | CONFIG = { 6 | "rect_kwargs": { 7 | "stroke_width": 0.5, 8 | "fill_opacity": .75, 9 | "fill_color": RED, 10 | } 11 | } 12 | 13 | def construct(self): 14 | # get_start_anchors() = get_start_anchors() 15 | square = Square(**self.rect_kwargs).shift(DOWN * 2) # .rotate(PI / 4) 16 | 17 | self.add(square) 18 | squares = VGroup(square) 19 | rep = 2 20 | temp = VGroup() 21 | for _ in range(rep): 22 | for sq in squares: 23 | verts = sq.get_start_anchors() 24 | # for _ in range(rep): 25 | rect1, rect2 = self.bisect_square(sq) 26 | self.add(rect1, rect2) 27 | perp1 = (rotate_vector(-(3 / 4) * (verts[0] - verts[-1]), PI / 2) + sq.get_center()) 28 | perp2 = (rotate_vector(-(3 / 4) * (verts[1] - verts[2]), -PI / 2) + sq.get_center()) 29 | # self.add(*[Dot(l) for l in [perp1, perp2]]) 30 | self.play( 31 | rect1.move_to, perp1, 32 | rect2.move_to, perp2, 33 | ) 34 | self.play( 35 | rect1.shift, (verts[0] - verts[-1]) / 2, 36 | rect2.shift, (verts[1] - verts[2]) / 2, 37 | ) 38 | trxn1 = self.trisect_rect(rect1) 39 | trxn2 = self.trisect_rect(rect2) 40 | self.add(trxn1, trxn2) 41 | self.remove(rect1, rect2) 42 | 43 | self.previous_angles1 = [0, 0, 0] 44 | self.previous_angles2 = [0, 0, 0] 45 | 46 | ############################################## 47 | def update_trxn1_tri1(mob, alpha): 48 | # print(alpha) 49 | mob.rotate((PI) * alpha - self.previous_angles1[0], about_point=verts[1]) 50 | self.previous_angles1[0] = (PI) * alpha 51 | 52 | def update_trxn1_tri2(mob, alpha): 53 | # print(alpha) 54 | mob.rotate((-PI / 2) * alpha - self.previous_angles1[1], about_point=trxn1[1].get_start_anchors()[2]) 55 | self.previous_angles1[1] = (-PI / 2) * alpha 56 | 57 | def update_trxn1_tri3(mob, alpha): 58 | # print(alpha) 59 | mob.rotate((-2 * PI) * alpha - self.previous_angles1[2], about_point=trxn1[2].get_start_anchors()[0]) 60 | self.previous_angles1[2] = (-2 * PI) * alpha 61 | 62 | def update_trxn1_pos_mid_tri(mob): 63 | offset = trxn1[1].get_center() - trxn1[1].get_start_anchors()[2] 64 | mob.move_to(trxn1[0].get_start_anchors()[0] + offset) 65 | 66 | def update_trxn1_pos_top_tri(mob): 67 | offset = trxn1[2].get_center() - trxn1[2].get_start_anchors()[0] 68 | mob.move_to(trxn1[1].get_start_anchors()[0] + offset) 69 | ############################################## 70 | 71 | ############################################## 72 | def update_trxn2_tri1(mob, alpha): 73 | # print(alpha) 74 | mob.rotate((-PI) * alpha - self.previous_angles2[0], about_point=verts[0]) 75 | self.previous_angles2[0] = (-PI) * alpha 76 | 77 | def update_trxn2_tri2(mob, alpha): 78 | # print(alpha) 79 | mob.rotate((PI / 2) * alpha - self.previous_angles2[1], about_point=trxn2[1].get_start_anchors()[2]) 80 | self.previous_angles2[1] = (PI / 2) * alpha 81 | 82 | def update_trxn2_tri3(mob, alpha): 83 | # print(alpha) 84 | mob.rotate((2 * PI) * alpha - self.previous_angles2[2], about_point=trxn2[2].get_start_anchors()[0]) 85 | self.previous_angles2[2] = (2 * PI) * alpha 86 | 87 | def update_trxn2_pos_mid_tri(mob): 88 | offset = trxn2[1].get_center() - trxn2[1].get_start_anchors()[2] 89 | mob.move_to(trxn2[0].get_start_anchors()[0] + offset) 90 | 91 | def update_trxn2_pos_top_tri(mob): 92 | offset = trxn2[2].get_center() - trxn2[2].get_start_anchors()[0] 93 | mob.move_to(trxn2[1].get_start_anchors()[0] + offset) 94 | ############################################## 95 | 96 | trxn1[1].add_updater(update_trxn1_pos_mid_tri) 97 | trxn1[2].add_updater(update_trxn1_pos_top_tri) 98 | 99 | trxn2[1].add_updater(update_trxn2_pos_mid_tri) 100 | trxn2[2].add_updater(update_trxn2_pos_top_tri) 101 | 102 | self.add(trxn1[1:]) 103 | self.add(trxn2[1:]) 104 | self.play( 105 | UpdateFromAlphaFunc(trxn1[0], update_trxn1_tri1), 106 | UpdateFromAlphaFunc(trxn1[1], update_trxn1_tri2), 107 | UpdateFromAlphaFunc(trxn1[2], update_trxn1_tri3), 108 | 109 | UpdateFromAlphaFunc(trxn2[0], update_trxn2_tri1), 110 | UpdateFromAlphaFunc(trxn2[1], update_trxn2_tri2), 111 | UpdateFromAlphaFunc(trxn2[2], update_trxn2_tri3), 112 | run_time=2 113 | ) 114 | sq1 = VMobject(**self.rect_kwargs).set_points_as_corners([trxn1[1].get_start_anchors()[1], trxn1[1].get_start_anchors()[0], verts[1], trxn1[0].get_start_anchors()[0], trxn1[1].get_start_anchors()[1]]) 115 | sq2 = sq1.copy().flip().move_to(trxn2[0].get_start_anchors()[1]) 116 | self.add(sq1, sq2) 117 | 118 | # self.play( 119 | # AnimationGroup( 120 | # *[ShowCreation(Dot(k)) for k in sq1.get_start_anchors()], 121 | # lag_ratio=0.5 122 | # ) 123 | # ) 124 | # self.play( 125 | # AnimationGroup( 126 | # *[ShowCreation(Dot(k)) for k in sq2.get_start_anchors()], 127 | # lag_ratio=0.5 128 | # ) 129 | # ) 130 | self.play(*[FadeOut(j) for j in [trxn1, trxn2]]) 131 | # self.remove(trxn1, trxn2) 132 | # self.play(Indicate(sq1), Indicate(sq2)) 133 | # self.play(trxn1.shift, RIGHT) 134 | print("FFFFFFF") 135 | temp = VGroup(sq1, sq2) 136 | # temp.add(sqs) 137 | 138 | print(f"Loop {_} over") 139 | squares = temp 140 | print(squares) 141 | temp = VGroup() 142 | # self.play(trxn1[0].rotate, PI, {"about_point": trxn1[0].get_start_anchors()[2]}) 143 | # self.play(Indicate(trxn1[0])) 144 | # self.add(*[Dot(i) for i in [perp1, perp2]]) 145 | self.wait() 146 | 147 | def bisect_square(self, sq): 148 | verts = sq.get_start_anchors() 149 | print(verts) 150 | midpts = [midpoint(*verts[_:_ + 2]) for _ in [0, 2]] 151 | 152 | rect1 = VMobject(**self.rect_kwargs) 153 | rect1.set_points_as_corners([midpts[0], *verts[1:3], midpts[1], midpts[0]]) 154 | rect2 = VMobject(**self.rect_kwargs) 155 | rect2.set_points_as_corners([verts[0], *midpts, verts[-1], verts[0]]) 156 | 157 | rects = VGroup(rect1, rect2) 158 | return rects 159 | 160 | def trisect_rect(self, rect): 161 | verts = rect.get_start_anchors() 162 | midpt = midpoint(*verts[1:3]) 163 | tri1 = VMobject(**self.rect_kwargs).set_points_as_corners([verts[3], verts[2], midpt, verts[3]]) 164 | tri3 = VMobject(**self.rect_kwargs).set_points_as_corners([*verts[0:2], midpt, verts[0]]) 165 | tri2 = VMobject(**self.rect_kwargs).set_points_as_corners([verts[0], midpt, verts[3], verts[0]]) 166 | trxn = VGroup(*[tri1, tri2, tri3]) 167 | if rect.get_center()[0] > 0: 168 | trxn.flip() 169 | return trxn 170 | 171 | # bisect square CHECK 172 | # trisect rectangles 173 | # rearrange trisection to form individual squares and repeat 174 | 175 | # for _ in sq.get_start_anchors(): 176 | # self.play(FadeIn(Dot(_))) 177 | 178 | # self.wait() 179 | # cut = VMobject(color="RED").set_points_as_corners([sq.get_start_anchors()[0], sq.get_top(), sq.get_bottom(), *sq.get_start_anchors()[-1::-3]]) 180 | # # cut.set_fill(fill_color="RED") 181 | # self.wait() 182 | 183 | # def update_sq(mob, alpha): 184 | # # print(alpha) 185 | # sq.shift(UP * 2 * alpha) 186 | # print(UP * 2 * alpha) 187 | # self.play(UpdateFromAlphaFunc(sq, update_sq), run_time=2) 188 | # mp = [midpoint(*verts[1:3]), midpoint(verts[3], verts[0])] 189 | # tri1 = VMobject(**self.rect_kwargs).set_points_as_corners([*verts[0:2], *mp[:], verts[0]]) 190 | # tri2 = VMobject(**self.rect_kwargs).set_points_as_corners([*mp[:], *verts[2:], mp[0]]) 191 | 192 | # self.add(sq) 193 | # self.play(ShowCreation(tri1)) 194 | # self.play(ShowCreation(tri2)) 195 | """ 196 | offset = rect2.get_center() - rect2.get_start_anchors()[2] 197 | self.prev1 = 0 198 | self.prev2 = 0 199 | 200 | def update_rect1(mob, alpha): 201 | # print(alpha) 202 | rect1.rotate((PI / 2) * alpha - self.prev1, about_point=rect1.get_start_anchors()[3]) 203 | self.prev1 = (PI / 2) * alpha 204 | 205 | def update_rect2(mob, alpha): 206 | # print(alpha) 207 | rect2.rotate((-PI / 2) * alpha - self.prev2, about_point=rect2.get_start_anchors()[2]) 208 | self.prev2 = (-PI / 2) * alpha 209 | 210 | def update_rect2_pos(mob): 211 | offset = rect2.get_center() - rect2.get_start_anchors()[3] 212 | mob.move_to(rect1.get_start_anchors()[2] + offset) 213 | # print(rect1.get_start_anchors()[1]) 214 | 215 | rect2.add_updater(update_rect2_pos) # lambda x: x.move_to(rect1.get_start_anchors()[2])) 216 | self.add(rect2, rect1)------- 217 | self.play( 218 | # rect1.rotate, PI / 2, {"about_point": rect1.get_start_anchors()[2]}, 219 | UpdateFromAlphaFunc(rect1, update_rect1), 220 | UpdateFromAlphaFunc(rect2, update_rect2), 221 | run_time=2 222 | ) 223 | print(rect1.get_start_anchors()[1]) 224 | """ 225 | # self.play(ShowCreation(self.trisect_rect(rect1))) 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ManimMiniProjects 2 | Short animations using Manim 3 | -------------------------------------------------------------------------------- /RKMethod.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | def four_swirls_function(point): 5 | x, y = point[:2] 6 | result = 1 * RIGHT + (x**2 - y**2) * UP 7 | result *= 0.05 8 | norm = get_norm(result) 9 | if norm == 0: 10 | return result 11 | # result *= 2 * sigmoid(norm) / norm 12 | return result 13 | 14 | 15 | class RK2(MovingCameraScene): 16 | CONFIG = { 17 | "dot_kwargs": { 18 | "radius": .035, 19 | "color": BLUE, 20 | "fill_opacity": .75, 21 | }, 22 | "vectorfield_kwargs": { 23 | # "x_min": -2, 24 | # "x_max": 2, 25 | # "y_min": -2, 26 | # "y_max": 2, 27 | # #"delta_x": .25, 28 | # #"delta_y": .25, 29 | # # "length_func": lambda norm: .45 * sigmoid(norm), 30 | # #"opacity": 1.0, 31 | }, 32 | "grid_kwargs": { 33 | "axis_config": { 34 | "stroke_color": WHITE, 35 | "stroke_width": 1, 36 | "include_ticks": False, 37 | "include_tip": False, 38 | "line_to_number_buff": SMALL_BUFF, 39 | "label_direction": DR, 40 | "number_scale_val": 0.5, 41 | }, 42 | "y_axis_config": { 43 | "label_direction": DR, 44 | }, 45 | "background_line_style": { 46 | "stroke_color": BLUE_D, 47 | "stroke_width": 2, 48 | "stroke_opacity": 1, 49 | }, 50 | # Defaults to a faded version of line_config 51 | "faded_line_style": None, 52 | "x_line_frequency": 1, 53 | "y_line_frequency": 1, 54 | "faded_line_ratio": 1, 55 | "make_smooth_after_applying_functions": True, 56 | }, 57 | "number_line_kwargs": { 58 | "color": LIGHT_GREY, 59 | "x_min": -FRAME_X_RADIUS, 60 | "x_max": FRAME_X_RADIUS, 61 | "unit_size": 1, 62 | "include_ticks": True, 63 | "tick_size": 0.1, 64 | "tick_frequency": 1, 65 | # Defaults to value near x_min s.t. 0 is a tick 66 | # TODO, rename this 67 | "leftmost_tick": None, 68 | # Change name 69 | "numbers_with_elongated_ticks": [0], 70 | "include_numbers": False, 71 | "numbers_to_show": None, 72 | "longer_tick_multiple": 2, 73 | "number_at_center": 0, 74 | "number_scale_val": 0.75, 75 | "label_direction": DOWN, 76 | "line_to_number_buff": MED_SMALL_BUFF, 77 | "include_tip": False, 78 | "tip_width": 0.25, 79 | "tip_height": 0.25, 80 | "decimal_number_config": { 81 | "num_decimal_places": 0, 82 | }, 83 | "exclude_zero_from_default_numbers": False, 84 | } 85 | 86 | } 87 | 88 | def construct(self): 89 | 90 | title = TextMobject("Euler's Method - A numerical method for solving ODE").to_edge(UP).add_background_rectangle(opacity=0.85) 91 | diff_eqn = TexMobject("\\dfrac{dy}{dx}=", "x^2-y^2").next_to(title, direction=DOWN).shift(LEFT * 4).add_background_rectangle(opacity=0.55) 92 | init_text = TexMobject("y(0)=0").move_to(UL).add_background_rectangle() 93 | # self.play(Write(title)) 94 | 95 | grid = NumberPlane(**self.grid_kwargs) 96 | grid.add_coordinates() 97 | # self.play(Write(grid)) 98 | # self.wait() 99 | # self.play(Write(diff_eqn)) 100 | # self.wait() 101 | 102 | field = VectorField(four_swirls_function) 103 | # self.add(field) 104 | initial_condition = ORIGIN # * 3 105 | main_dot = Dot(initial_condition, color=RED) 106 | pseudo_dot = Dot(initial_condition, color=WHITE) 107 | demo_vect = field.get_vector(main_dot.get_center()) 108 | 109 | def func(x, y): 110 | return x**2 - y**2 111 | 112 | slope_field = VGroup() 113 | x_rad = 7 114 | for i in list(range(-x_rad, x_rad + 1, 1)): 115 | for j in list(range(-x_rad, x_rad + 1, 1)): 116 | slope_line = Line(ORIGIN, RIGHT, color=YELLOW).scale(.5).rotate(np.arctan(func(i, j))) 117 | slope_line.move_to(np.array([i, j, 0])) 118 | slope_field.add(slope_line) 119 | 120 | coords = TexMobject("(0,0)", "(1,0)", "(2,0)") 121 | for k, l in zip(coords, [ORIGIN, RIGHT, RIGHT * 2]): 122 | k.move_to(l) 123 | 124 | samples = VGroup( 125 | *[Line(ORIGIN, RIGHT, color=YELLOW) 126 | .scale(.5) 127 | .rotate(np.arctan(func(*x))).move_to(np.array([x[0], x[1], 0])) 128 | for x in [[0, 0], [1, 0], [2, 0]] 129 | ] 130 | ) 131 | 132 | # for coord, sample in zip(coords, samples): 133 | # self.play(Write(coord)) 134 | # self.play( 135 | # coord.move_to, diff_eqn, 136 | # coord.scale, .01 137 | # ) 138 | # self.wait(.5) 139 | # self.play(TransformFromCopy(diff_eqn[2], sample)) 140 | # self.wait() 141 | 142 | slope_field.add_to_back() # [title, diff_eqn, init_text, main_dot, demo_vect]) 143 | # self.play( 144 | # ShowCreation(slope_field), 145 | # # FadeOut(title), 146 | # # FadeOut(diff_eqn), 147 | # grid.fade, .7, 148 | # ) 149 | self.wait() 150 | # self.play(slope_field.fade, .6) 151 | self.play(self.camera_frame.scale, .75) 152 | # self.wait(.5) 153 | # self.play(Write(init_text)) 154 | self.play(ShowCreation(main_dot), ShowCreation(demo_vect)) 155 | # self.wait() 156 | # self.play(FadeOut(init_text)) 157 | 158 | step_size = TextMobject("Step Size =").to_corner(UL).shift(DOWN * .75 + RIGHT) 159 | step = DecimalNumber(1).next_to(step_size) 160 | step_text = VGroup(step_size, step).add_background_rectangle().scale(.75) 161 | self.play(Write(step_text)) 162 | 163 | def get_demo_vect(): 164 | return field.get_vector(main_dot.get_center()) 165 | 166 | def update_vector(obj): 167 | obj.become(get_demo_vect()) 168 | 169 | demo_vect.add_updater(update_vector) 170 | 171 | # self.play(FadeIn(main_dot), FadeIn(demo_vect)) 172 | self.add(demo_vect) 173 | # self.wait(2) 174 | 175 | main_path = VMobject(stroke_width=2, color=RED) 176 | main_path.set_points_as_corners([main_dot.get_center(), main_dot.get_center() + UP * 0.01]) 177 | pseudo_path = VMobject(stroke_width=2, color=WHITE) 178 | pseudo_path.set_points_as_corners([pseudo_dot.get_center(), pseudo_dot.get_center() + UP * 0.01]) 179 | 180 | def update_main_path(main_path): 181 | previus_path = main_path.copy() 182 | previus_path.add_points_as_corners([main_dot.get_center()]) 183 | main_path.become(previus_path) 184 | 185 | def update_pseudo_path(pseudo_path): 186 | previus_path = main_path.copy() 187 | previus_path.add_points_as_corners([pseudo_dot.get_center()]) 188 | main_path.become(previus_path) 189 | 190 | main_path.add_updater(update_main_path) 191 | self.add(main_path) 192 | pseudo_path.add_updater(update_pseudo_path) 193 | self.add(pseudo_path) 194 | 195 | # self.wait() 196 | 197 | def get_intersection_point(line1, line2): 198 | endpoints1, endpoints2 = np.array([line1.points[0], line1.points[-1]]), \ 199 | np.array([line2.points[0], line2.points[-1]]) 200 | return line_intersection(endpoints1, endpoints2) 201 | 202 | def get_slope_mobject(point): 203 | i, j = point[0], point[1] 204 | slope_obj = Line(ORIGIN, RIGHT, color=YELLOW).scale(.5).rotate(np.arctan(func(i, j))) 205 | slope_obj.move_to(np.array([i, j, 0])) 206 | return slope_obj 207 | 208 | intervals = [3] # , 2] # , 2] 209 | widths = [1] # , .5] # , .25] 210 | 211 | intersection_point = initial_condition 212 | intersection_line = Line(DOWN * 10, UP * 10, stroke_width=1, color=GREEN) 213 | main_dot.save_state() 214 | intersection_line.save_state() 215 | 216 | for interval, width, j in zip(intervals, widths, list(range(len(intervals)))): 217 | step.set_value(width) 218 | for i in range(interval): 219 | # print(f"===================interval:{interval}, i:{i}, j:{j}================") 220 | self.play(ApplyMethod(main_dot.move_to, intersection_point)) 221 | if j != 0: 222 | self.play(FadeOut(average_slope_mobj)) 223 | elif j != 1: 224 | self.play(FadeOut(slope_field)) 225 | intersection_line.shift(RIGHT * width) 226 | 227 | pseudo_tangent_line = Line(LEFT * 10, RIGHT * 10, stroke_width=3, color=PURPLE)\ 228 | .rotate(np.arctan(func(intersection_point[0], intersection_point[1]))) 229 | pseudo_tangent_line.move_to(intersection_point) 230 | pseudo_intersection_point = get_intersection_point(intersection_line, pseudo_tangent_line) 231 | 232 | slope = DecimalNumber(func(intersection_point[0], intersection_point[1])) 233 | slope_n = get_slope_mobject(intersection_point) 234 | self.play(ShowCreation(slope_n)) 235 | 236 | self.play(ApplyMethod(pseudo_dot.move_to, pseudo_intersection_point)) 237 | 238 | pseudo_slope = DecimalNumber(func(pseudo_intersection_point[0], pseudo_intersection_point[1])) 239 | pseudo_slope_line = get_slope_mobject(pseudo_intersection_point) 240 | self.play(ShowCreation(pseudo_slope_line)) 241 | 242 | plus = TexMobject("+", "2") 243 | divide = Line(LEFT, RIGHT) 244 | average_slope_value = (slope.get_value() + pseudo_slope.get_value()) / 2 245 | average_slope_value_mobj = DecimalNumber(average_slope_value) 246 | average_number_group_pseudo = VGroup(slope, plus[0], pseudo_slope).arrange_submobjects(direction=RIGHT) 247 | average_number_group = VGroup(average_number_group_pseudo, divide, plus[1])\ 248 | .arrange_submobjects(direction=DOWN).next_to(step_text, direction=DOWN) 249 | average_slope_value_mobj.move_to(average_number_group) 250 | 251 | self.play(ReplacementTransform(slope_n, slope)) 252 | self.play(ReplacementTransform(pseudo_slope_line, pseudo_slope)) 253 | self.play(Write(plus), run_time=2) 254 | # self.wait() 255 | self.play(ReplacementTransform(average_number_group, average_slope_value_mobj)) 256 | 257 | average_slope_mobj = Line(ORIGIN, RIGHT, color=BLUE).scale(.5)\ 258 | .rotate(np.arctan(average_slope_value)).move_to(np.array([intersection_point[0], intersection_point[1], 0])) 259 | 260 | self.play(ReplacementTransform(average_slope_value_mobj, average_slope_mobj)) 261 | 262 | tangent_line = Line(LEFT * 10, RIGHT * 10, stroke_width=3, color=PURPLE)\ 263 | .rotate( 264 | np.arctan(average_slope_value) 265 | ) 266 | intersection_point = get_intersection_point(intersection_line, tangent_line) 267 | self.wait() 268 | pseudo_path.suspend_updating() 269 | self.play( 270 | FadeOut(pseudo_path), 271 | FadeOut(pseudo_dot) 272 | ) 273 | self.remove(pseudo_path) 274 | pseudo_dot.move_to(intersection_point) 275 | pseudo_path = VMobject(stroke_width=2) 276 | 277 | pseudo_path.set_points_as_corners([pseudo_dot.get_center(), pseudo_dot.get_center() + UP * 0.01]) 278 | pseudo_path.add_updater(update_pseudo_path) 279 | self.add(pseudo_path) 280 | self.wait() 281 | 282 | main_path.suspend_updating() 283 | intersection_point = initial_condition 284 | intersection_line.restore() 285 | self.play( 286 | main_dot.restore, 287 | FadeOut(main_path) 288 | ) 289 | self.remove(main_path) 290 | main_path = VMobject(stroke_width=2) 291 | main_path.set_points_as_corners([main_dot.get_center(), main_dot.get_center() + UP * 0.01]) 292 | main_path.add_updater(update_main_path) 293 | self.add(main_path) 294 | 295 | self.wait(2) 296 | 297 | # self.play( 298 | # *[FadeOut(mob)for mob in self.mobjects], 299 | # run_time=2 300 | # ) 301 | -------------------------------------------------------------------------------- /SeriesProof.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class Series(Scene): 5 | CONFIG = { 6 | "rect_kwargs": { 7 | "stroke_width": 2 8 | } 9 | } 10 | 11 | def construct(self): 12 | a = 12 13 | iterations = 50 14 | formula = TexMobject( 15 | "(1-x) \\mathbf{.} 1", 16 | "+ (1-x) \\mathbf{.} \\, x", 17 | "+ (1-x)\\mathbf{.} \\, x^2", 18 | "+... \\,", 19 | " = \\, 1" 20 | ).scale(1.25).shift((FRAME_HEIGHT - 1) * UP) 21 | unit_sq = Square(side_length=a, **self.rect_kwargs) 22 | one = TexMobject("1", "1").scale(1.5) 23 | one[0].next_to(unit_sq, direction=UP) 24 | one[1].next_to(unit_sq) 25 | self.play(ShowCreation(unit_sq), Write(one)) 26 | self.play(FadeOut(one)) 27 | # box = unit_sq.copy() 28 | x_text = TexMobject("x = ") 29 | x_obj = DecimalNumber(.5) 30 | x_grp = VGroup(x_text, x_obj).arrange_submobjects(direction=RIGHT).scale(2).shift((FRAME_HEIGHT - 1) * DOWN) 31 | self.play(Write(x_grp)) 32 | self.x = x_obj.get_value() 33 | 34 | def update_box(box, dt): 35 | bc = unit_sq.copy() 36 | bg = VGroup(bc) 37 | for i in range(iterations): 38 | if i % 2 == 0: 39 | bc.stretch_about_point(self.x, 0, bc.get_left()) 40 | else: 41 | bc.stretch_about_point(self.x, 1, bc.get_top()) 42 | bg.add(bc.copy()) 43 | 44 | box.become(bg) 45 | 46 | box_group = VGroup(unit_sq.copy()) 47 | box_copy = unit_sq.copy() 48 | 49 | # ############################################################ 50 | for i in range(iterations): 51 | if i % 2 == 0: 52 | temp_box = box_copy.copy().stretch_about_point(1 - self.x, 0, box_copy.get_right()).save_state() 53 | if i < 20: 54 | self.play(box_copy.stretch_about_point, self.x, 0, box_copy.get_left()) 55 | else: 56 | box_copy.stretch_about_point(self.x, 0, box_copy.get_left()) 57 | else: 58 | temp_box = box_copy.copy().stretch_about_point(1 - self.x, 1, box_copy.get_bottom()).save_state() 59 | if i < 20: 60 | self.play(box_copy.stretch_about_point, self.x, 1, box_copy.get_top()) 61 | else: 62 | box_copy.stretch_about_point(self.x, 0, box_copy.get_top()) 63 | box_group.add(box_copy.copy()) 64 | 65 | self.add(box_group[-1]) 66 | if i < 3: 67 | if i != 0: 68 | temp = formula[i][1:].copy().scale(1 / (0.5 * i)).move_to(temp_box) 69 | else: 70 | temp = formula[i].copy().scale(1.5).move_to(temp_box) 71 | self.play(Write(formula[i])) 72 | 73 | self.play(temp_box.set_fill, {"color": RED, "opacity": 0.75}) 74 | self.play(TransformFromCopy(formula[i], temp)) 75 | self.play(FadeOut(temp_box), FadeOut(temp)) 76 | if i == 2: 77 | self.play(Write(formula[3])) 78 | 79 | box_group.add_updater(update_box) 80 | self.add(box_group) 81 | 82 | self.play(Write(formula[-1])) 83 | self.t = 0 84 | 85 | def update_x_obj(x_obj, dt): 86 | self.t += dt / 5 87 | if self.t <= 1: 88 | x_obj.set_value(0.25 * np.sin(2 * PI * self.t) + 0.5) 89 | self.x = x_obj.get_value() 90 | 91 | x_obj.add_updater(update_x_obj) 92 | self.add(x_obj) 93 | self.wait(10) 94 | -------------------------------------------------------------------------------- /SimpsonsRule.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class Simpsons(GraphScene): 5 | CONFIG = { 6 | "x_min": -1, 7 | "x_max": 11, 8 | "x_axis_width": 10, 9 | 10 | "x_tick_frequency": 1, 11 | "x_leftmost_tick": None, # Change if different from x_min 12 | "x_labeled_nums": None, 13 | "x_axis_label": "$x$", 14 | "y_min": -1, 15 | "y_max": 11, 16 | "y_axis_height": 6, 17 | "y_tick_frequency": 2, 18 | "y_bottom_tick": None, # Change if different from y_min 19 | "y_labeled_nums": None, 20 | "y_axis_label": "$y$", 21 | "axes_color": GREY, 22 | "graph_origin": 2.5 * DOWN + 4 * LEFT, 23 | "exclude_zero_label": True, 24 | "default_graph_colors": [BLUE, GREEN, YELLOW], 25 | "default_derivative_color": GREEN, 26 | "default_input_color": YELLOW, 27 | "default_riemann_start_color": BLUE, 28 | "default_riemann_end_color": GREEN, 29 | "area_opacity": 0.8, 30 | "num_rects": 50, 31 | 32 | } 33 | 34 | def get_parabola(self, pt1, pt2, pt3): 35 | a = np.array([[pt1[0]**2, pt1[0], 1], [pt2[0]**2, pt2[0], 1], [pt3[0]**2, pt3[0], 1]]) 36 | # print(a) 37 | b = np.array([pt1[1], pt2[1], pt3[1]]) 38 | # print(b) 39 | x = np.linalg.solve(a, b) 40 | return x 41 | 42 | def construct(self): 43 | def get_triangle(corners, **kwargs): 44 | tri = VMobject(**kwargs) 45 | tri.set_points_as_corners([*corners, corners[0]]) 46 | return tri 47 | 48 | def func(t): 49 | return .05 * t**3 - .55 * t**2 + t + 7 50 | 51 | ctp = self.coords_to_point 52 | title = TextMobject("Simpsons Rule").scale(2) 53 | self.play(Write(title)) 54 | self.play(title.to_edge, UP) 55 | self.play(FadeOut(title)) 56 | 57 | self.setup_axes(animate=True) 58 | 59 | graph = self.get_graph(func, stroke_width=3, color=RED) 60 | self.play(ShowCreation(graph)) 61 | 62 | integral = VMobject(stroke_width=0, fill_opacity=.5, color=YELLOW) 63 | integral_points = [ 64 | self.coords_to_point(0, 0), 65 | *[self.input_to_graph_point(l, graph) for l in (np.arange(0, self.x_max - 1 + .1, .1))], 66 | self.coords_to_point(self.x_max - 1, 0), 67 | self.coords_to_point(0, 0), 68 | ] 69 | integral.set_points_as_corners(integral_points) 70 | self.play(FadeIn(integral)) 71 | area_text = TextMobject("Area = ?").scale(1.5).move_to(integral.get_center() + 2 * DOWN) 72 | self.play(Write(area_text)) 73 | self.play(FadeOut(area_text), FadeOut(integral)) 74 | 75 | step_size = TexMobject("\\Delta x =").to_edge(UP) 76 | step = DecimalNumber(2).next_to(step_size) 77 | step_text = VGroup(step_size, step).add_background_rectangle() 78 | 79 | number_line = VGroup(Line(ctp(0, 0), ctp(self.x_max - 1, 0), color=BLUE)) 80 | tick = Line(.125 * UP, .125 * DOWN, color=BLUE) 81 | for i in np.arange(0, self.x_max - 1 + 2, 2): 82 | tick_copy = tick.copy().move_to(ctp(i, 0)).shift(.4 * DOWN) 83 | number_line.add(tick_copy) 84 | 85 | measure_line = Line(ctp(0, 0), ctp(2, 0), color=PURPLE).shift(.4 * DOWN) 86 | delx = TexMobject("\\Delta x").scale(.75).next_to(measure_line.get_center(), buff=.2, direction=DOWN) 87 | 88 | # n = 2 89 | iterations = VGroup() 90 | 91 | self.play(Write(number_line[0])) 92 | self.play(ApplyMethod(number_line[0].shift, .4 * DOWN)) 93 | self.play(Write(number_line[1:])) 94 | self.wait() 95 | self.play(WiggleOutThenIn(measure_line)) 96 | self.play(Write(delx)) 97 | self.wait() 98 | self.play(ReplacementTransform(delx, step_text), FadeOut(measure_line)) 99 | self.wait() 100 | 101 | make_permanent = True 102 | for n in [2, 1, .5]: 103 | self.play(step.set_value, n) 104 | x_samps = np.arange(0, 8, n) 105 | x_samps_centers = [] 106 | 107 | for s in range(len(x_samps)): 108 | if s % 2 != 0: 109 | x_samps_centers.append(x_samps[s]) 110 | nth_iteration = VGroup() 111 | 112 | for x_samps_center in x_samps_centers: 113 | simpson_pts = [x_samps_center - n, x_samps_center, x_samps_center + n] 114 | y_samps = [func(i) for i in simpson_pts] 115 | x = self.get_parabola(*[(simpson_pts[k], y_samps[k]) for k in range(3)]) 116 | 117 | parab_approx = self.get_graph( 118 | lambda t: x[0] * t**2 + x[1] * t + x[2], 119 | x_min=x_samps_center - (n + 2), 120 | x_max=x_samps_center + (n + 2), 121 | color=PURPLE, 122 | stroke_width=1.5 123 | ) 124 | simpson_pts_GR = [self.input_to_graph_point(s, graph) for s in simpson_pts] 125 | 126 | line = self.get_vertical_line_to_graph(simpson_pts[-1], graph, line_class=DashedLine, color=BLUE) 127 | 128 | parab_area = VMobject(fill_color=BLUE, sheen_direction=RIGHT, fill_opacity=0.5, stroke_width=0) 129 | parab_area_points = [ 130 | self.coords_to_point(simpson_pts[0], 0), 131 | simpson_pts_GR[0], 132 | *[self.input_to_graph_point(l, parab_approx) for l in (np.arange(simpson_pts[0], simpson_pts[-1], .1))], 133 | simpson_pts_GR[-1], 134 | self.coords_to_point(simpson_pts[-1], 0), 135 | ] 136 | 137 | parab_area.set_points_as_corners(parab_area_points) 138 | 139 | dots = VGroup(*[Dot(s, radius=.05) for s in simpson_pts_GR]) 140 | 141 | simps_elements = VGroup(dots, parab_approx, line, parab_area) 142 | if make_permanent: 143 | for_later_exp = [self.coords_to_point(simpson_pts[0], 0), self.coords_to_point(simpson_pts[1], 0), self.coords_to_point(simpson_pts[-1], 0)] 144 | first_iteration = simps_elements 145 | mini_par_graph = parab_approx 146 | print(for_later_exp) 147 | self.play(FadeOut(number_line)) 148 | 149 | nth_iteration.add(simps_elements) 150 | 151 | for k, c in zip(simps_elements, [0, 0, 0, 1]): 152 | if c != 0: 153 | self.play(Write(k)) 154 | if c == 0: 155 | self.play(ShowCreation(k)) 156 | 157 | make_permanent = False 158 | self.wait() 159 | 160 | iterations.add(nth_iteration) 161 | self.play(FadeOut(nth_iteration)) 162 | self.wait() 163 | # self.add(parab_approx, dots, line, parab_area) 164 | 165 | self.play(FadeOut(step_text)) 166 | # first_iteration = iterations[0][0] 167 | dots = first_iteration[0] 168 | x1, x2, x3 = for_later_exp 169 | y1, y2, y3 = [dot.get_center() for dot in dots] 170 | mini_par = VMobject(stroke_width=0, color=YELLOW, fill_opacity=.5) 171 | pts = [] 172 | 173 | # crap hardcode ffs revise later 174 | for p in mini_par_graph.points: 175 | if p[0] >= -4 and p[0] <= -0.72727273: 176 | pts.append(p) 177 | 178 | mini_par_points = [ 179 | y1, 180 | # *[self.input_to_graph_point(a, mini_par_graph) for a in np.arange(0, 4, 1)], # this didn't work for some reason T_T 181 | *pts, 182 | y1 183 | ] 184 | dots_copy = dots.copy() 185 | mini_par.set_points_as_corners( 186 | mini_par_points 187 | ).add(dots_copy) 188 | 189 | trap = VMobject(stroke_width=0, color=GREEN, fill_opacity=.5) 190 | trap.set_points_as_corners( 191 | [y1, 192 | y3, 193 | x3, x1, 194 | y1] 195 | ) 196 | 197 | x_labels = TexMobject("A", "B", "C").scale(.75) 198 | pseudo_dots = VGroup() 199 | for x_label, x_pos in zip(x_labels, for_later_exp): 200 | x_label.next_to(x_pos, direction=DOWN) 201 | x_point = Dot(radius=.00001).move_to(x_pos) 202 | pseudo_dots.add(x_point) 203 | 204 | # self.add(x_labels) 205 | lines = VGroup( 206 | *[DashedLine(dot.get_center(), x_pt, stroke_width=1) for dot, x_pt in zip(dots, for_later_exp)], 207 | *[DashedLine(dots[i].get_center(), dots[i + 1].get_center(), stroke_width=1) for i in range(3) if i != 2], 208 | DashedLine(y1, y3, stroke_width=1) 209 | ) 210 | par_n_dots = VGroup(first_iteration[::3], pseudo_dots, lines, x_labels) 211 | 212 | self.play(FadeIn(first_iteration)) 213 | self.x_axis.save_state() 214 | self.y_axis.save_state() 215 | self.play( 216 | self.x_axis.fade, 1, 217 | self.y_axis.fade, 1, 218 | FadeOut(graph), 219 | * [FadeOut(first_iteration[p]) for p in [1, 2]], 220 | ) 221 | 222 | plus_n_equal = TexMobject("=", "+") 223 | sum_of_two = VGroup(par_n_dots.copy(), plus_n_equal[0], mini_par, plus_n_equal[1], trap)\ 224 | .arrange_submobjects(direction=RIGHT, buff=.65) 225 | 226 | self.play(Transform(par_n_dots, sum_of_two[0])) 227 | 228 | # self.add(mini_par) 229 | 230 | self.play(AnimationGroup(*[FadeIn(mobj) for mobj in sum_of_two[1:]], lag_ratio=1)) 231 | # self.add(mini_par, trap) 232 | labels = TexMobject("y_{n-1}", "y_n", "y_{n+1}") 233 | labels_copy = labels.copy() 234 | 235 | for label, dot, direction in zip(labels, dots, [UP, UP, UR]): 236 | label.next_to(dot, direction=direction, buff=.04).scale(.75) 237 | 238 | for label_copy, dot_copy, direction in zip(labels_copy, dots_copy, [UL, UP, DOWN]): 239 | label_copy.next_to(dot_copy, direction=direction, buff=.01).scale(.65) 240 | 241 | numbered_labels = TexMobject("P_1", "P_2", "P_3") 242 | numbered_labels_copy = numbered_labels.copy() 243 | 244 | for numbered_label, dot, direction in zip(numbered_labels, dots, [UP, UP, UR]): 245 | numbered_label.next_to(dot, direction=direction, buff=.04).scale(.75) 246 | 247 | for numbered_label_copy, dot_copy, direction in zip(numbered_labels_copy, dots_copy, [UL, UP, DOWN]): 248 | numbered_label_copy.next_to(dot_copy, direction=direction, buff=.01).scale(.65) 249 | 250 | # self.add(labels, labels_copy) 251 | # self.play(WiggleOutThenIn(mini_par[-3:])) 252 | self.wait(2) 253 | 254 | self.play(Write(numbered_labels), Write(numbered_labels_copy), Write(x_labels)) 255 | self.wait() 256 | 257 | archimedes_triangle = get_triangle( 258 | [dot.get_center() for dot in dots_copy], 259 | stroke_width=1.5, 260 | color=RED, 261 | fill_opacity=.5 262 | ).add(numbered_labels_copy) 263 | 264 | tex_scale = .75 265 | sum_of_two[2].add(archimedes_triangle) 266 | self.play(FadeIn(archimedes_triangle)) 267 | four_thirds = TexMobject("\\dfrac{4}{3} \\,\\times").scale(tex_scale) 268 | multiple_tri_grp = VGroup(four_thirds, archimedes_triangle.copy()).arrange_submobjects(direction=RIGHT, buff=0.001) 269 | self.play(Transform(sum_of_two[2], multiple_tri_grp), sum_of_two[1].shift, LEFT * 0.4) 270 | 271 | eqn_RHS = TexMobject("\\dfrac{4}{3}\\,", "S_{\\tiny{P_1 P_2 P_3}}", "+", "\\, S_{\\small P_1 P_3 C A }").scale(tex_scale) 272 | sum_of_3_areas = TexMobject("\\dfrac{4}{3} \\Bigg(", "S_{P_1P_2BA}", "\\,+", "S_{P_2P_3CB}", "\\,-", "S_{P_1P_3CA}", "\\Bigg) +", "\\, S_{\\small P_1 P_3 C A }").scale(tex_scale) 273 | sum_of_3_areas.next_to(sum_of_two[1]) # .arrange_submobjects(direction=RIGHT) 274 | 275 | def get_trap(points, **kwargs): 276 | trap = VMobject(**kwargs) 277 | trap.set_points_as_corners([*points, points[0]]) 278 | return trap 279 | 280 | x1, x2, x3 = [pseudo_dot.get_center() for pseudo_dot in pseudo_dots] 281 | y1, y2, y3 = [dot.get_center() for dot in dots] 282 | 283 | trap_group = VGroup(*[get_trap(pts, stroke_width=0, fill_opacity=.5, fill_color=color,) for pts, color in zip([[y1, y2, x2, x1], [y2, y3, x3, x2], [y1, y3, x3, x1]], [YELLOW, PURPLE, GREEN])]) 284 | pseudo_arch_tri = get_trap([y1, y2, y3], stroke_width=0, fill_color=RED, fill_opacity=1) 285 | self.wait() 286 | self.play(ReplacementTransform(sum_of_two[2:], eqn_RHS)) 287 | self.wait() 288 | self.play(par_n_dots[0].fade, .75) 289 | self.wait() 290 | self.play(FadeIn(pseudo_arch_tri)) 291 | self.play( 292 | ReplacementTransform(eqn_RHS, sum_of_3_areas), 293 | # eqn_RHS[-1].move_to,eqn1_RHS[-2:-1].get_center() 294 | ) 295 | 296 | self.wait() 297 | self.play(FadeIn(trap_group[0]), Indicate(sum_of_3_areas[1])) 298 | for i, j in zip(range(0, 2), [3, 5]): 299 | self.play(ReplacementTransform(trap_group[i], trap_group[i + 1]), Indicate(sum_of_3_areas[j]), run_time=2) 300 | self.wait() 301 | self.play(FadeOut(pseudo_arch_tri), FadeOut(trap_group[-1])) 302 | sum_of_3_areas_2 = TexMobject( 303 | "\\dfrac{1}{3} \\Bigg(", 304 | "4\\,S_{P_1P_2BA}", 305 | "\\,+", "4\\,S_{P_2P_3CB}", 306 | "\\,-", "4\\,S_{P_1P_3CA}", 307 | " +", 308 | "\\, 3\\,S_{\\small P_1 P_3 C A }\\Bigg)" 309 | ).scale(tex_scale).next_to(sum_of_two[1]) 310 | 311 | self.play(ReplacementTransform(sum_of_3_areas, sum_of_3_areas_2)) 312 | self.wait() 313 | 314 | sum_of_3_areas_3 = TexMobject( 315 | "\\dfrac{1}{3} \\Bigg(", 316 | "4\\,S_{P_1P_2BA}", 317 | "\\,+", 318 | "4\\,S_{P_2P_3CB}", 319 | "\\,-", 320 | "\\,S_{P_1P_3CA}", 321 | "\\Bigg)" 322 | ).scale(tex_scale).next_to(sum_of_two[1]) 323 | self.play(ReplacementTransform(sum_of_3_areas_2, sum_of_3_areas_3)) 324 | self.wait() 325 | 326 | trap_area_texts = TexMobject("4\\,\\dfrac{y_1+y_2}{2}\\,\\Delta x", "4\\,\\dfrac{y_2+y_3}{2}\\,\\Delta x", "\\dfrac{y_1+y_3}{2} \\,(2\\Delta x)") 327 | 328 | for text, trap_area_text, scale_fac in zip([sum_of_3_areas_3[1], sum_of_3_areas_3[3], sum_of_3_areas_3[5]], trap_area_texts, [.55, .55, .5]): 329 | trap_area_text.scale(scale_fac) 330 | trap_area_text.move_to(text.get_center()) 331 | self.play(Transform(text, trap_area_text)) 332 | self.wait() 333 | 334 | # right_hand_side = VGroup(sum_of_3_areas_3) 335 | simpsons_rule = [ 336 | TexMobject("\\dfrac{\\Delta x}{3}(", "y_1", "+", "4\\,y_2", "+", "y_3", ")"), 337 | TexMobject("\\dfrac{\\Delta x}{3}(", "y_1", "+", "4\\,y_2", "+", "y_3", ")", "+", "\\dfrac{\\Delta x}{3}(", "y_3", "+", "4\\,y_4", "+", "y_5", ")", "+", "...", "\\\\", 338 | "+", "\\dfrac{\\Delta x}{3}(", "y_{n - 2}", " + ", "4\\, y_{n - 1}", " + ", "y_n", ")"), 339 | TexMobject("\\dfrac{\\Delta x}{3}\\Big[", "(y_1+y_n)", "+", "4\\,(y_2+y_4+...\\,+y_{n-1})", "\\\\ ", "+", "\\,2(y_3+y_5+...\\,+y_{n-2})", "\\Big]"), 340 | 341 | ] 342 | simpsons_rule[-1][-3:].shift(RIGHT * 2) 343 | for simp in simpsons_rule: 344 | simp.scale(tex_scale).next_to(sum_of_two[1]) 345 | 346 | axes_n_graph = VGroup(graph, integral, self.x_axis, self.y_axis).scale(.35).move_to(par_n_dots.get_center()) 347 | y_axis = Line(1.5 * DOWN, 1.5 * UP).move_to(self.y_axis).shift(0.05 * LEFT) 348 | x_axis = Line(2 * LEFT, 2 * RIGHT).move_to(self.x_axis).shift(0.05 * DOWN) 349 | 350 | axes_n_graph.add_to_back(x_axis, y_axis) 351 | 352 | self.play(ReplacementTransform(sum_of_3_areas_3, simpsons_rule[0])) 353 | self.wait() 354 | self.play(FadeOut(par_n_dots), FadeOut(numbered_labels)) 355 | self.play(ReplacementTransform(simpsons_rule[0], simpsons_rule[1]), FadeIn(axes_n_graph)) 356 | self.wait() 357 | self.play(ReplacementTransform(simpsons_rule[1], simpsons_rule[2])) 358 | self.wait() 359 | how = TextMobject("How").scale(2).to_edge(UP) 360 | self.add(how) 361 | self.play(*[FadeOut(mobj) for mobj in self.mobjects], run_time=5) 362 | 363 | 364 | #https://www.youtube.com/channel/UCKn6_1iFFC5fxSmFgVC9Fsw 365 | # You’re free to use this song in any of your videos, but you must include the following in your video description: 366 | # There's Probably No Time by Chris Zabriskie is licensed under a Creative Commons Attribution license (https://creativecommons.org/licenses/by/4.0/) 367 | # Source: http://chriszabriskie.com/uvp/ 368 | # Artist: http://chriszabriskie.com/ 369 | -------------------------------------------------------------------------------- /SupThevNor.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | def get_switch(): 5 | rr = RoundedRectangle(height=1, width=2) 6 | circ = Circle(radius=0.455) 7 | GREEN = "#5DFC0A" 8 | RED = "#FF0000" 9 | switch = VGroup() 10 | circ.set_fill(opacity=1, color=RED).set_stroke(width=0.01, color=RED) 11 | circ.align_to(rr.get_left(), direction=LEFT) 12 | rr_cp = rr.copy() 13 | rr_cp.add(circ) 14 | switch.add(rr_cp) 15 | 16 | circ_cp = circ.copy() 17 | circ_cp.set_fill(opacity=1, color=GREEN).set_stroke(width=0.01, color=GREEN) 18 | circ_cp.align_to(rr.get_right(), direction=RIGHT) 19 | rr_cp2 = rr.copy() 20 | rr_cp2.add(circ_cp) 21 | switch.add(rr_cp2) 22 | 23 | return switch 24 | 25 | 26 | class Intro(Scene): 27 | def construct(self): 28 | box = Square() 29 | ip = Line(LEFT, ORIGIN).align_to(box.get_vertices()[0], direction=UR).shift(DOWN * 0.25) 30 | ip_cp = ip.copy().align_to(box.get_vertices()[-1], direction=DR).shift(UP * 0.25) 31 | op = Line(LEFT, ORIGIN).align_to(box.get_right(), direction=LEFT) 32 | box.add(ip, ip_cp, op) 33 | self.add(box) 34 | -------------------------------------------------------------------------------- /ThreePhase.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class ThreePhase(Scene): 5 | CONFIG = { 6 | "radians": 0, 7 | "theta_2": 120 * DEGREES, 8 | "theta_3": 240 * DEGREES, 9 | "displacement": 4 * LEFT, 10 | "amp": 2, 11 | "t_offset": 0, 12 | "rate": 0.05, 13 | "x_min": -4, # xmin and max are to define the bounds of the horizontal graph 14 | "x_max": 9, 15 | "color_1": RED, 16 | "color_2": YELLOW, 17 | "color_3": BLUE, 18 | 19 | "axes_config": { 20 | "x_min": 0, 21 | "x_max": 10, 22 | "x_axis_config": { 23 | "stroke_width": 2, 24 | }, 25 | "y_min": -2.5, 26 | "y_max": 2.5, 27 | "y_axis_config": { 28 | "tick_frequency": 0.25, 29 | "unit_size": 1.5, 30 | "include_tip": False, 31 | "stroke_width": 2, 32 | }, 33 | }, 34 | "complex_plane_config": { 35 | "axis_config": { 36 | "unit_size": 2 37 | } 38 | }, 39 | } 40 | 41 | def construct(self): 42 | phase = self.rate 43 | t_tracker = ValueTracker(0) 44 | t_tracker.add_updater(lambda t, dt: t.increment_value(dt)) 45 | get_t = t_tracker.get_value 46 | 47 | def get_horizontally_moving_tracing(Vector, color, stroke_width=3, rate=0.25): 48 | path = VMobject() 49 | path.set_stroke(color, stroke_width) 50 | path.start_new_path(np.array([self.displacement[0], Vector.get_end()[1], 0])) 51 | path.Vector = Vector 52 | 53 | def update_path(p, dt): 54 | p.shift(rate * dt * 3 * RIGHT) 55 | p.add_smooth_curve_to(np.array([self.displacement[0], p.Vector.get_end()[1], 0])) 56 | path.add_updater(update_path) 57 | return path 58 | colorcircle = interpolate_color(BLACK, GREY, .5) 59 | circle = Circle(radius=2, stroke_width=1, color=colorcircle) 60 | 61 | axis = Axes(x_min=-2.5, x_max=10, y_min=-3, y_max=3, stroke_width=2, include_tip=False).shift(self.displacement) 62 | text = TextMobject("Real").move_to(6.5 * RIGHT) 63 | text1 = TextMobject("Img").move_to(4 * LEFT + 3.25 * UP) 64 | phase1 = Vector(2 * RIGHT, color=self.color_1) 65 | phase1.shift(self.displacement) 66 | 67 | phase2 = Vector(2 * RIGHT, color=self.color_2) 68 | phase2.shift(self.displacement) 69 | 70 | phase3 = Vector(2 * RIGHT, color=self.color_3) 71 | phase3.shift(self.displacement) 72 | 73 | subphase1 = DashedLine(phase1.get_end(), np.array([self.displacement[0], phase1.get_end()[1], 0]), color=self.color_1) 74 | subphase2 = DashedLine(phase2.get_end(), np.array([self.displacement[0], phase2.get_end()[1], 0]), color=self.color_2) 75 | subphase3 = DashedLine(phase3.get_end(), np.array([self.displacement[0], phase3.get_end()[1], 0]), color=self.color_3) 76 | circle.move_to(self.displacement) 77 | self.play(Write(axis), Write(text), Write(text1)) 78 | self.play(ShowCreation(circle)) 79 | 80 | phase1.add_updater(lambda t: t.set_angle(get_t())) 81 | phase2.add_updater(lambda t: t.set_angle(get_t() + 120 * DEGREES)) 82 | phase3.add_updater(lambda t: t.set_angle(get_t() + 240 * DEGREES)) 83 | 84 | subphase1.add_updater(lambda t: t.put_start_and_end_on(phase1.get_end(), np.array([self.displacement[0], phase1.get_end()[1], 0]))) 85 | subphase2.add_updater(lambda t: t.put_start_and_end_on(phase2.get_end(), np.array([self.displacement[0], phase2.get_end()[1], 0]))) 86 | subphase3.add_updater(lambda t: t.put_start_and_end_on(phase3.get_end(), np.array([self.displacement[0], phase3.get_end()[1], 0]))) 87 | 88 | self.play( 89 | ShowCreation(phase1,) 90 | ) 91 | self.play( 92 | ShowCreation(subphase1,) 93 | ) 94 | self.add(phase1, subphase1) 95 | self.add( 96 | t_tracker, 97 | ) 98 | traced_path1 = get_horizontally_moving_tracing(phase1, self.color_1) 99 | self.add( 100 | traced_path1, 101 | ) 102 | self.wait(2 * 2 * PI) 103 | 104 | traced_path1.suspend_updating() 105 | t_tracker.suspend_updating() 106 | 107 | self.play( 108 | ShowCreation(phase2,) 109 | ) 110 | arc1 = Arc(0, phase2.get_angle(), radius=.5, arc_center=self.displacement, color=YELLOW) 111 | label1 = TexMobject("120 ^\\circ").move_to(arc1.get_center() + .3 * UP + .5 * RIGHT).scale(.5) 112 | grp1 = VGroup(arc1, label1) 113 | self.play(ShowCreation(grp1)) 114 | self.wait() 115 | self.play(FadeOut(grp1)) 116 | 117 | self.play( 118 | FadeIn(subphase2, ) 119 | ) 120 | t_tracker.resume_updating() 121 | traced_path1.resume_updating() 122 | 123 | traced_path2 = get_horizontally_moving_tracing(phase2, self.color_2) 124 | self.add( 125 | traced_path2, 126 | ) 127 | self.wait(2 * PI) 128 | traced_path2.suspend_updating() 129 | traced_path1.suspend_updating() 130 | t_tracker.suspend_updating() 131 | self.play( 132 | ShowCreation(phase3,) 133 | ) 134 | self.play( 135 | FadeIn(subphase3,) 136 | ) 137 | 138 | arc2 = Arc(0, 240 * DEGREES, radius=.85, arc_center=phase1.points[0], color=BLUE) 139 | label2 = TexMobject("240 ^\\circ").move_to(arc2.get_center() + .4 * DOWN + .5 * RIGHT) 140 | grp2 = VGroup(arc2, label2).scale(.5) 141 | self.play(ShowCreation(grp2), run_time=2) 142 | self.wait() 143 | self.play(FadeOut(grp2)) 144 | 145 | t_tracker.resume_updating() 146 | traced_path1.resume_updating() 147 | traced_path2.resume_updating() 148 | 149 | traced_path3 = get_horizontally_moving_tracing(phase3, self.color_3) 150 | self.add( 151 | traced_path3, 152 | ) 153 | 154 | self.wait(5) 155 | -------------------------------------------------------------------------------- /TrapRule.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class TrapRule(GraphScene): 5 | CONFIG = { 6 | "x_min": -1, 7 | "x_max": 11, 8 | "x_axis_width": 10, 9 | 10 | "x_tick_frequency": 1, 11 | "x_leftmost_tick": None, # Change if different from x_min 12 | "x_labeled_nums": None, 13 | "x_axis_label": "$x$", 14 | "y_min": -1, 15 | "y_max": 11, 16 | "y_axis_height": 6, 17 | "y_tick_frequency": 2, 18 | "y_bottom_tick": None, # Change if different from y_min 19 | "y_labeled_nums": None, 20 | "y_axis_label": "$y$", 21 | "axes_color": BLACK, 22 | "graph_origin": 2.5 * DOWN + 4 * LEFT, 23 | "exclude_zero_label": True, 24 | "area_opacity": 0.8, 25 | "num_rects": 50, 26 | "x_axis_label_color": BLACK, 27 | "y_axis_label_color": BLACK, 28 | "camera_config": {"background_color": WHITE} 29 | 30 | } 31 | 32 | def get_parabola(self, pt1, pt2, pt3): 33 | a = np.array([[pt1[0]**2, pt1[0], 1], [pt2[0]**2, pt2[0], 1], [pt3[0]**2, pt3[0], 1]]) 34 | # print(a) 35 | b = np.array([pt1[1], pt2[1], pt3[1]]) 36 | # print(b) 37 | x = np.linalg.solve(a, b) 38 | return x 39 | 40 | def construct(self): 41 | # self.x_axis.x_label.set_color(BLACK) 42 | # self.y_axis.y_label.set_color(BLACK) 43 | 44 | def func(t): 45 | return .05 * t**3 - .55 * t**2 + t + 7 46 | 47 | ctp = self.coords_to_point 48 | itp = self.input_to_graph_point 49 | 50 | title = TextMobject("Trapezoidal Rule", color=BLACK).scale(2) 51 | self.play(Write(title)) 52 | self.play(title.to_edge, UP) 53 | self.play(FadeOut(title)) 54 | 55 | self.setup_axes(animate=True) 56 | 57 | graph = self.get_graph(func, stroke_width=3, color=RED) 58 | self.play(ShowCreation(graph)) 59 | 60 | integral = VMobject(stroke_width=0, fill_opacity=.5, color=YELLOW) 61 | integral_points = [ 62 | ctp(0, 0), 63 | *[itp(l, graph) for l in (np.arange(0, self.x_max - 1 + .1, .1))], 64 | ctp(self.x_max - 1, 0), 65 | ctp(0, 0), 66 | ] 67 | integral.set_points_as_corners(integral_points) 68 | self.play(FadeIn(integral)) 69 | area_text = TextMobject("Area = ?", color=BLACK).scale(1.5).move_to(integral.get_center() + 2 * DOWN) 70 | self.play(Write(area_text)) 71 | self.play(FadeOut(area_text), FadeOut(integral)) 72 | 73 | step_size = TexMobject("\\Delta x =", color=BLACK).to_edge(UP) 74 | step = DecimalNumber(2, color=BLACK).next_to(step_size) 75 | step_text = VGroup(step_size, step) 76 | 77 | number_line = VGroup(Line(ctp(0, 0), ctp(self.x_max - 1, 0), color=BLUE)) 78 | tick = Line(.125 * UP, .125 * DOWN, color=BLUE) 79 | for i in np.arange(0, self.x_max - 1 + 2, 2): 80 | tick_copy = tick.copy().move_to(ctp(i, 0)).shift(.4 * DOWN) 81 | number_line.add(tick_copy) 82 | 83 | measure_line = Line(ctp(0, 0), ctp(2, 0), color=PURPLE).shift(.4 * DOWN) 84 | delx = TexMobject("\\Delta x", color=BLACK).scale(.75).next_to(measure_line.get_center(), buff=.2, direction=DOWN) 85 | 86 | # n = 2 87 | 88 | iterations = VGroup() 89 | 90 | self.play(Write(number_line[0])) 91 | self.play(ApplyMethod(number_line[0].shift, .4 * DOWN)) 92 | self.play(Write(number_line[1:])) 93 | self.wait() 94 | self.play(WiggleOutThenIn(measure_line)) 95 | self.play(Write(delx)) 96 | self.wait() 97 | self.play(ReplacementTransform(delx, step_text), FadeOut(measure_line)) 98 | self.wait() 99 | 100 | def get_trapezoid(corners, **kwargs): 101 | trap = VMobject(**kwargs) 102 | trap.set_points_as_corners([*corners, corners[0]]) 103 | return trap 104 | 105 | def show_trap(x_samp): 106 | two_points = [itp(s, graph) for s in [x_samp, x_samp + n]] 107 | dots = VGroup() 108 | for s in two_points: 109 | dots.add(Dot(s, color=BLACK)) 110 | trapezoid = get_trapezoid( 111 | [ 112 | *two_points, 113 | *[ctp(s, 0) for s in [x_samp + n, x_samp]], 114 | itp(x_samp, graph) 115 | ], 116 | fill_color=BLUE, 117 | sheen_direction=RIGHT, 118 | fill_opacity=0.5, 119 | stroke_width=0 120 | ) 121 | trap_line = Line(dots[0].get_center(), dots[1].get_center(), color=BLACK) 122 | line = self.get_vertical_line_to_graph(x_samp + n, graph, line_class=DashedLine, color=BLUE) 123 | self.play(ShowCreation(dots)) 124 | self.play(Write(line), Write(trap_line)) 125 | self.play(FadeIn(trapezoid)) 126 | trap_elements = VGroup(trapezoid, dots, line, trap_line) 127 | nth_iteration.add(trap_elements) 128 | 129 | last_iteration = False 130 | first_iteration = True 131 | n_list = [2, 1] # , .5] 132 | for n in n_list: 133 | 134 | if n == n_list[-1]: 135 | last_iteration = True 136 | 137 | self.play(step.set_value, n) 138 | x_samps = np.arange(0, 8, n) 139 | nth_iteration = VGroup() 140 | 141 | for x_samp in x_samps: 142 | show_trap(x_samp) 143 | 144 | iterations.add(nth_iteration) 145 | if first_iteration: 146 | self.play(FadeOut(number_line)) 147 | 148 | if not last_iteration: 149 | self.play(FadeOut(nth_iteration)) 150 | 151 | if last_iteration: 152 | self.play(FadeOut(step_text)) 153 | self.wait() 154 | first_iteration = False 155 | # self.add(parab_approx, dots, line, parab_area) 156 | 157 | last_iteration = iterations[-1] 158 | 159 | graph_setup = VGroup(self.x_axis, self.y_axis, graph, last_iteration) 160 | self.play(graph_setup.scale, .5, {"about_point": ORIGIN}) 161 | self.play(graph_setup.to_edge, LEFT) 162 | 163 | temp_grp = VGroup(last_iteration[2:-1]) 164 | for i in [0, 1, 2, -1]: 165 | if i != 2: 166 | last_iteration[i].save_state() 167 | last_iteration[i].fade(1) 168 | else: 169 | print(i) 170 | temp_grp.save_state() 171 | print("saved") 172 | temp_grp.fade(1) 173 | 174 | # self.wait(2) 175 | trap_formula_crude = TexMobject( 176 | "=", 177 | "\\dfrac{y_1+y_2}{2}\\,\\Delta x", 178 | "+", 179 | "\\dfrac{y_2+y_3}{2}\\,\\Delta x", 180 | "+", 181 | "...", 182 | "\\\\\\,+" 183 | "\\dfrac{y_{n-1}+y_{n}}{2}\\,\\Delta x", 184 | color=BLACK, 185 | ).next_to(graph_setup).shift(DOWN) 186 | self.play(Write(trap_formula_crude[0])) 187 | self.wait() 188 | self.play(AnimationGroup(ApplyMethod(last_iteration[0].restore), Write(trap_formula_crude[1:3]), lag_ratio=.5)) 189 | self.wait() 190 | self.play(AnimationGroup(ApplyMethod(last_iteration[1].restore), Write(trap_formula_crude[3:5]), lag_ratio=.5)) 191 | self.wait() 192 | self.play(AnimationGroup(ApplyMethod(temp_grp.restore), Write(trap_formula_crude[5]), lag_ratio=.5)) 193 | self.wait() 194 | self.play(AnimationGroup(ApplyMethod(last_iteration[-1].restore), Write(trap_formula_crude[6:]), lag_ratio=.5)) 195 | self.wait(2) 196 | 197 | trap_formula = TexMobject( 198 | "\\dfrac{\\Delta x}{2}\\,", 199 | "\\Big[", 200 | "(y_1+y_n)", 201 | "+", 202 | "2\\,(y_2+y_3+...+y_{n-1})", 203 | "\\Big]", 204 | color=BLACK, 205 | ).scale(.75).next_to(trap_formula_crude[0]) 206 | self.play(ReplacementTransform(trap_formula_crude[1:], trap_formula)) 207 | self.wait() 208 | self.play(*[FadeOut(mobj) for mobj in self.mobjects], run_time=5) 209 | -------------------------------------------------------------------------------- /TrigPowerSeries.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | FRAME_WIDTH = 16 4 | FRAME_HEIGHT = 20 5 | 6 | 7 | class PowerSeries(MovingCameraScene): 8 | CONFIG = { 9 | "x_min": -FRAME_WIDTH / 2, 10 | "x_max": FRAME_WIDTH / 2, 11 | "x_axis_width": FRAME_WIDTH * 2, 12 | "y_min": -FRAME_HEIGHT / 2, 13 | "y_max": FRAME_HEIGHT / 2, 14 | "y_axis_height": FRAME_HEIGHT * 2, 15 | "graph_origin": ORIGIN, 16 | "x_axis_label": None, 17 | "y_axis_label": None, 18 | 19 | } 20 | 21 | def construct(self): 22 | 23 | scale_fac = 3 24 | theta = PI / 2 25 | 26 | # init_seg = VMobject().set_points_as_corners([2 * UP, UR * 1.5, 2 * RIGHT, DR * 1.5, DOWN * 2]) 27 | init_seg = RegularPolygon(n=500, start_angle=PI / 2).scale(scale_fac) 28 | # init_seg = FunctionGraph(lambda x: x**2, x_max=2, x_min=-2) 29 | 30 | # radii = VGroup(Line(ORIGIN, init_seg.points[0]), Line(ORIGIN, init_seg.points[-1])) 31 | self.add(init_seg) # , radii) 32 | # pseudo_points = [2 * UP, UR * 1.5, 2 * RIGHT, DR * 1.5, DOWN * 2] 33 | rev = init_seg.get_vertices() 34 | pseudo_points = rev[:126] 35 | 36 | trace_line = Line(pseudo_points[0], pseudo_points[1] + UP * 0.0001, color=YELLOW) 37 | self.add(trace_line) 38 | path = VMobject(color=PURPLE).set_points_as_corners([init_seg.get_top(), init_seg.get_top() + UP * 0.001]) 39 | self.add(path) 40 | 41 | for _ in range(3): 42 | for i in range(len(pseudo_points) - 2): 43 | # self.play(trace_line.put_start_and_end_on, pseudo_points[i], pseudo_points[i + 1]) 44 | tgt_angle = (angle_of_vector(pseudo_points[i + 1] - pseudo_points[i + 2]) - angle_of_vector(pseudo_points[i] - pseudo_points[i + 1])) 45 | # self.play(trace_line.rotate, tgt_angle, {"about_point": pseudo_points[i + 1]}) 46 | # x = i + 1 47 | # if _ != 0: 48 | # self.play(trace_line.scale_about_point, i, pseudo_points[i + 1]) 49 | # else: 50 | # self.play(trace_line.scale_about_point, i + 1, pseudo_points[i + 1]) 51 | 52 | trace_line.put_start_and_end_on(pseudo_points[i], pseudo_points[i + 1])\ 53 | .rotate(tgt_angle, about_point=pseudo_points[i + 1]) 54 | 55 | if _ != 0: 56 | trace_line.scale_about_point(i, pseudo_points[i + 1]) 57 | else: 58 | trace_line.scale_about_point(i + 1, pseudo_points[i + 1]) 59 | 60 | path.add_points_as_corners([trace_line.points[0]]) 61 | # self.add(trace_line.copy()) 62 | # self.add(Dot(trace_line.copy().points[0])) 63 | if i == len(pseudo_points) - 3: 64 | # self.add(Line(path[-1], trace_line.points[0], color=YELLOW)) 65 | self.add(trace_line.copy()) 66 | print(angle_of_vector(trace_line.points[0] - trace_line.points[1])) 67 | if _ == 2: 68 | self.camera_frame.move_to(init_seg.get_top()) 69 | # self.camera_frame.scale(0.25) 70 | self.add(path) 71 | 72 | pseudo_points = self.discretise(path).vertices 73 | # self.add(self.discretise(path)) 74 | path = VMobject(color=RED).set_points_as_corners([pseudo_points[0] + UP * 0.000000001, pseudo_points[0]]) 75 | self.wait() 76 | 77 | def discretise(self, func): 78 | prez = 5 79 | samples = np.arange(0, 1, 1 / 10**prez) 80 | # print(len(samples)) 81 | pfp = func.point_from_proportion 82 | a = 0 83 | n = 0.1 84 | lin_aprox = VMobject() 85 | lin_aprox.vertices = [pfp(a), pfp(a) + UP * 0.0001] 86 | lin_aprox.set_points_as_corners(lin_aprox.vertices) 87 | 88 | def next_point(samples, a): 89 | for i, s in enumerate(samples): 90 | norm = round(abs(np.linalg.norm(pfp(s) - pfp(a))), prez - 1) 91 | if norm == n: 92 | lin_aprox.vertices.append(pfp(s)) 93 | lin_aprox.add_points_as_corners([pfp(s)]) 94 | return i 95 | 96 | while abs(np.linalg.norm(pfp(samples[0]) - pfp(samples[-1]))) > n: 97 | i = next_point(samples, a) 98 | a = samples[i] 99 | samples = samples[i:] 100 | 101 | return lin_aprox 102 | -------------------------------------------------------------------------------- /TrippyCircleGif.py: -------------------------------------------------------------------------------- 1 | from manimlib.imports import * 2 | 3 | 4 | class Trippy(Scene): 5 | CONFIG = { 6 | "camera_config": {"background_color": GREY} 7 | } 8 | 9 | def construct(self): 10 | donut = VGroup(*[AnnularSector(inner_radius=1.25, angle=PI, fill_color=i) for i in [WHITE, BLACK]]) 11 | donut[1].rotate(PI, about_point=ORIGIN) 12 | self.play(GrowFromCenter(donut)) 13 | self.add(donut) 14 | self.wait() 15 | donut_copy1 = donut.copy().scale(1.00451) # .rotate(PI / 4, about_point=ORIGIN) 16 | donut_copy2 = donut.copy().scale(1.00451) # .rotate(-PI / 4, about_point=ORIGIN) 17 | 18 | self.play( 19 | AnimationGroup( 20 | ApplyMethod(donut_copy1.move_to, 5 * RIGHT), 21 | ApplyMethod(donut_copy2.move_to, 5 * LEFT), 22 | lag_ratio=0.5 23 | ) 24 | ) 25 | self.play( 26 | AnimationGroup( 27 | ApplyMethod(donut_copy1.rotate, PI / 4, {"about_point": donut_copy1.get_center()}), 28 | ApplyMethod(donut_copy2.rotate, -PI / 4, {"about_point": donut_copy2.get_center()}), 29 | lag_ratio=0.5 30 | ) 31 | ) 32 | self.wait() 33 | self.play(FadeOut(donut)) 34 | offset = 0.04 35 | self.play( 36 | donut_copy1.move_to, offset * RIGHT, 37 | donut_copy2.move_to, offset * LEFT 38 | ) 39 | self.play(FadeIn(donut)) 40 | self.wait() 41 | 42 | def keep_rotating(mob, dt): 43 | mob.rotate(-25 * dt) # 17 44 | 45 | # def donut_updater(mob): 46 | # self.add(mob) 47 | # donut.add_updater(donut_updater) 48 | 49 | for _ in [donut, donut_copy1, donut_copy2]: 50 | _.add_updater(keep_rotating) 51 | self.add(donut_copy1, donut_copy2, donut) 52 | 53 | self.wait(5) 54 | 55 | truth = VGroup( 56 | *[ 57 | Line(TOP, BOTTOM, color=WHITE, stroke_width=2).move_to(_).scale(2) 58 | for _ in [donut_copy2.get_left() + 0.025 * LEFT, donut_copy1.get_right() + 0.025 * RIGHT] 59 | ] 60 | ) 61 | self.play(FadeIn(truth)) 62 | self.wait(5) 63 | self.remove(truth) 64 | wheel = VGroup(*[donut, donut_copy1, donut_copy2]) 65 | 66 | self.play(FadeOut(wheel)) 67 | for _ in [donut, donut_copy1, donut_copy2]: 68 | _.clear_updaters() 69 | 70 | # nov = 6 # 10 71 | # wheels = [wheel.copy().scale(1.1) for _ in range(nov)] # 0.75 72 | 73 | # poly = RegularPolygon(n=nov, color=WHITE).scale(4.5) 74 | # # self.add(poly) 75 | # for i, v in enumerate(poly.get_vertices()): 76 | # for _ in range(3): 77 | # wheels[i][_].add_updater(keep_rotating) 78 | # self.add(wheels[i].copy().rotate(((i + 1) * TAU / nov) + PI / 6).move_to(v)) 79 | 80 | # self.wait(7) 81 | # self.play(FadeIn(poly)) 82 | # self.wait(2) 83 | # self.play(FadeOut(poly)) 84 | # self.wait() 85 | --------------------------------------------------------------------------------