diff --git a/.gitignore b/.gitignore index 88230a54..f10a0816 100644 --- a/.gitignore +++ b/.gitignore @@ -143,4 +143,7 @@ dmypy.json # End of https://www.toptal.com/developers/gitignore/api/python # Custom exclusions: -.DS_Store \ No newline at end of file +.DS_Store + +# +/videos \ No newline at end of file diff --git a/example_scenes.py b/example_scenes.py index 8cfd3cd3..fb32966b 100644 --- a/example_scenes.py +++ b/example_scenes.py @@ -111,6 +111,9 @@ class SquareToCircle(Scene): class TexTransformExample(Scene): def construct(self): + kw = { + "substrings_to_isolate": ["B", "C", "="] + } lines = VGroup( # Surrounding substrings with double braces # will ensure that those parts are separated @@ -119,10 +122,14 @@ class TexTransformExample(Scene): # to the strings [A^2, +, B^2, =, C^2] TexMobject("{{A^2}} + {{B^2}} = {{C^2}}"), TexMobject("{{A^2}} = {{C^2}} - {{B^2}}"), - TexMobject( - "A = \\sqrt{(C + B)(C - B)}", - substrings_to_isolate=["A", "B", "C"] - ), + # Alternatively, you can pass in the keyword argument + # substrings_to_isolate with a list of strings that + # should be broken out as their own submobject. So + # both lines below are equivalent to what you'd get + # by wrapping every instance of "B", "C" and "=" with + # double braces + TexMobject("{{A^2}} = (C + B)(C - B)", **kw), + TexMobject("A = \\sqrt{(C + B)(C - B)}", **kw) ) lines.arrange(DOWN, buff=LARGE_BUFF) for line in lines: @@ -133,28 +140,68 @@ class TexTransformExample(Scene): }) self.add(lines[0]) - # The animation TransformMatchingTex will line up parts - # of the source and target which have matching tex strings - self.play(TransformMatchingTex( - lines[0].copy(), lines[1], - run_time=2, path_arc=90 * DEGREES, - )) + # of the source and target which have matching tex strings. + # Here, giving it a little path_arc makes each part sort of + # rotate into their final positions, which feels appropriate + # for the idea of rearranging an equation + self.play( + TransformMatchingTex( + lines[0].copy(), lines[1], + path_arc=90 * DEGREES, + ), + ) self.wait() - # The animation TransformMatchingShapes will line up parts - # of the source and target which have matching shapes, regardless - # of where they fall in the mobject family heirarchies. - # For example, calling TransformMatchingTex below would not - # quite look like we want, becuase lines[2] has none of its - # substringsisolated, and even if it did it would not know to - # match the symbol "C", say, from line[1] to the "C" from line[2], - # since in line[1] it is tied up with the full C^2 submobject. - # However, TransformMatchingShapes just does its best to pair - # pieces which look the same - self.play(TransformMatchingShapes( - lines[1].copy(), lines[2], - run_time=2, - )) + + # Now, we could try this again on the next line... + self.play( + TransformMatchingTex(lines[1].copy(), lines[2]), + ) + self.wait() + # ...and this looks nice enough, but since there's no tex + # in lines[2] which matches "C^2" or "B^2", those terms fade + # out to nothing while the C and B terms fade in from nothing. + # If, however, we want the C to go to C, and B to go to B, but + # we don't want to think about breaking up the tex string + # differently, we could instead try TransformMatchingShapes, + # which will line up parts of the source and target which + # have matching shapes, regardless of where they fall in the + # mobject family heirarchies. + self.play(FadeOut(lines[2])) + self.play( + TransformMatchingShapes(lines[1].copy(), lines[2]), + ) + # That's almost what we want, but if you were finicky you + # might complain that all the exponents from lines[1] got + # to the 2 in A^2, since that's the only part of lines[2] + # which matches the shape of a 2. In this case, one option + # would be to use TransformMatchingTex on the left-hand-side, + # but TransformMatchingShapes on the right-hand-side + eq_index = lines[1].index_of_part_by_tex("=") + self.play(FadeOut(lines[2])) + self.play( + TransformMatchingTex( + lines[1][:eq_index].copy(), + lines[2][:eq_index], + ), + TransformMatchingShapes( + lines[1][eq_index:].copy(), + lines[2][eq_index:], + ), + ) + self.wait() + + # And to finish off, a simple TransformMatchingShapes will do, + # though maybe we really want that exponent from A^2 to turn + # into the square root, so we set fade_transform_mismatches to + # True so that parts with mis-matching shapes transform into + # each other. + self.play( + TransformMatchingShapes( + lines[2].copy(), lines[3], + fade_transform_mismatches=True, + ), + ) self.wait()