Aligning Text – manim Series: Part 6

You can find the previous post in this series here and the overview of the entire series here.

6.0 Aligning Text and Using Braces

This post will show how to use braces to visually group equations or text together but also how to align text elements. We will first write a program to align elements of two equations but in a somewhat clunky fashion; this is not the most elegant way to accomplish this task. After looking at this first version we will rewrite the code in a more concise fashion that lines everything up even better.

Copy and paste the following code and run it.

class UsingBraces(Scene):
    #Using braces to group text together
    def construct(self):
        eq1A = TextMobject("4x + 3y")
        eq1B = TextMobject("=")
        eq1C = TextMobject("0")
        eq2A = TextMobject("5x -2y")
        eq2B = TextMobject("=")
        eq2C = TextMobject("3")
        eq1B.next_to(eq1A,RIGHT)
        eq1C.next_to(eq1B,RIGHT)
        eq2A.shift(DOWN)
        eq2B.shift(DOWN)
        eq2C.shift(DOWN)
        eq2A.align_to(eq1A,LEFT)
        eq2B.align_to(eq1B,LEFT)
        eq2C.align_to(eq1C,LEFT)

        eq_group=VGroup(eq1A,eq2A)
        braces=Brace(eq_group,LEFT)
        eq_text = braces.get_text("A pair of equations")

        self.add(eq1A, eq1B, eq1C)
        self.add(eq2A, eq2B, eq2C)
        self.play(GrowFromCenter(braces),Write(eq_text))

To line up parts of the equations on screen we use next_to() and align_to(). For this example we’ve broken the equation into smaller parts and then used next_to() to place the subparts of each equation next to each other and then align_to() to line up the left side of each part of the equation. You can also use UP, DOWN, and RIGHT to align different edges of the mobjects. We’ve also added a brace to show how to visually group a set of equations. In order to use the braces we must use VGroup() to combine the equations. When we instantiate the braces the first argument is the group and the second argument is where the braces are located relative to the grouping. You can set the text next to the braces using get_text(). This method does not draw the text on the screen, it is only used to set the location of the text relative to the braces so you will still need to add the text to the screen.

class UsingBracesConcise(Scene):
    #A more concise block of code with all columns aligned
    def construct(self):
        eq1_text=["4","x","+","3","y","=","0"]
        eq2_text=["5","x","-","2","y","=","3"]
        eq1_mob=TexMobject(*eq1_text)
        eq2_mob=TexMobject(*eq2_text)
        eq1_mob.set_color_by_tex_to_color_map({
            "x":RED_B,
            "y":GREEN_C
            })
        eq2_mob.set_color_by_tex_to_color_map({
            "x":RED_B,
            "y":GREEN_C
            })
        for i,item in enumerate(eq2_mob):
            item.align_to(eq1_mob[i],LEFT)
        eq1=VGroup(*eq1_mob)
        eq2=VGroup(*eq2_mob)
        eq2.shift(DOWN)
        eq_group=VGroup(eq1,eq2)
        braces=Brace(eq_group,LEFT)
        eq_text = braces.get_text("A pair of equations")

        self.play(Write(eq1),Write(eq2))
        self.play(GrowFromCenter(braces),Write(eq_text))

Here is a more concise version of the previous code. Each equation is written out as a list with each part of the equation as a separate string. This allows more control over the vertical alignment of the parts of the two equations. Inside the for loop we use align_to() to line up the left edge of the elements in eq1 and eq2.

Notice that when creating the texmobjects that we passed the variable name of the list with an asterisk in front of it eq1_mob=TexMobject(*eq1_text). The asterisk is a Python command to unpack the list and treat the argument as a comma-separated list. Thus eq1_mob=TexMobject(*eq1_text) is identical to eq1_mob=TexMobject("4","x","+","3","y","=","0").

Things to try:
– Arrange the equations on the screen
– Add some shapes around your equations.

 

