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))
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 colors and rectangles
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=RED)
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

Advertisements
Posted in Just for Fun, Programming | Tagged , , , | Leave a comment

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.

# My first scene
from big_ol_pile_of_manim_imports import *

class Shapes(Scene):
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 , , , | 2 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 , , , | Leave a comment

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.

 

Part 1: Installing manim and Python

Part 2: Creating Your First Scene

Part 3: More Shapes

 

 


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

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

Programming Games with Python

I’ll be giving a talk at the Science Olympiad Nationals being held here at UW-Stout on gaming physics engines. I thought I’d put up a few resources related to my talk and add some resources on how to get started programming games using Python.

Why Python? Python is an easy language to learn, it is easy to code, and it is very easy to read (which is a huge plus for me as an instructor). Not many commercial games are written in Python but some do use elements of Python as part of their scripting engine. Python is a good place to start learning how to program before moving on to more challenging languages. As a scientist I use Python as my primary programming language because many of the tools I need on a day-to-day basis are available in Python.

Both Udacity and Coursera have free courses available that will help you learn Python. Keep in mind that in addition to a paid version of the courses you can usually take the courses for free.

To learn how to program games in Python I recommend Invent Your Own Computer Games with Python and Making Games with Python and Pygame. Both are available for free or you can pay to get a physical copy of the books. These two books work well together and I recommend my students take a look at both when getting started. I also recommend looking at the website Programming Arcade Games with Python and Pygame as another great place to get tips and tricks for starting out.

More general books for learning how to program Python are available at Learning Python the Hard Way and How to Think Like a Computer Scientist: Learn with Python. Both are great resources for beginners.

Good Luck

Programs from my Science Olympiad talk:

    Here are links to the programs I demonstrated during my talk at Science Olympiad Nationals. This folder on the www.glowscript.ord contains all of my publicly available VPython files, which you are free to copy and use for your own purposes.

Posted in Just for Fun, Programming, Teaching Physics | Tagged | Leave a comment

List of SBG Resources

There are quite a few other bloggers that I relied on to get started with learning objectives based grading. Here is a good collection of the links I’ve found invaluable in getting started.

Blogs on SBG

Shawn Cornally at ThinkThankThunk
Frank Noschese at Action-Reaction
Kelly O’Shea at Physics! Blog!
Always Formative
Pretty Good Physics Standards Based Grading
Dan Myers at dy/dan
Ian Beatty at Beatty Web
Geoff Schmidt at Pedagogue Padawan


SBG Galas

One of the richest resources I’ve found have been the SBG Galas (which no longer seem to occur). Here are links to some of the earlier galas

SBG Gala #1 at https://fnoschese.wordpress.com/2010/07/20/sbg-gala-1/
SBG Gala #2 at http://alwaysformative.blogspot.com/2010/09/standards-based-grading-gala-2.html
SBG Gala #3 at http://blog.msbethea.com/?p=462
SBG Gala #4 at https://fnoschese.wordpress.com/2010/12/23/sbg-gala-4/
SBG Gala #5 at https://quantumprogress.wordpress.com/2011/02/18/sbg-gala-5-2/
SBG Gala #6 at http://oldmathdognewtricks.blogspot.com/2011/06/sbg-gala-6.html

Posted in Teaching Physics | Tagged , , | Leave a comment