## Creating Text – manim Series: Part 4

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

Important Note:  These posts are based on an earlier version of manim which uses Python 2.7.  The latest version of manim is using Python 3.  To follow along with these posts, use Python 2.7 and the May 9, 2018 commit of manim .

# 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):
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.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.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)))


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)



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

This entry was posted in Just for Fun, Programming and tagged , , , . Bookmark the permalink.

### 12 Responses to Creating Text – manim Series: Part 4

1. nosedog says:

Here’s some feedback: thanks so much for this series. I hope to use manim for education one day, but even if I don’t, it’s fascinating to read about the moving parts within it. You’ve done a great job.

2. Mr. J says:

How do you change the font btw?
Thanks

• This is something I want to figure out at some point but haven’t had time. I know you could change the font in tex_template.tex, but that would change the font on all text. I’m guessing you might use something like \fontfamily to change font for a single block of text but I haven’t tried it yet.

3. Netal says:

Thanks for the tutorial, it’s been tremendously helpful so far.
A comment: the second to last line in “AddingMoreText” doesn’t seem to do anything. Naturally, scaling by 1 does nothing, as you explained (though it is a bit confusing to have it in the code). The part I don’t understand is why match_color does not work.

• match_color works ok for me. What object are you trying to match colors with?

4. ZipWin Metric says:

Thanks for your nice tutorial. But when I extracted AddingText, the command window showed that a .svg file couldn’t be found. I am using texlive2018 in my win10 PC. I can’t find out where the problem is.

Traceback (most recent call last):
File “extract_scene.py”, line 289, in main
handle_scene(SceneClass(**scene_kwargs), **config)
File “E:\manim\scene\scene.py”, line 71, in __init__
self.construct(*self.construct_args)
File “E:\manim\manim_tutorial_1.py”, line 55, in construct
second_line=TextMobject(“and easy to do!”)
File “E:\manim\mobject\svg\tex_mobject.py”, line 145, in __init__
self, self.arg_separator.join(tex_strings), **kwargs
File “E:\manim\mobject\svg\tex_mobject.py”, line 48, in __init__
SVGMobject.__init__(self, file_name=file_name, **kwargs)
File “E:\manim\mobject\svg\svg_mobject.py”, line 46, in __init__
self.ensure_valid_file()
File “E:\manim\mobject\svg\svg_mobject.py”, line 63, in ensure_valid_file
self.file_name)
OSError: No file matching E:\manim\files\Tex\f83d794bd5780e56.svg in image directory

• Unfortunately I’m a Mac user so I can’t be much help. It sounds like Latex isn’t generating the correct output to display text. I’d recommend asking for help at https://github.com/3b1b/manim/issues.

• ZipWin Metric says:

Thanks for your advice. I have made the extraction process continue by converting f83d794bd5780e56.dvi to f83d794bd5780e56.svg file manually.

• Ryan M Sullivan says:

I’m on linux and had a similar issue. The log file said I was missing physics.sys and after installing the tex physics package everything worked no problem.

5. ZipWin Metric says:

Here is a comment on AddingMoreText:

Actually I find if you put ApplyMethod(author.match_color,quote2) and Transform(author,author.scale(1)) as arguments of the same play, the match_color doesn’t work. But if you split them like

self.play(ApplyMethod(author.match_color, quote2))
self.play(Transform(author, author.scale(1)))


the match_color does work.

And there is another advice. I find you can animate a scale-up or scale-down by ApplyMethod. You can use self.play(ApplyMethod(author.scale, 1.5)), which animate a scale-up and this really works for me. I think the scale is an enlargement factor instead of the size of the Mobject. Maybe this is the reason why ApplyMethod(author.scale, 1) doesn’t seem to work.

I am not sure whether I have expressed myself clearly, because English is not mother tongue.

This site uses Akismet to reduce spam. Learn how your comment data is processed.