Next up: Plotting graphs in manim

Advertisements
Posted in Just for Fun, Programming | Tagged , , , | 3 Comments

Mathematical Equations – manim Series: Part 5

You can find the previous post in this series here and the overview of the entire series here.

5.0 Mathematical Equations

A math animation package wouldn’t be much use if you couldn’t include nice looking equations. The best way I know of to typeset equations is using LaTeX (\LaTeX) , which manim makes use of. If you’d like to learn more about typesetting with LaTeX I’d recommend the tutorials at ShareLaTeX for a basic intro, but you don’t need to know much about LaTeX to use manim. You can find a list of commonly used symbols here, which is about all you need to know for manim.

Copy and paste the code into a .py file and use extract_scene.py to run the following scene:

class BasicEquations(Scene):
    #A short script showing how to use Latex commands
    def construct(self):
        eq1=TextMobject("$\\vec{X}_0 \\cdot \\vec{Y}_1 = 3$")
        eq1.shift(2*UP)
        eq2=TexMobject("\\vec{F}_{net} = \\sum_i \\vec{F}_i")
        eq2.shift(2*DOWN)

        self.play(Write(eq1))
        self.play(Write(eq2))

In LaTeX you normally enclose an equation with dollar signs $$ to denote an equation and that works here as well. The main difference is that, due to how manim parses the text, an extra backslash must be included in front of all LaTeX commands. For instance Greek letters can be created in LaTeX by typing out the name of the letter preceded by a backslash; lower case alpha \alpha would be $\alpha$, the angle theta \theta would be $\theta$. In manim, however, a double backslash is needed so \alpha would be $\\alpha$ and \theta would be written as $\\theta$.

You can place a vector arrow over a variable such as \vec{A} using \vec{A} or, since manim requires double backslashes, \\vec{A}. Whatever you place inside the brackets will show up on screen with an arrow over it. Subscripts are denoted by the underscore so \vec{X}_0 would be written as $\vec{X}_0$. If the subscript consists of more than a single character you can enclose the subscript in brackets. Thus \vec{F}_{net} in manim would be $\\vec{F}_{net}$.

It can get tedious having to always include the dollar signs so the TexMobject class assumes all strings are math objects. TEX (\TeX) is the typesetting language that LaTeX is based on so I assume TexMobject is named for TEX. The main difference between TextMobject() and TexMobject is the text math object assumes everything is plain text unless you specify an equation with dollar signs while the Tex math object assumes everything is an equation unless you specify something is plain text using \\text{}.

When mobjects of any sort are created the default position seems to be the center of the screen. Once created you can use shift() or move_to to change the location of the mobjects. For this example above I’ve moved the equations either two MUnits up or two MUnits down (remember that the MUnit or math unit is what I call the measure of length inside manim). Since the screen height is set to a default of 8 MUnits, a 2 MUnit shift corresponds to about a quarter of the screen height.

The Write() method, which is a sublcass of ShowCreation, takes a TextMobject or TexMobject and animates writing the text on the screen. You can also pass a string to Write() and it will create the TextMobject for you. Write() needs to be inside of play() in order to animate it.

5.1 Coloring Equations

class ColoringEquations(Scene):
    #Grouping and coloring parts of equations
    def construct(self):
        line1=TexMobject("\\text{The vector }", "\\vec{F}_{net}", "\\text{ is the net force on object of mass }")
        line1.set_color_by_tex("force", BLUE)
        line2=TexMobject("m", "\\text{ and acceleration }", "\\vec{a}", ".  ")
        line2.set_color_by_tex_to_color_map({
            "m": YELLOW,
            "{a}": RED
        })
        sentence=VGroup(line1,line2)
        sentence.arrange_submobjects(DOWN, buff=MED_LARGE_BUFF)
        self.play(Write(sentence))

