mirror of
https://github.com/3b1b/manim.git
synced 2026-01-13 00:18:05 -05:00
Compare commits
45 Commits
0.1.11
...
cairo-back
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f934bdc61e | ||
|
|
ba405521ce | ||
|
|
0dc8e4389d | ||
|
|
34ec0f4795 | ||
|
|
faa52d7dd4 | ||
|
|
d797e5f1fe | ||
|
|
99952067c1 | ||
|
|
30ae89464e | ||
|
|
1ecbbbbcd5 | ||
|
|
186b86cb70 | ||
|
|
4c42083ffc | ||
|
|
dec753fc26 | ||
|
|
08c90c272b | ||
|
|
be8b28dd9d | ||
|
|
d0dc7ed301 | ||
|
|
abc24f2d52 | ||
|
|
53756ea140 | ||
|
|
dcb608f258 | ||
|
|
05acf31e47 | ||
|
|
bc5c3968d9 | ||
|
|
11c451c2e9 | ||
|
|
52c5e32ba5 | ||
|
|
37efc93e9c | ||
|
|
d63f61b903 | ||
|
|
49d53d9a8f | ||
|
|
79bf87754a | ||
|
|
e336cf5ddc | ||
|
|
e9638aee2e | ||
|
|
a42d9c6ecb | ||
|
|
9f945d9940 | ||
|
|
7556b99dc0 | ||
|
|
9174ec335c | ||
|
|
ea929d167f | ||
|
|
82d6ad0ef5 | ||
|
|
3c1a6bb8b1 | ||
|
|
00ff47855e | ||
|
|
45c5ec7091 | ||
|
|
4d78e0c63e | ||
|
|
c82b1fc2c9 | ||
|
|
f3f9d0dfb7 | ||
|
|
2f26a32f96 | ||
|
|
6a571262fd | ||
|
|
93ebd66853 | ||
|
|
99519090fb | ||
|
|
b5a75c3250 |
@@ -1,5 +1,5 @@
|
||||
language: python
|
||||
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
|
||||
dist: bionic
|
||||
python: "3.7"
|
||||
cache: pip
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -8,14 +8,17 @@
|
||||
|
||||
Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as seen in the videos at [3Blue1Brown](https://www.3blue1brown.com/).
|
||||
|
||||
This repository contains the version of manim used by 3Blue1Brown. There is also a community maintained version at https://github.com/ManimCommunity/manim/.
|
||||
To get help or to join the development effort, please join the [discord](https://discord.gg/mMRrZQW).
|
||||
|
||||
## Installation
|
||||
Manim runs on Python 3.7. You can install it from PyPI via pip:
|
||||
Manim runs on Python 3.6 or higher version. You can install it from PyPI via pip:
|
||||
|
||||
```sh
|
||||
pip3 install manimlib
|
||||
```
|
||||
|
||||
System requirements are [cairo](https://www.cairographics.org), [ffmpeg](https://www.ffmpeg.org), [sox](http://sox.sourceforge.net), [latex](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
System requirements are [cairo](https://www.cairographics.org), [ffmpeg](https://www.ffmpeg.org), [sox](http://sox.sourceforge.net) (optional, if you want to play the prompt tone after running), [latex](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
|
||||
You can now use it via the `manim` command. For example:
|
||||
|
||||
@@ -39,7 +42,7 @@ python3 ./manim.py example_scenes.py SquareToCircle -pl
|
||||
|
||||
### Directly (Windows)
|
||||
1. [Install FFmpeg](https://www.wikihow.com/Install-FFmpeg-on-Windows).
|
||||
2. [Install Cairo](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo). For most users, ``pycairo‑1.18.0‑cp37‑cp37m‑win32.whl`` will do fine.
|
||||
2. [Install Cairo](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo). For most users, ``pycairo‑1.18.0‑cp37‑cp37m‑win32.whl`` will do fine (you can download it or other versions from [here](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo)).
|
||||
```sh
|
||||
pip3 install C:\path\to\wheel\pycairo‑1.18.0‑cp37‑cp37m‑win32.whl
|
||||
```
|
||||
@@ -47,7 +50,7 @@ python3 ./manim.py example_scenes.py SquareToCircle -pl
|
||||
|
||||
4. [Install SoX](https://sourceforge.net/projects/sox/files/sox/).
|
||||
|
||||
5. Install the remaining Python packages. Make sure that ``pycairo==1.17.1`` is changed to ``pycairo==1.18.0`` in requirements.txt.
|
||||
5. Install the remaining Python packages.
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
@@ -119,13 +122,15 @@ Look through the `old_projects` folder to see the code for previous 3b1b videos.
|
||||
While developing a scene, the `-sp` flags are helpful to just see what things look like at the end without having to generate the full animation. It can also be helpful to use the `-n` flag to skip over some number of animations.
|
||||
|
||||
### Documentation
|
||||
Documentation is in progress at [eulertour.com/docs](https://www.eulertour.com/docs/).
|
||||
Documentation is in progress at [eulertour.com/docs](https://www.eulertour.com/docs/). And there is also an all-in-one documentation and tutorials maintained by **@manim-kindergarten**: [manim.ml](https://manim.ml/) (in Chinese).
|
||||
|
||||
### Walkthrough
|
||||
Todd Zimmerman put together a [tutorial](https://talkingphysics.wordpress.com/2019/01/08/getting-started-animating-with-manim-and-python-3-7/) on getting started with manim, which has been updated to run on Python 3.7.
|
||||
|
||||
[manim-kindergarten](https://github.com/manim-kindergarten/) wrote and collected some useful extra classes and some codes of videos in [manim_sandbox repo](https://github.com/manim-kindergarten/manim_sandbox).
|
||||
|
||||
## Contributing
|
||||
Is always welcome. In particular, there is a dire need for tests and documentation.
|
||||
Only accepts pull requests that fixes bugs / fixes typos / improves existing content (for more information, see [#1243](https://github.com/3b1b/manim/issues/1243)). Most pull requests should be directed to the [community version](https://github.com/ManimCommunity/manim/).
|
||||
|
||||
## License
|
||||
All files in the directory `from_3b1b`, which by and large generate the visuals for 3b1b videos, are copyright 3Blue1Brown.
|
||||
|
||||
@@ -15,5 +15,6 @@ dependencies:
|
||||
- pycairo==1.18.0
|
||||
- pydub==0.23.0
|
||||
- ffmpeg
|
||||
- pygments==2.6.1
|
||||
- pip:
|
||||
- pyreadline
|
||||
- pyreadline
|
||||
|
||||
@@ -5,7 +5,7 @@ from manimlib.imports import *
|
||||
# To watch one of these scenes, run the following:
|
||||
# python -m manim example_scenes.py SquareToCircle -pl
|
||||
#
|
||||
# Use the flat -l for a faster rendering at a lower
|
||||
# Use the flag -l for a faster rendering at a lower
|
||||
# quality.
|
||||
# Use -s to skip to the end and just save the final frame
|
||||
# Use the -p to have the animation (or image, if -s was
|
||||
@@ -98,7 +98,7 @@ class WarpSquare(Scene):
|
||||
class WriteStuff(Scene):
|
||||
def construct(self):
|
||||
example_text = TextMobject(
|
||||
"This is a some text",
|
||||
"This is some text",
|
||||
tex_to_color_map={"text": YELLOW}
|
||||
)
|
||||
example_tex = TexMobject(
|
||||
|
||||
@@ -152,7 +152,7 @@ class ApplyMethod(Transform):
|
||||
method is a method of Mobject, *args are arguments for
|
||||
that method. Key word arguments should be passed in
|
||||
as the last arg, as a dict, since **kwargs is for
|
||||
configuration of the transform itslef
|
||||
configuration of the transform itself
|
||||
|
||||
Relies on the fact that mobject methods return the mobject
|
||||
"""
|
||||
|
||||
@@ -26,7 +26,7 @@ def initialize_directories(config):
|
||||
"Dropbox (3Blue1Brown)/3Blue1Brown Team Folder"
|
||||
)
|
||||
if not os.path.isdir(MEDIA_DIR):
|
||||
MEDIA_DIR = "./media"
|
||||
MEDIA_DIR = os.path.join(os.getcwd(), "media")
|
||||
print(
|
||||
f"Media will be written to {MEDIA_DIR + os.sep}. You can change "
|
||||
"this behavior with the --media_dir flag."
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
\documentclass[preview]{standalone}
|
||||
\usepackage[UTF8]{ctex}
|
||||
|
||||
\usepackage[english]{babel}
|
||||
\usepackage{amsmath}
|
||||
@@ -16,7 +17,6 @@
|
||||
\usepackage{xcolor}
|
||||
\usepackage{microtype}
|
||||
%\DisableLigatures{encoding = *, family = * }
|
||||
\usepackage[UTF8]{ctex}
|
||||
\linespread{1}
|
||||
|
||||
\begin{document}
|
||||
|
||||
@@ -74,7 +74,7 @@ class OpeningQuote(Scene):
|
||||
if self.quote_arg_separator == " ":
|
||||
quote[0].shift(0.2 * RIGHT)
|
||||
quote[-1].shift(0.2 * LEFT)
|
||||
for term, color in self.highlighted_quote_terms:
|
||||
for term, color in self.highlighted_quote_terms.items():
|
||||
quote.set_color_by_tex(term, color)
|
||||
quote.to_edge(UP, buff=self.top_buff)
|
||||
if quote.get_width() > max_width:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
I won't pretend like this is best practice, by in creating animations for a video,
|
||||
I won't pretend like this is best practice, but in creating animations for a video,
|
||||
it can be very nice to simply have all of the Mobjects, Animations, Scenes, etc.
|
||||
of manim available without having to worry about what namespace they come from.
|
||||
|
||||
|
||||
@@ -186,19 +186,19 @@ class Axes(VGroup, CoordinateSystem):
|
||||
def get_axes(self):
|
||||
return self.axes
|
||||
|
||||
def get_coordinate_labels(self, x_vals=None, y_vals=None):
|
||||
def get_coordinate_labels(self, x_vals=None, y_vals=None, **kwargs):
|
||||
if x_vals is None:
|
||||
x_vals = []
|
||||
if y_vals is None:
|
||||
y_vals = []
|
||||
x_mobs = self.get_x_axis().get_number_mobjects(*x_vals)
|
||||
y_mobs = self.get_y_axis().get_number_mobjects(*y_vals)
|
||||
x_mobs = self.get_x_axis().get_number_mobjects(*x_vals, **kwargs)
|
||||
y_mobs = self.get_y_axis().get_number_mobjects(*y_vals, **kwargs)
|
||||
|
||||
self.coordinate_labels = VGroup(x_mobs, y_mobs)
|
||||
return self.coordinate_labels
|
||||
|
||||
def add_coordinates(self, x_vals=None, y_vals=None):
|
||||
self.add(self.get_coordinate_labels(x_vals, y_vals))
|
||||
def add_coordinates(self, x_vals=None, y_vals=None, **kwargs):
|
||||
self.add(self.get_coordinate_labels(x_vals, y_vals, **kwargs))
|
||||
return self
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ class NumberPlane(Axes):
|
||||
for inputs in ranges:
|
||||
for k, x in enumerate(inputs):
|
||||
new_line = line.copy()
|
||||
new_line.move_to(axis2.number_to_point(x))
|
||||
new_line.shift(axis2.number_to_point(x))
|
||||
if k % (1 + ratio) == 0:
|
||||
lines1.add(new_line)
|
||||
else:
|
||||
|
||||
@@ -272,7 +272,7 @@ class Mobject(Container):
|
||||
return self
|
||||
|
||||
def apply_function(self, function, **kwargs):
|
||||
# Default to applying matrix about the origin, not mobjects center
|
||||
# Default to applying function about the origin, not mobjects center
|
||||
if len(kwargs) == 0:
|
||||
kwargs["about_point"] = ORIGIN
|
||||
self.apply_points_function_about_point(
|
||||
@@ -477,7 +477,7 @@ class Mobject(Container):
|
||||
return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
|
||||
|
||||
def stretch_to_fit_depth(self, depth, **kwargs):
|
||||
return self.rescale_to_fit(depth, 1, stretch=True, **kwargs)
|
||||
return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
|
||||
|
||||
def set_width(self, width, stretch=False, **kwargs):
|
||||
return self.rescale_to_fit(width, 0, stretch=stretch, **kwargs)
|
||||
@@ -701,7 +701,6 @@ class Mobject(Container):
|
||||
result, submob.get_merged_array(array_attr),
|
||||
axis=0
|
||||
)
|
||||
submob.get_merged_array(array_attr)
|
||||
return result
|
||||
|
||||
def get_all_points(self):
|
||||
|
||||
@@ -131,7 +131,7 @@ class NumberLine(Line):
|
||||
return self.point_to_number(point)
|
||||
|
||||
def get_unit_size(self):
|
||||
return (self.x_max - self.x_min) / self.get_length()
|
||||
return self.get_length() / (self.x_max - self.x_min)
|
||||
|
||||
def default_numbers_to_display(self):
|
||||
if self.numbers_to_show is not None:
|
||||
|
||||
@@ -9,7 +9,7 @@ from manimlib.mobject.svg.tex_mobject import TextMobject
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.space_ops import get_norm
|
||||
|
||||
import copy
|
||||
|
||||
class Brace(TexMobject):
|
||||
CONFIG = {
|
||||
|
||||
@@ -257,6 +257,7 @@ class BulletedList(TextMobject):
|
||||
CONFIG = {
|
||||
"buff": MED_LARGE_BUFF,
|
||||
"dot_scale_factor": 2,
|
||||
"dot_color": WHITE,
|
||||
# Have to include because of handle_multiple_args implementation
|
||||
"template_tex_file_body": TEMPLATE_TEXT_FILE_BODY,
|
||||
"alignment": "",
|
||||
@@ -266,7 +267,7 @@ class BulletedList(TextMobject):
|
||||
line_separated_items = [s + "\\\\" for s in items]
|
||||
TextMobject.__init__(self, *line_separated_items, **kwargs)
|
||||
for part in self:
|
||||
dot = TexMobject("\\cdot").scale(self.dot_scale_factor)
|
||||
dot = TexMobject("\\cdot", color=self.dot_color).scale(self.dot_scale_factor)
|
||||
dot.next_to(part[0], LEFT, SMALL_BUFF)
|
||||
part.add_to_back(dot)
|
||||
self.arrange(
|
||||
|
||||
@@ -90,7 +90,7 @@ class Scene(Container):
|
||||
def tear_down(self):
|
||||
"""
|
||||
This is meant to be implemented by any scenes which
|
||||
are comonly subclassed, and have some common method
|
||||
are commonly subclassed, and have some common method
|
||||
to be invoked before the scene ends.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -333,7 +333,7 @@ class SceneFileWriter(object):
|
||||
Pixel array of the frame.
|
||||
"""
|
||||
if self.write_to_movie:
|
||||
self.writing_process.stdin.write(frame.tostring())
|
||||
self.writing_process.stdin.write(frame.tobytes())
|
||||
|
||||
def save_final_image(self, image):
|
||||
"""
|
||||
@@ -427,7 +427,7 @@ class SceneFileWriter(object):
|
||||
def close_movie_pipe(self):
|
||||
"""
|
||||
Used internally by Manim to gracefully stop writing to FFMPEG's
|
||||
input buffer, and move the temporary files into their permananant
|
||||
input buffer, and move the temporary files into their permanent
|
||||
locations
|
||||
"""
|
||||
self.writing_process.stdin.close()
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
"""
|
||||
A set of scenes to be used for performance testing of Manim.
|
||||
"""
|
||||
|
||||
|
||||
class Perf1(GraphScene):
|
||||
"""
|
||||
A simple scene of two animations from the end of a video on recursion.
|
||||
|
||||
- Uses a graph in 1/4 of the scene.
|
||||
- First fades in multiple lines of text and equations, and the graph axes.
|
||||
- Next animates creation of two graphs and the creation of their text
|
||||
labels.
|
||||
"""
|
||||
CONFIG = {
|
||||
"x_axis_label":
|
||||
"$n$",
|
||||
"y_axis_label":
|
||||
"$time$",
|
||||
"x_axis_width":
|
||||
FRAME_HEIGHT,
|
||||
"y_axis_height":
|
||||
FRAME_HEIGHT / 2,
|
||||
"y_max":
|
||||
50,
|
||||
"y_min":
|
||||
0,
|
||||
"x_max":
|
||||
100,
|
||||
"x_min":
|
||||
0,
|
||||
"x_labeled_nums": [50, 100],
|
||||
"y_labeled_nums":
|
||||
range(0, 51, 10),
|
||||
"y_tick_frequency":
|
||||
10,
|
||||
"x_tick_frequency":
|
||||
10,
|
||||
"axes_color":
|
||||
BLUE,
|
||||
"graph_origin":
|
||||
np.array(
|
||||
(-FRAME_X_RADIUS + LARGE_BUFF, -FRAME_Y_RADIUS + LARGE_BUFF, 0))
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
t1 = TextMobject(
|
||||
"Dividing a problem in half over and over means\\\\"
|
||||
"the work done is proportional to $\\log_2{n}$").to_edge(UP)
|
||||
|
||||
t2 = TextMobject(
|
||||
'\\textit{This is one of our\\\\favorite things to do in CS!}')
|
||||
t2.to_edge(RIGHT)
|
||||
|
||||
t3 = TextMobject(
|
||||
'The new \\texttt{power(x,n)} is \\underline{much}\\\\better than the old!'
|
||||
)
|
||||
t3.scale(0.8)
|
||||
p1f = TexMobject('x^n=x \\times x^{n-1}').set_color(ORANGE)
|
||||
t4 = TextMobject('\\textit{vs.}').scale(0.8)
|
||||
p2f = TexMobject(
|
||||
'x^n=x^{\\frac{n}{2}} \\times x^{\\frac{n}{2}}').set_color(GREEN)
|
||||
p1v2g = VGroup(t3, p1f, t4, p2f).arrange(DOWN).center().to_edge(RIGHT)
|
||||
|
||||
self.setup_axes()
|
||||
o_n = self.get_graph(lambda x: x, color=ORANGE, x_min=1, x_max=50)
|
||||
o_log2n = self.get_graph(lambda x: math.log2(x),
|
||||
color=GREEN,
|
||||
x_min=2,
|
||||
x_max=90)
|
||||
onl = TexMobject('O(n)')
|
||||
olog2nl = TexMobject('O(\\log_2{n})')
|
||||
onl.next_to(o_n.get_point_from_function(0.6), UL)
|
||||
olog2nl.next_to(o_log2n.get_point_from_function(0.8), UP)
|
||||
self.play(
|
||||
FadeIn(t1),
|
||||
FadeIn(self.axes),
|
||||
# FadeInFromDown(t2),
|
||||
FadeIn(p1v2g),
|
||||
)
|
||||
self.play(ShowCreation(o_n),
|
||||
ShowCreation(o_log2n),
|
||||
ShowCreation(onl),
|
||||
ShowCreation(olog2nl),
|
||||
run_time=3)
|
||||
self.wait(duration=5)
|
||||
Reference in New Issue
Block a user