For this example we have broken our text into blocks of plain text and equations. This allows us to color the equations using either set_color_by_tex() or set_color_by_tex_to_color_map(). The set_color_by_tex() method takes the individual string you want colors and the color as arguments. It looks like you only have to specify part of a string to match but the entire string gets colored. For instance, if we type in line1.set_color_by_tex("F",BLUE), the only place a capital F occurs is in the force variable so the whole net force variable is colored blue. If instead we try line1.set_color_by_tex("net",BLUE), the term net appears in two places in line1 so both the force variable and the string is the net force on object of mass are colored blue. If you want to change the color of multiple elements within a list of texmobjects you can use set_color_by_tex_to_color_map() and a dictionary. The key for the dictionary should be the text we want colored (or a unique part of the string) and the value should be the desired color.

Notice that, since we are using a texmobject and not a textmobject, we have to enclose plain text in the LaTeX command \\text{}. If you don’t do this the text is assumed to be part of an equation so the font and spacing are of the text looks funny. Thus “the net force on object of mass” would look like the net force on object of mass. The equation environment doesn’t recognize spaces between words, uses a different font, and spaces the letters differently than normal text.

By grouping the two lines together with VGroup(), we can use the arrange_submobjects() method to space out the two lines. The first argument is the direction you want the objects spaced out and buff (I assume) is the buffer distance between the mobjects. There are several default buffer distances defined in constants.py but you can also a single number. The smallest default buffer is SMALL_BUFF=0.1 and the largest is LARGE_BUFF=1. Although I didn’t dive into the code, I think the way the buffers work is as a multiplicative factor of one of the main directional vectors (e.g. UP, DOWN, LEFT, RIGHT) so that specifying SMALL_BUFF and LEFT would be equivalent to $0.1*(-1,0,0) = (-0.1,0,0)$.

Things to try:
– Create your own equations using the symbols here.
– Try changing the colors of different parts of the equations

 

In the next post in this series we’ll look at how to align text.

Posted in Just for Fun, Programming | Tagged , , , | 3 Comments

Creating Text – manim Series: Part 4

You can find the previous post in this series here and the overview of the entire series here.

4.0 Creating Text

There is a special subclass of Mobject called a TextMobject (a text math object). Add the following class to your manim_tutorial_1.py file and type python extract_scene.py manim_tutorial_1.py Shapes -pl at the command line. Note that the text looks really fuzzy because we are rending the animations at low quality to speed things up. With a small file like this you could render it at full resolution without taking too much time. To do this, replace -pl with -p (leaving off the low resolution tag).

class AddingText(Scene):
    #Adding text on the screen
    def construct(self):
        my_first_text=TextMobject("Writing with manim is fun")
        second_line=TextMobject("and easy to do!")
        second_line.next_to(my_first_text,DOWN)
        third_line=TextMobject("for me and you!")
        third_line.next_to(my_first_text,DOWN)

        self.add(my_first_text, second_line)
        self.wait(2)
        self.play(Transform(second_line,third_line))
        self.wait(2)
        second_line.shift(3*DOWN)
        self.play(ApplyMethod(my_first_text.shift,3*UP))

To create a textmobject you must pass it a valid string as an argument. Text rendering is based on Latex so you can use many Latex typesetting features; I’ll get into that in a later post. As a subclass of mobjects, any method such as move_to, shift, and next_to can be used with textmobjects.

The wait() method will prevent the next command for the scene from being executed for the desired number of seconds. The default time is 1 second so calling self.wait() will wait 1 second before executing the next command in your script.

You should notice that, during the animation, the second line jumps down while the top line gently glides up. This has to do with the fact that we applied the shift() method to the second line but we created an animation of the shift to the first line. When animating a mobject() method the ApplyMethod() animation is needed. Notice the arguments of ApplyMethod() is a pointer to the method (in this case my_first_text.shift without any parentheses) followed by a comma and then the what you would normally include as the argument to the shift() method. In other words, ApplyMethod(my_first_text.shift,3*UP) will create an animation of shifting my_first_text three MUnits up.

4.1 Changing Text

Add this code to your tutorial file and extract the following scene.

class AddingMoreText(Scene):
    #Playing around with text properties
    def construct(self):
        quote = TextMobject("Imagination is more important than knowledge")
        quote.set_color(RED)
        quote.to_edge(UP)
        quote2 = TextMobject("A person who never made a mistake never tried anything new")
        quote2.set_color(YELLOW)
        author=TextMobject("-Albert Einstein")
        author.scale(0.75)
        author.next_to(quote.get_corner(DOWN+RIGHT),DOWN)

        self.add(quote)
        self.add(author)
        self.wait(2)
        self.play(Transform(quote,quote2),ApplyMethod(author.move_to,quote2.get_corner(DOWN+RIGHT)+DOWN+2*LEFT))
        self.play(ApplyMethod(author.match_color,quote2),Transform(author,author.scale(1)))
        self.play(FadeOut(quote))

Here we see how to change the color of text using set_color(). This uses the same colors discussed in relation to drawing geometric shapes, many of which are defined in the COLOR_MAP dictionary in constants.py. In addition to setting the color, you can also match the color to another object. In the second to last line of code above we use match_color() to change the color of the author to match quote2.

You can change the size of text using scale(). This method scales the mobject up by the numerical factor given. Thus scale(2) will double the size of a mobject while scale(0.3) will shrink the mobject down to 30% of its size. It doesn’t seem you can use scale() in an animation (ApplyMethod(author.scale,2) doesn’t work). There is probably a better way around this but what I would do if I wanted to animate a scale-up or down is create a second textmobject that
is the final size I want and use Transform() to smoothly shift from one scale to another. Hopefully I’ll figure out a better way to do this later on.

You can align mobjects with the center of the edge of the screen by telling to_edge() whether you want the object to be UP, DOWN, LEFT, or RIGHT. You can also use to_corner(), in which case you need to combine two directions such as UP+LEFT to indicate the corner.

Each mobject has a bounding box and you can get the coordinates of the corners of this bounding box using get_corner() and specifying a direction. Thus get_corner(DOWN+LEFT) will return the location of the lower left corner of a mobject. In our example we find the lower right corner of quote and place the author one unit down from that point. Later we move the author down and slightly left of quote2.

An important thing to note is that the Transform() animation still leaves the mobject quote on the screen but has just changed its display text and properties to be those of quote2. This is why FadeOut() refers to quote and not quote2. However, the corner of quote is where it was originally, which is why we have to find the corner of quote2 to move author to the correct location. Keep in mind that when you use Tranform, properties of the mobects involved might not be what you think they are so beware.

Another useful piece of information is that the scale() method changes the size of the objects as it currently is.  In other words, using scale(.5) followed by scale(.25) results in an object that is $0.5*0.25 = 0.125$ times the original size

Things to try:
– Try using the to_corner() method
– Check out COLOR_MAP in the constants.py file and change the color of the text

4.2 Rotating and Highlighting Text

The following code will demonstrate how to rotate text and give it some pizzazz. As usual, copy the code into your tutorial file and extract it using python extract_scene.py manim_tutorial_1.py RotateAndHighlight -p

class RotateAndHighlight(Scene):
    #Rotation of text and highlighting with surrounding geometries
    def construct(self):
        square=Square(side_length=5,fill_color=YELLOW, fill_opacity=1)
        label=TextMobject("Text at an angle")
        label.bg=BackgroundRectangle(label,fill_opacity=1)
        label_group=VGroup(label.bg,label)  #Order matters
        label_group.rotate(TAU/8)
        label2=TextMobject("Boxed text",color=BLACK)
        label2.bg=SurroundingRectangle(label2,color=BLUE,fill_color=RED, fill_opacity=.5)
        label2_group=VGroup(label2,label2.bg)
        label2_group.next_to(label_group,DOWN)
        label3=TextMobject("Rainbow")
        label3.scale(2)
        label3.set_color_by_gradient(RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE)
        label3.to_edge(DOWN)

        self.add(square)
        self.play(FadeIn(label_group))
        self.play(FadeIn(label2_group))
        self.play(FadeIn(label3))

We’ve added a square in the background to show what BackgroundRectangle does. Note that the opacity of the fill color defaults to zero so if you don’t define the fill_opacity you only see the edges of the square. To create a background rectange you need to specify the textmobject to apply this method to, as well as the opacity. You can’t change the color background to anything but black.

The VGroup class allows you to combine multiple mobjects into a single vectorized math object. This allows you to apply any VMobject methods to the all elements of the group. You are still able change properties of the orignal mobjects after they are groups. In other words, the original mobjects are not destroyed, the vmobject is just a higher level grouping of the mobjects. By grouping the text and the background rectangle we can then use rotate() to change the orientation of both objects together. Note that TAU is equal to $2 \pi$ (see the Tau Manifesto, which makes some interesting points).

The next_to() method can be thought of as a shift relative to some other object so label2_group.next_to(label_group,DOWN) places label2_group shifted down one unit from label1_group (remember that the unit of distance is set by the FRAME_HEIGHT variable in constants.py and the default screen height is 8 units).

You can create a a color gradient using set_color_by_gradient(). Pass the method any number of colors, separated by commas.

Things to play with
– Try changing the fill opacity for both the square and the background rectangle
– Try rotating the background rectangle separately from the the text
– Change the color of label2 to see how it affects the readability of the text
– Change the colors of “Rainbow”
– Place the “Rainbow” text on a different edge of the screen.

NOTE: If anything in these posts isn’t making sense, please leave a comment. I hope to continue to edit these posts to clarify and help people learn how to use manim so feedback is appreciated.

You can find a copy of this code at https://github.com/zimmermant/manim_tutorial

Posted in Just for Fun, Programming | Tagged , , , | 3 Comments

More Shapes – manim Series: Part 3

You can find the previous post in this series here and the overview of the entire series here.

3.0 More Shapes

You can create almost any geomtric shape using manim. You can create circles, squares, rectangles, ellipses, lines, and arrows. Let’s take a look at how to draw some of those shapes.

Copy and paste the code below into your manim_tutorial_1.py file and type the following into the command line to run this scene: python extract_scene.py manim_tutorial_1.py MoreShapes -pl.

class MoreShapes(Scene):
    #A few more simple shapes
    def construct(self):
        circle = Circle(color=PURPLE_A)
        square = Square(fill_color=GOLD_B, fill_opacity=1, color=GOLD_A)
        square.move_to(UP+LEFT)
        circle.surround(square)
        rectangle = Rectangle(height=2, width=3)
        ellipse=Ellipse(width=3, height=1, color=RED)
        ellipse.shift(2*DOWN+2*RIGHT)
        pointer = CurvedArrow(2*RIGHT,5*RIGHT,color=MAROON_C)
        arrow = Arrow(LEFT,UP)
        arrow.next_to(circle,DOWN+LEFT)
        rectangle.next_to(arrow,DOWN+LEFT)
        ring=Annulus(inner_radius=.5, outer_radius=1, color=BLUE)
        ring.next_to(ellipse, RIGHT)

        self.add(pointer)
        self.play(FadeIn(square))
        self.play(Rotating(square),FadeIn(circle))
        self.play(GrowArrow(arrow))
        self.play(GrowFromCenter(rectangle), GrowFromCenter(ellipse), GrowFromCenter(ring))

You’ll notice we have a few new shapes and we are using a couple of new commands. Previously we saw the Circle(), Square(), Line(), and Polygon() classes. Now we’ve added Rectangle(), Ellipse(), Annulus(), Arrow(), and CurvedArrow(). All shapes, with the exception of lines and arrows, are created at the origin (center of the screen, which is (0,0,0)). For the lines and arrows you need to specify the location of the two ends.

For starters, we’ve specified a color for the square using the keyword argument color=. Most of the shapes are subclasses of VMobject, which stands for a vectorized math object. VMobject is itself a subclass of the math object class Mobject. The best way to determine the keyword arguments you can pass to the classes are to take a look at the allowed arguments for the VMobject and Mobject class. Some possible keywords include radius, height, width, color, fill_color, and fill_opacity. For the Annulus() class we have inner_radius and outer_radius for keyword arguments.

A list of the named colors can be found in the COLOR_MAP dictionary located in the constant.py file. The named colors are keys to the COLOR_MAP dictionary which yield the hex color code. You can create your own colors using a hex color code picker (Google it and adding entries to COLOR_MAP.

3.1 Direction Vectors

The constants.py file contains other useful defintions, such as direction vectors that can be used to place objects in the scene. For example, UP is a numpy array (0,1,0), which corresponds to 1 unit of distance. To honor the naming convention used in manim I’ve decided to call the units of distance the MUnit or math unit (this is my own term, not a manim term). Thus the default screen height is 8 MUnits (as defined in constants.py). The default screen width is 14.2 MUnits.

If we are thinking in terms of x-, y-, and z-coordinates, UP is a vector pointing along the positive y-axis. RIGHT is the array (1,0,0) or a vector pointing along the positive x-axis. The other direction vectors are LEFT, DOWN, IN, and OUT. Each vector has a length of 1 MUnit. After creating an instance of an object you can use the .move_to() method to move the object to a specific location on the screen. Notice that the direction vectors can be added together (such as UP+LEFT) or multiplied by a scalar to scale it up (like 2*RIGHT). In other words, the direction vectors act like you would expect mathematical vectors to behave. If you want to specify your own vectors, they will need to be numpy arrays with three components. The center edge of each screen side is also defined by vectors TOP, BOTTOM, LEFT_SIDE, and RIGHT_SIDE.

The overall scale of the vectors (the relationship between pixels and MUnits) is set by the FRAME_HEIGHT variable defined in constants.py. The default value for this is 8. This means you would have to move an object 8*UP to go from the bottom of the screen to the top of the screen. At this time I don’t see a way to change it other than by changing it in constants.py.

Mobjects can also be located relative to another object using the next_to() method. The command arrow.next_to(circle,DOWN+LEFT) places the arrow one MUnit down and one to the left of the circle. The rectangle is then located one MUnit down and one left of the arrow.

The Circle() class has a surround() method that allows you to create a circle that completely encloses another mobject. The size of the circle will be determined by the largest dimension of the mobject surrounded.

3.2 Making Simple Animations

As previously mentioned, the .add() method places a mobject on screen at the start of the scene. The .play() method can be used animate things in your scene.

The names of the animations, such as FadeIn or GrowFromCenter, are pretty self-explanatory. What you should notice is that animations play sequentially in the order listed and that if you want multiple animations to occur simultaneously, you should include all those animations in the argument of a single .play() command separated by commas. I’ll show you how to use lists of animations to play multiple animations at the same time in a later entry in this series.

Things to try:
– Use the Polygon() class to create other shapes
– Try placing multiple objects on the screen at various locations
– Take a look at the different types of transformations available in /animation/transforms.py

Next time we will take a look at writing text on the screen.

Posted in Just for Fun, Programming | Tagged , , , | 2 Comments

Creating Your First Scene – manim Series: Part 2

This is part of a series of posts on my journey learning how to use manim, a mathematical animation toolbox created for the 3blue1brown video series. Check out the previous entry to install the required packages to get started.

To give you an idea how I’m approaching learning manim, I started off by going through the example scenes in example_scenes.py in the top-level manim folder. I also found another Github repository by Adirockzz95, who had worked out several more example files. Once I had a good feel for those examples, I started watching the 3b1b videos and when I came to an animation I wanted to learn I’d go to the original code (located in the old_projects folder of the manim code) and try to figure out how it worked. Note that, due to changes in manim, much of the older code will throw an error. However, trying to fix the code enough to run will give you a better idea of how things work.

2.0 Creating Your First Scene

Copy and paste the code below into a new text file and save it as manim_tutorial_1.py in the top-level manim directory. The .py extension tells your operating system that this is a Python file.

Open up a  command line window and go to the top-level manim directory, and type python extract_scene.py manim_tutorial_1.py Shapes -pl

We are calling the Python interpreter with the python command. The first argument passed to Python, extract_scence.py is the part of the manim code that runs your script and creates a video file. This argument will always need to be called to create videos. The second argument, manim_tutorial_1.py is the name of the file (i.e. the module) where your script is stored. The third argument, Shapes is the name of the class (i.e. the scene name) defined within your file that gives instructions on how to construct a scene. The last arguments, -pl tell the extract_scene script to preview the animation by playing it once it is done and to render the animation in low quality, which speeds up the time to create the animation. See the README.md for directions on what other arguments you can pass to extract_scene.

from big_ol_pile_of_manim_imports import *

class Shapes(Scene):
    #A few simple shapes
    def construct(self):
        circle = Circle()
        square = Square()
        line=Line(np.array([3,0,0]),np.array([5,0,0]))
        triangle=Polygon(np.array([0,0,0]),np.array([1,1,0]),np.array([1,-1,0]))

        self.add(line)
        self.play(ShowCreation(circle))
        self.play(FadeOut(circle))
        self.play(GrowFromCenter(square))
        self.play(Transform(square,triangle))

If everything works you should see the following messages (or something similar) in your terminal:

The video should look like this:

All of the various manim modules are contained in big_ol_pile_of_manim_imports.py so importing this gives you all of the basic features of manim. This doesn’t include every single module from manim but it contains the core modules. It is worth your time to dive into some of the modules to see how things are put together. I’ve learned a surprising amount of Python by trying to figure out how things work. Incidentally I find using the search box at https://github.com/3b1b/manim very helpful for finding different classes and figuring out what arguments they take and how they work.

2.1 Scenes and Animation

The Scene is the script that tells manim how to place and animate your objects on the screen. I read that each 3blue1brown video is created as individual scenes which are stiched together using video editing software. You must define each scene as a separate class that is a subclass of Scene. This class must have a construct() method, along with any other code required for creating objects, adding them to the screen, and animating them. The construct() method is essentially the main method in the class that gets called when run through extract_scene.py. It is similar to __init__; it is the method that is automatically called when you create an instance of the class. Within this method you should define all of your objects, any code needed to control the objects, and code to place the objects onscreen and animate them.

For this first scene we’ve created a circle, a square, a line, and a triangle. Note that the coordinates are specified using numpy arrays np.array(). You can pass a 3-tuple like (3,0,0), which works sometimes, but some of the transformation methods expect the coordinates to be a numpy array.

One of the more important methods from the Scene() class is the play() method. play() is what processes the various animations you ask manim to perform. My favorite animation is Transform, which does a spectacular job of morphing one mobject into another. This scene shows a square changing into a triangle, but you can use the transform to morph any two objects together. To have objects appear on the screen without any animation you can use add() to place them. The line has been added and shows up in the very first frame, while the other objects are fade in or grow. The naming of the transformations is pretty straight forward so it’s usually obvious what each one does.

Things to try
– Change the order of the add() and play() commands.
– Try using the Transform() method on other shapes.
– Check out the shapes defined in geometry.py which is located in the /manim/mobject/ folder.

Next time: In the next entry in this series I’ll look at other shapes and how to change their properties.

Posted in Just for Fun, Programming | Tagged , , , | 7 Comments

Installing manim and Python – manim Series: Part 1

This post is part of a series on what I learned as I taught myself how to use manim, the mathematical animation software behind the beautiful videos at 3blue1brown. Check them out if you haven’t seen any of them yet.

1.0 Installing manim and Python

To get started you will need to have Python 2.7 installed and a copy of the manim repository cloned to your computer. I recommend using Anaconda to install Python and use the virtual environment commands within Anaconda to manage the packages you need to install. I should note that I’m working in macOS so things might be a bit different in Windows or Linux.

  • Install Python 2.7 from https://www.anaconda.com/download/
  • Open a terminal and navigate to the folder you want to clone the manim files to.
  • In the terminal type git clone https://github.com/3b1b/manim.git
  • Create a virtual environment to house all the Python packages by typing conda create -n manim27 python=2.7
  • This will create an environment named manim27 (feel free to choose another name) and it will install a clean version of Python 2.7 in the environment.
  • To activate your environment type source activate manim27 on macOS and Linux systems or activate manim27 on Windows systems. If you gave your environment a different name you can replace manim27 with the name you gave to your environment.
  • In the terminal, navigate to the top-level folder of manim. You can identify this folder because it should have a file named requirements.txt.
  • To install the packages required for manim, type pip install -r requirements.txt. These packages will be installed in your virtual environment and won’t affect any other installations of Python on your system.
  • You will need to tell manim where to save your video files. Open constants.py, which is in the top-level manim directory and change the directory listed under MEDIA_DIR to be the place you want videos saved to. You will want to change Dropbox (3Blue1Brown)/3Blue1Brown Team Folder shown below to be your desired output directory:
# Things anyone wishing to use this repository for their
# own use will want to change
MEDIA_DIR = os.path.join(
os.path.expanduser('~'),
"Dropbox (3Blue1Brown)/3Blue1Brown Team Folder"
)
  • Type python extract_scene.py example_scenes.py SquareToCircle -pl. This should result in a video that shows a square turning into a circle. If this doesn’t work for you I can’t provide any tech support; I recommend you go to https://github.com/3b1b/manim/issues?q=is%3Aissue+is%3Aclosed to see the issues others have had getting manim to run.
  • The output video file will show up in a subdirectory named /animations/example_scenes/480p15/ in the directory you specified for outputs in constants.py.

There is also a Docker image available (see https://github.com/3b1b/manim at the bottom of the page) but I ran into issues getting it working on my machine.

In my next entry in this series we’ll start off creating our own animated scene.


Note: The May 9, 2018 commit of manim can be found here

Posted in Just for Fun, Programming | Tagged , , , | 6 Comments

Learning How To Animate Videos Using manim Series – A Journey

Grant Sanderson of 3Blue1Brown has an amazing series of videos on a variety of topics in mathematics. I especially like how he helps you develop a deeper intuitive feel of some mathematical concepts in linear algebra, calculus, and several other topics. What is also pretty awe-inspiring is that he has developed the animation tools, called manim,  for his videos in Python, which has inspired me to try and animate some videos of my own. Unfortunately there are not many resources for learning how to use manim (which I think stands for mathematical animation) so I decided to set out and teach myself how to use it. The code for manim is freely available on Github.  I’ve noticed a number of people expressing interest in learning how to use manim so I thought I’d share my journey through a series of posts.

The following assumes you have a good understanding of Python and of object oriented programming. Also note that this is based on the May 9, 2018 commit of manim – future versions may break things

Before getting things up and running, I want to point out that this is in no way a definitive manual of the workings of manim. It is merely a narration of my own journey learning how to use manim. My understanding may be faulty and my execution may not be optimal. With those caveats in mind, let’s get started learning how to create our own beautiful mathematical animations.

Tutorial posts in the manim Series:


Tutorial files can be found at https://github.com/zimmermant/manim_tutorial

Posted in Just for Fun, Programming | Tagged , , , | 11 Comments