mirror of
https://github.com/3b1b/manim.git
synced 2026-01-12 16:08:16 -05:00
Compare commits
188 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aff2d21bad | ||
|
|
ca0b7a6b06 | ||
|
|
d31be357e5 | ||
|
|
a529a59abf | ||
|
|
cf656e9c21 | ||
|
|
7f1a15b6ba | ||
|
|
dbdd799696 | ||
|
|
522a5b3c5f | ||
|
|
3362f93964 | ||
|
|
af65c9d5d4 | ||
|
|
f0cdcd90ba | ||
|
|
19e3c97589 | ||
|
|
811ee4d26b | ||
|
|
c847988e10 | ||
|
|
1bb2e8c237 | ||
|
|
77ab3b8d3a | ||
|
|
87d8671995 | ||
|
|
f0796055cc | ||
|
|
48f2a1ec3c | ||
|
|
422e86e0da | ||
|
|
c896f58bbd | ||
|
|
97a0a707d7 | ||
|
|
30728879be | ||
|
|
77acc999cd | ||
|
|
1279f040da | ||
|
|
0f71b0a408 | ||
|
|
ada09f1928 | ||
|
|
839fb4ff58 | ||
|
|
24d077fbce | ||
|
|
16f8c025cd | ||
|
|
6fe082a5d8 | ||
|
|
0e92deddc4 | ||
|
|
fa2c831ef3 | ||
|
|
2916990077 | ||
|
|
ef6716625e | ||
|
|
a138cea3ed | ||
|
|
1387d88043 | ||
|
|
9deb2d3732 | ||
|
|
a95318f1ab | ||
|
|
5ea6c0f525 | ||
|
|
c74cfa3c5d | ||
|
|
5cce05fc46 | ||
|
|
c2838d78a2 | ||
|
|
ba2f2f8840 | ||
|
|
ebd4fbd1d2 | ||
|
|
b1d8d1081c | ||
|
|
c579fb521e | ||
|
|
fc28375e42 | ||
|
|
f89bb3e125 | ||
|
|
3628b61d75 | ||
|
|
0bddadea35 | ||
|
|
cfc5ecc59c | ||
|
|
72006334f5 | ||
|
|
94a3883880 | ||
|
|
84e7bdb2b1 | ||
|
|
b7cb9aa938 | ||
|
|
259007954b | ||
|
|
a51a6ab489 | ||
|
|
e57f08f46e | ||
|
|
2e25c4c0a3 | ||
|
|
bc593695f9 | ||
|
|
9811564f70 | ||
|
|
32e4daaeba | ||
|
|
aaff13a079 | ||
|
|
241030f916 | ||
|
|
2afa079b6a | ||
|
|
637c48905a | ||
|
|
43098a07e7 | ||
|
|
c37ece9007 | ||
|
|
aaebd8a5cf | ||
|
|
6f70df0852 | ||
|
|
975c4dd03c | ||
|
|
495ace2423 | ||
|
|
b651050dd0 | ||
|
|
eb03a56dfc | ||
|
|
13193d209e | ||
|
|
bcb8824e2c | ||
|
|
1e3cf9fa78 | ||
|
|
b1b516e9c4 | ||
|
|
0e1da5ef28 | ||
|
|
4df666e964 | ||
|
|
0729f2eb59 | ||
|
|
c79474a57c | ||
|
|
ec9dd06d38 | ||
|
|
920d140e40 | ||
|
|
b163b1b685 | ||
|
|
8c28017239 | ||
|
|
e1e66f3082 | ||
|
|
c4aefe9396 | ||
|
|
7674a9eaee | ||
|
|
76c295a60b | ||
|
|
d80af64798 | ||
|
|
ccc51664f4 | ||
|
|
f66d6e4f97 | ||
|
|
67f3d1584c | ||
|
|
c94aef8845 | ||
|
|
4eb6c6fb5b | ||
|
|
8e15846ec5 | ||
|
|
ff55e768c9 | ||
|
|
557bbff36c | ||
|
|
946367aa19 | ||
|
|
2bb8afa9e0 | ||
|
|
42e0cd07ac | ||
|
|
307ac852a6 | ||
|
|
ffecd03cb2 | ||
|
|
0f037651f3 | ||
|
|
77797741a5 | ||
|
|
a19a6317ec | ||
|
|
85e5b20ede | ||
|
|
f34a110d5b | ||
|
|
f54b2ac81a | ||
|
|
afbdb94bb3 | ||
|
|
e85beb91dc | ||
|
|
2f2ef09c92 | ||
|
|
a5641c8144 | ||
|
|
4391c9147b | ||
|
|
308a3e23ad | ||
|
|
0ac7b420f2 | ||
|
|
32abbb9371 | ||
|
|
b74e5ca254 | ||
|
|
9b3e60f5ce | ||
|
|
f0cff687aa | ||
|
|
73fea6a197 | ||
|
|
7e3dbf51fa | ||
|
|
0983fa11be | ||
|
|
d5dc0d4d5b | ||
|
|
e9fa188d42 | ||
|
|
fd3721e050 | ||
|
|
d61d540655 | ||
|
|
e1c049bece | ||
|
|
e498077e6a | ||
|
|
057a92f92c | ||
|
|
cce2191eb6 | ||
|
|
00b5aaeb26 | ||
|
|
91580ed4a3 | ||
|
|
06f78bf28f | ||
|
|
502ad1a02a | ||
|
|
49582c3591 | ||
|
|
f1413c7717 | ||
|
|
55ece141e8 | ||
|
|
519f82f1e7 | ||
|
|
930e059a16 | ||
|
|
82a1b05f28 | ||
|
|
b467444ad3 | ||
|
|
c7e6d9d474 | ||
|
|
d6876b995d | ||
|
|
61bb4944fa | ||
|
|
9f761822e1 | ||
|
|
3cee3de94f | ||
|
|
38432a73e7 | ||
|
|
71b71f2d65 | ||
|
|
d400952acc | ||
|
|
43d28a8595 | ||
|
|
17505673d6 | ||
|
|
0fa3415cc0 | ||
|
|
b31a5fb421 | ||
|
|
eb13def609 | ||
|
|
a721a19137 | ||
|
|
25a75f1876 | ||
|
|
b31a174ac6 | ||
|
|
612158277e | ||
|
|
c60dd05e33 | ||
|
|
e5d7ebd978 | ||
|
|
0645bc6acc | ||
|
|
d01ca92120 | ||
|
|
61c963a8ae | ||
|
|
e83c69d968 | ||
|
|
dfdceb1908 | ||
|
|
36be369901 | ||
|
|
b3673e93d7 | ||
|
|
985ef4518f | ||
|
|
096f033954 | ||
|
|
92f4c0c001 | ||
|
|
10f2c105b1 | ||
|
|
34e343ec66 | ||
|
|
aec56c63be | ||
|
|
c6d6e500fb | ||
|
|
a3c1640fb7 | ||
|
|
0a695dd442 | ||
|
|
64c960041b | ||
|
|
f3048eb574 | ||
|
|
48f38b8940 | ||
|
|
a535c6917e | ||
|
|
0432514ccf | ||
|
|
a9baae4e98 | ||
|
|
0e44abe741 | ||
|
|
40e44e6dd7 | ||
|
|
02413d165a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ cairo_test.py
|
||||
mayavi_test.py
|
||||
random_scenes/
|
||||
files/
|
||||
assets/
|
||||
ben_playground.py
|
||||
ben_cairo_test.py
|
||||
.floo
|
||||
|
||||
3
LICENSE
3
LICENSE
@@ -1,5 +1,4 @@
|
||||
All files of this project under the directories active_projects and old_projects
|
||||
are copyright 3Blue1Brown LLC and used by permission for this project only.
|
||||
All files of this project under the directory "from_3b1b" are copyright 3Blue1Brown LLC and used by permission for this project only.
|
||||
|
||||
Any other file of this project is available under the MIT license as follow:
|
||||
|
||||
|
||||
51
README.md
51
README.md
@@ -1,7 +1,7 @@
|
||||
<img src="logo/cropped.png"/>
|
||||

|
||||
|
||||
[](https://travis-ci.org/3b1b/manim)
|
||||
[](https://www.eulertour.com/learn/manim/)
|
||||
[](https://www.eulertour.com/docs)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
[](https://www.reddit.com/r/manim/)
|
||||
[](https://discord.gg/mMRrZQW)
|
||||
@@ -9,7 +9,7 @@
|
||||
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/).
|
||||
|
||||
## Installation
|
||||
Manim runs on python 3.7. You can install it from PyPI via pip
|
||||
Manim runs on Python 3.7. You can install it from PyPI via pip:
|
||||
|
||||
```sh
|
||||
pip3 install manimlib
|
||||
@@ -23,7 +23,7 @@ You can now use it via the `manim` command. For example:
|
||||
manim my_project.py MyScene
|
||||
```
|
||||
|
||||
For more options, take a look at the “Using manim“ sections further below.
|
||||
For more options, take a look at the [Using manim](#using-manim) sections further below.
|
||||
|
||||
### Directly
|
||||
|
||||
@@ -39,7 +39,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. Download the wheel from 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.
|
||||
```sh
|
||||
pip3 install C:\path\to\wheel\pycairo‑1.18.0‑cp37‑cp37m‑win32.whl
|
||||
```
|
||||
@@ -74,14 +74,14 @@ python3 -m manim example_scenes.py SquareToCircle -pl
|
||||
### Using Docker
|
||||
Since it's a bit tricky to get all the dependencies set up just right, there is a Dockerfile and Compose file provided in this repo as well as [a premade image on Docker Hub](https://hub.docker.com/r/eulertour/manim/tags/). The Dockerfile contains instructions on how to build a manim image, while the Compose file contains instructions on how to run the image.
|
||||
|
||||
The prebuilt container image has manin repository included.
|
||||
The prebuilt container image has manim repository included.
|
||||
`INPUT_PATH` is where the container looks for scene files. You must set the `INPUT_PATH`
|
||||
environment variable to the absolute path containing your scene file and the
|
||||
`OUTPUT_PATH` environment variable to the directory where you want media to be written.
|
||||
|
||||
1. [Install Docker](https://docs.docker.com)
|
||||
2. [Install Docker Compose](https://docs.docker.com/compose/install/)
|
||||
3. Render an animation
|
||||
3. Render an animation:
|
||||
```sh
|
||||
INPUT_PATH=/path/to/dir/containing/source/code \
|
||||
OUTPUT_PATH=/path/to/output/ \
|
||||
@@ -91,9 +91,9 @@ The command needs to be run as root if your username is not in the docker group.
|
||||
|
||||
You can replace `example.scenes.py` with any relative path from your `INPUT_PATH`.
|
||||
|
||||
<img src=./manim_docker_diagram.png/>
|
||||

|
||||
|
||||
After running the output will say files ready at `/tmp/output/`, which refers to path inside the container. Your OUTPUT_PATH is bind mounted to this `/tmp/output` so any changes made by the container to `/tmp/output` will be mirrored on your OUTPUT_PATH. `/media/` will be created in `OUTPUT_PATH`.
|
||||
After running the output will say files ready at `/tmp/output/`, which refers to path inside the container. Your `OUTPUT_PATH` is bind mounted to this `/tmp/output` so any changes made by the container to `/tmp/output` will be mirrored on your `OUTPUT_PATH`. `/media/` will be created in `OUTPUT_PATH`.
|
||||
|
||||
`-p` won't work as manim would look for video player in the container system, which it does not have.
|
||||
|
||||
@@ -108,49 +108,26 @@ python3 -m manim example_scenes.py SquareToCircle -pl
|
||||
The `-p` flag in the command above is for previewing, meaning the video file will automatically open when it is done rendering. The `-l` flag is for a faster rendering at a lower quality.
|
||||
|
||||
Some other useful flags include:
|
||||
|
||||
* `-s` to skip to the end and just show the final frame.
|
||||
* `-n <number>` to skip ahead to the `n`'th animation of a scene.
|
||||
* `-f` to show the file in finder (for OSX).
|
||||
|
||||
Set `MEDIA_DIR` environment variable to specify where the image and animation files will be written.
|
||||
|
||||
Look through the `old_projects` folder to see the code for previous 3b1b videos. Note, however, that developments are often made to the library without considering backwards compatibility with those old projects. To run an old project with a guarantee that it will work, you will have to go back to the commit which completed that project.
|
||||
Look through the `old_projects` folder to see the code for previous 3b1b videos. Note, however, that developments are often made to the library without considering backwards compatibility with those old projects. To run an old project with a guarantee that it will work, you will have to go back to the commit which completed that project.
|
||||
|
||||
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.
|
||||
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 [manim.readthedocs.io](https://manim.readthedocs.io).
|
||||
Documentation is in progress at [eulertour.com/docs](https://www.eulertour.com/docs/).
|
||||
|
||||
### 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.
|
||||
|
||||
### Live Streaming
|
||||
To live stream your animations, simply run manim with the `--livestream` option.
|
||||
|
||||
```sh
|
||||
> python -m manim --livestream
|
||||
Writing to media/videos/scene/scene/1080p30/LiveStreamTemp.mp4
|
||||
|
||||
Manim is now running in streaming mode. Stream animations by passing
|
||||
them to manim.play(), e.g.
|
||||
>>> c = Circle()
|
||||
>>> manim.play(ShowCreation(c))
|
||||
|
||||
>>>
|
||||
```
|
||||
|
||||
It is also possible to stream directly to Twitch. To do that simply pass
|
||||
--livestream and --to-twitch to manim and specify the stream key with
|
||||
--with-key. Then when you follow the above example the stream will directly
|
||||
start on your Twitch channel (with no audio support).
|
||||
|
||||
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.
|
||||
|
||||
## Contributing
|
||||
Is always welcome. In particular, there is a dire need for tests and documentation.
|
||||
|
||||
|
||||
## License
|
||||
All files in the directories active_projects and old_projects, which by and large generate the visuals for 3b1b videos, are copyright 3Blue1Brown.
|
||||
All files in the directory `from_3b1b`, which by and large generate the visuals for 3b1b videos, are copyright 3Blue1Brown.
|
||||
|
||||
The general purpose animation code found in the remainder of the repository, on the other hand, is under the MIT license.
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
from active_projects.ode.part4.staging import *
|
||||
from active_projects.ode.part4.fourier_series_scenes import *
|
||||
from active_projects.ode.part4.pi_creature_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ComplexFourierSeriesExample,
|
||||
ComplexFourierSeriesExampleEnd,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample,
|
||||
RelationToOtherVideos,
|
||||
WhyWouldYouCare,
|
||||
# Oldies
|
||||
|
||||
# FourierSeriesIllustraiton,
|
||||
# FourierNameIntro,
|
||||
# CircleAnimationOfF,
|
||||
]
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.fourier_series import FourierOfName
|
||||
|
||||
name_color_pairs = [
|
||||
|
||||
]
|
||||
|
||||
circle_counts = [
|
||||
# 10,
|
||||
# 25,
|
||||
100,
|
||||
]
|
||||
|
||||
if __name__ == "__main__":
|
||||
for name, color in name_color_pairs:
|
||||
for n_circles in circle_counts:
|
||||
try:
|
||||
first_name = name.split(" ")[0]
|
||||
scene = FourierOfName(
|
||||
name_text=name,
|
||||
name_color=color,
|
||||
n_circles=n_circles,
|
||||
file_writer_config={
|
||||
"write_to_movie": True,
|
||||
"output_directory": os.path.join(
|
||||
"patron_fourier_names",
|
||||
first_name,
|
||||
),
|
||||
"file_name": "{}_Fouierified_{}_Separate_paths".format(
|
||||
first_name,
|
||||
n_circles
|
||||
),
|
||||
},
|
||||
camera_config={
|
||||
"frame_rate": 24,
|
||||
},
|
||||
)
|
||||
except:
|
||||
pass
|
||||
@@ -1,242 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
from active_projects.ode.part2.fourier_series import FourierOfTrebleClef
|
||||
|
||||
|
||||
class ComplexFourierSeriesExample(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "EighthNote",
|
||||
"run_time": 10,
|
||||
"n_vectors": 200,
|
||||
"n_cycles": 2,
|
||||
"max_circle_stroke_width": 0.75,
|
||||
"drawing_height": 5,
|
||||
"center_point": DOWN,
|
||||
"top_row_y": 3,
|
||||
"top_row_label_y": 2,
|
||||
"top_row_x_spacing": 1.75,
|
||||
"top_row_copy_scale_factor": 0.9,
|
||||
"start_drawn": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.add_top_row(self.vectors, self.circles)
|
||||
self.write_title()
|
||||
self.highlight_vectors_one_by_one()
|
||||
self.change_shape()
|
||||
|
||||
def write_title(self):
|
||||
title = TextMobject("Complex\\\\Fourier series")
|
||||
title.scale(1.5)
|
||||
title.to_edge(LEFT)
|
||||
title.match_y(self.path)
|
||||
|
||||
self.wait(5)
|
||||
self.play(FadeInFromDown(title))
|
||||
self.wait(2)
|
||||
self.title = title
|
||||
|
||||
def highlight_vectors_one_by_one(self):
|
||||
# Don't know why these vectors can't get copied.
|
||||
# That seems like a problem that will come up again.
|
||||
labels = self.top_row[-1]
|
||||
next_anims = []
|
||||
for vector, circle, label in zip(self.vectors, self.circles, labels):
|
||||
# v_color = vector.get_color()
|
||||
c_color = circle.get_color()
|
||||
c_stroke_width = circle.get_stroke_width()
|
||||
|
||||
rect = SurroundingRectangle(label, color=PINK)
|
||||
self.play(
|
||||
# vector.set_color, PINK,
|
||||
circle.set_stroke, RED, 3,
|
||||
FadeIn(rect),
|
||||
*next_anims
|
||||
)
|
||||
self.wait()
|
||||
next_anims = [
|
||||
# vector.set_color, v_color,
|
||||
circle.set_stroke, c_color, c_stroke_width,
|
||||
FadeOut(rect),
|
||||
]
|
||||
self.play(*next_anims)
|
||||
|
||||
def change_shape(self):
|
||||
# path_mob = TexMobject("\\pi")
|
||||
path_mob = SVGMobject("Nail_And_Gear")
|
||||
new_path = path_mob.family_members_with_points()[0]
|
||||
new_path.set_height(4)
|
||||
new_path.move_to(self.path, DOWN)
|
||||
new_path.shift(0.5 * UP)
|
||||
new_coefs = self.get_coefficients_of_path(new_path)
|
||||
new_vectors = self.get_rotating_vectors(
|
||||
coefficients=new_coefs
|
||||
)
|
||||
new_drawn_path = self.get_drawn_path(new_vectors)
|
||||
|
||||
self.vector_clock.set_value(0)
|
||||
self.vector_clock.suspend_updating(0)
|
||||
|
||||
vectors = self.vectors
|
||||
anims = []
|
||||
|
||||
for vect, new_vect in zip(vectors, new_vectors):
|
||||
new_vect.update()
|
||||
new_vect.clear_updaters()
|
||||
|
||||
line = Line(stroke_width=0)
|
||||
line.put_start_and_end_on(*vect.get_start_and_end())
|
||||
anims.append(ApplyMethod(
|
||||
line.put_start_and_end_on,
|
||||
*new_vect.get_start_and_end()
|
||||
))
|
||||
vect.freq = new_vect.freq
|
||||
vect.phase = new_vect.phase
|
||||
vect.coefficient = new_vect.coefficient
|
||||
|
||||
vect.line = line
|
||||
vect.add_updater(
|
||||
lambda v: v.put_start_and_end_on(
|
||||
*v.line.get_start_and_end()
|
||||
)
|
||||
)
|
||||
anims += [
|
||||
FadeOut(self.drawn_path)
|
||||
]
|
||||
|
||||
self.play(*anims, run_time=3)
|
||||
self.vector_clock.resume_updating()
|
||||
for vect in self.vectors:
|
||||
vect.remove_updater(vect.updaters[-1])
|
||||
|
||||
self.add(new_drawn_path)
|
||||
for n in range(self.n_cycles):
|
||||
self.run_one_cycle()
|
||||
|
||||
#
|
||||
def get_path(self):
|
||||
path = super().get_path()
|
||||
path.set_height(self.drawing_height)
|
||||
path.to_edge(DOWN)
|
||||
return path
|
||||
|
||||
def add_top_row(self, vectors, circles, max_freq=3):
|
||||
self.top_row = self.get_top_row(
|
||||
vectors, circles, max_freq
|
||||
)
|
||||
self.add(self.top_row)
|
||||
|
||||
def get_top_row(self, vectors, circles, max_freq=3):
|
||||
vector_copies = VGroup()
|
||||
circle_copies = VGroup()
|
||||
for vector, circle in zip(vectors, circles):
|
||||
if vector.freq > max_freq:
|
||||
break
|
||||
vcopy = vector.copy()
|
||||
vcopy.clear_updaters()
|
||||
ccopy = circle.copy()
|
||||
ccopy.clear_updaters()
|
||||
ccopy.original = circle
|
||||
vcopy.original = vector
|
||||
|
||||
vcopy.center_point = np.array([
|
||||
vector.freq * self.top_row_x_spacing,
|
||||
self.top_row_y,
|
||||
0
|
||||
])
|
||||
ccopy.center_point = vcopy.center_point
|
||||
vcopy.add_updater(self.update_top_row_vector_copy)
|
||||
ccopy.add_updater(self.update_top_row_circle_copy)
|
||||
vector_copies.add(vcopy)
|
||||
circle_copies.add(ccopy)
|
||||
|
||||
dots = VGroup(*[
|
||||
TexMobject("\\dots").next_to(
|
||||
circle_copies, direction,
|
||||
MED_LARGE_BUFF,
|
||||
)
|
||||
for direction in [LEFT, RIGHT]
|
||||
])
|
||||
labels = self.get_top_row_labels(vector_copies)
|
||||
return VGroup(
|
||||
vector_copies,
|
||||
circle_copies,
|
||||
dots,
|
||||
labels,
|
||||
)
|
||||
|
||||
def update_top_row_vector_copy(self, vcopy):
|
||||
vcopy.become(vcopy.original)
|
||||
vcopy.scale(self.top_row_copy_scale_factor)
|
||||
vcopy.shift(vcopy.center_point - vcopy.get_start())
|
||||
return vcopy
|
||||
|
||||
def update_top_row_circle_copy(self, ccopy):
|
||||
ccopy.become(ccopy.original)
|
||||
ccopy.scale(self.top_row_copy_scale_factor)
|
||||
ccopy.move_to(ccopy.center_point)
|
||||
return ccopy
|
||||
|
||||
def get_top_row_labels(self, vector_copies):
|
||||
labels = VGroup()
|
||||
for vector_copy in vector_copies:
|
||||
freq = vector_copy.freq
|
||||
label = Integer(freq)
|
||||
label.move_to(np.array([
|
||||
freq * self.top_row_x_spacing,
|
||||
self.top_row_label_y,
|
||||
0
|
||||
]))
|
||||
labels.add(label)
|
||||
return labels
|
||||
|
||||
|
||||
class ComplexFourierSeriesExampleEnd(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class FourierSeriesExampleWithRectForZoom(ComplexFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"slow_factor": 0.01,
|
||||
"rect_scale_factor": 0.15,
|
||||
"parametric_function_step_size": 0.0001,
|
||||
"start_drawn": True,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.circles.set_stroke(opacity=0.5)
|
||||
rect = self.get_rect()
|
||||
rect.set_height(self.rect_scale_factor * FRAME_HEIGHT)
|
||||
rect.add_updater(lambda m: m.move_to(
|
||||
center_of_mass([
|
||||
v.get_end()
|
||||
for v in self.vectors
|
||||
])
|
||||
))
|
||||
self.add(rect)
|
||||
self.run_one_cycle()
|
||||
|
||||
def get_rect(self):
|
||||
return ScreenRectangle(
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample(FourierSeriesExampleWithRectForZoom, MovingCameraScene):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15,
|
||||
"tip_length": 0.05,
|
||||
}
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
ComplexFourierSeriesExample.setup(self)
|
||||
MovingCameraScene.setup(self)
|
||||
|
||||
def get_rect(self):
|
||||
return self.camera_frame
|
||||
@@ -1,22 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WhyWouldYouCare(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Who cares!",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
added_anims=[self.teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[2]),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(
|
||||
"pondering", "erm", "thinking",
|
||||
look_at_arg=self.screen,
|
||||
)
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(5)
|
||||
@@ -18,7 +18,7 @@ Directories
|
||||
Created under ``MEDIA_DIR`` by default.
|
||||
TEX_DIR
|
||||
Files written by Latex are stored here. It also acts as a cache
|
||||
so that the files aren't rewritten each Latex is needed.
|
||||
so that the files aren't rewritten each time Latex is needed.
|
||||
|
||||
Those directories are created if they don't exist.
|
||||
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
Making a Scene
|
||||
==============
|
||||
|
||||
Talk about Scenes and organization, bring it all together.
|
||||
A scene is what renders when manim is executed. Each scene contains mobjects, which can then be animated as
|
||||
previously explained. In code, a scene is a class that extends ``Scene`` and implements the ``construct``
|
||||
function, like so. Manim will execute this function to render the scene.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
class ExampleScene(Scene):
|
||||
def construct(self):
|
||||
# Add and animate mobjects here
|
||||
@@ -39,3 +39,26 @@ the ``activate`` binary by doing ``source bin/activate``, to exit use the ``deac
|
||||
|
||||
texlive texlive-latex-extra texlive-fonts-extra
|
||||
texlive-latex-recommended texlive-science texlive-fonts-extra tipa
|
||||
|
||||
Arch Linux
|
||||
----------
|
||||
Install system libraries::
|
||||
|
||||
# pacman -S cairo ffmpeg opencv sox
|
||||
|
||||
Install Latex distribution::
|
||||
|
||||
# pacman -S texlive-most
|
||||
|
||||
OR install python-manimlib_:sup:`AUR` package::
|
||||
|
||||
$ git clone https://aur.archlinux.org/python-manimlib.git
|
||||
$ cd python-manimlib
|
||||
$ makepkg -si
|
||||
|
||||
You can use AUR helpers such as yay_:sup:`AUR`::
|
||||
|
||||
$ yay -S python-manimlib
|
||||
|
||||
.. _python-manimlib: https://aur.archlinux.org/packages/python-manimlib/
|
||||
.. _yay: https://aur.archlinux.org/packages/yay/
|
||||
|
||||
@@ -8,5 +8,5 @@ Mac come preinstalled with python2, but to use manim, python3 is required
|
||||
2. Install Cairo: ``brew install cairo``
|
||||
3. Install Sox: ``brew install sox``
|
||||
4. Install ffmpeg: ``brew install ffmpeg``
|
||||
5. Install latex (MiKTeX): https://miktex.org/howto/install-miktex-mac
|
||||
5. Install latex (MacTeX): ``brew cask install mactex``
|
||||
6. Install manimlib ``pip install manimlib`` (or ``pip install --user manimlib`` to just yourself)
|
||||
|
||||
@@ -49,12 +49,12 @@ the repository page with ``Clone or download`` button and unzip it.
|
||||
|
||||
Open the commandline within the manim directory with ``Shift + Right click`` on an empty space in the folder and select ``open command window here``
|
||||
|
||||
Install manim python dependencies with ``pip install -r requirement.txt``
|
||||
Install manim python dependencies with ``pip install -r requirements.txt``
|
||||
|
||||
Test the installation
|
||||
---------------------
|
||||
|
||||
Type in ``python -m manim -h`` and if nothing went wrong during the installtion process you should see the help text.
|
||||
Type in ``python -m manim -h`` and if nothing went wrong during the installation process you should see the help text.
|
||||
|
||||
Use ``python -m manim example_scenes.py SquareToCircle -pl`` to render the example scene and the file should play after rendering. The movie file should be
|
||||
in ``media/videos/example_scenes/480p15``
|
||||
|
||||
@@ -5,7 +5,7 @@ channels:
|
||||
dependencies:
|
||||
- python=3.7
|
||||
- cairo
|
||||
- ffmpeg
|
||||
- ffmpeg
|
||||
- colour==0.1.5
|
||||
- numpy==1.15.0
|
||||
- pillow==5.2.0
|
||||
@@ -14,4 +14,6 @@ dependencies:
|
||||
- opencv==3.4.2
|
||||
- pycairo==1.18.0
|
||||
- pydub==0.23.0
|
||||
- pyreadline
|
||||
- ffmpeg
|
||||
- pip:
|
||||
- pyreadline
|
||||
|
||||
1152
from_3b1b/active/bayes/footnote.py
Normal file
1152
from_3b1b/active/bayes/footnote.py
Normal file
File diff suppressed because it is too large
Load Diff
4830
from_3b1b/active/bayes/part1.py
Normal file
4830
from_3b1b/active/bayes/part1.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
from active_projects.ode.part1.pendulum import *
|
||||
from active_projects.ode.part1.staging import *
|
||||
from active_projects.ode.part1.pi_scenes import *
|
||||
from active_projects.ode.part1.phase_space import *
|
||||
from active_projects.ode.part1.wordy_scenes import *
|
||||
from active_projects.diffyq.part1.pendulum import *
|
||||
from active_projects.diffyq.part1.staging import *
|
||||
from active_projects.diffyq.part1.pi_scenes import *
|
||||
from active_projects.diffyq.part1.phase_space import *
|
||||
from active_projects.diffyq.part1.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
OUTPUT_DIRECTORY = "diffyq/part1"
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
@@ -1,10 +1,10 @@
|
||||
from active_projects.ode.part2.staging import *
|
||||
from active_projects.ode.part2.fourier_series import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.ode.part2.pi_scenes import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
from active_projects.diffyq.part2.staging import *
|
||||
from active_projects.diffyq.part2.fourier_series import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.pi_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part2"
|
||||
OUTPUT_DIRECTORY = "diffyq/part2"
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
@@ -1,11 +1,11 @@
|
||||
from active_projects.ode.part3.staging import *
|
||||
from active_projects.ode.part3.temperature_graphs import *
|
||||
from active_projects.ode.part3.pi_creature_scenes import *
|
||||
from active_projects.ode.part3.wordy_scenes import *
|
||||
from active_projects.ode.part3.discrete_case import *
|
||||
from active_projects.diffyq.part3.staging import *
|
||||
from active_projects.diffyq.part3.temperature_graphs import *
|
||||
from active_projects.diffyq.part3.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part3.wordy_scenes import *
|
||||
from active_projects.diffyq.part3.discrete_case import *
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part3"
|
||||
OUTPUT_DIRECTORY = "diffyq/part3"
|
||||
SCENES_IN_ORDER = [
|
||||
LastChapterWrapper,
|
||||
ThreeConstraints,
|
||||
65
from_3b1b/active/diffyq/all_part4_scenes.py
Normal file
65
from_3b1b/active/diffyq/all_part4_scenes.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from active_projects.diffyq.part4.staging import *
|
||||
from active_projects.diffyq.part4.fourier_series_scenes import *
|
||||
from active_projects.diffyq.part4.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part4.three_d_graphs import *
|
||||
from active_projects.diffyq.part4.temperature_scenes import *
|
||||
from active_projects.diffyq.part4.complex_functions import *
|
||||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
from active_projects.diffyq.part3.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ComplexFourierSeriesExample,
|
||||
FourierOfFourier,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierSeriesFormula,
|
||||
RelationToOtherVideos,
|
||||
WhyWouldYouCare,
|
||||
ShowLinearity,
|
||||
CombineSeveralSolutions,
|
||||
FourierGainsImmortality,
|
||||
SolveForWavesNothingElse,
|
||||
CycleThroughManyLinearCombinations,
|
||||
StepFunctionExample,
|
||||
WhichWavesAreAvailable,
|
||||
AlternateBoundaryConditions,
|
||||
AskQuestionOfGraph,
|
||||
CommentOnFouriersImmortality,
|
||||
HangOnThere,
|
||||
ShowInfiniteSum,
|
||||
TechnicalNuances,
|
||||
BreakDownStepFunction,
|
||||
StepFunctionSolutionFormla,
|
||||
# How to compute
|
||||
FourierSeriesOfLineIllustration,
|
||||
GeneralizeToComplexFunctions,
|
||||
ClarifyInputAndOutput,
|
||||
GraphForFlattenedPi,
|
||||
PiFourierSeries,
|
||||
RealValuedFunctionFourierSeries,
|
||||
YouSaidThisWasEasier,
|
||||
AskAboutComplexNotVector,
|
||||
SimpleComplexExponentExample,
|
||||
LooseWithLanguage,
|
||||
DemonstrateAddingArrows,
|
||||
TRangingFrom0To1,
|
||||
LabelRotatingVectors,
|
||||
IntegralTrick,
|
||||
SwapIntegralAndSum,
|
||||
FootnoteOnSwappingIntegralAndSum,
|
||||
FormulaOutOfContext,
|
||||
ShowRangeOfCnFormulas,
|
||||
DescribeSVG,
|
||||
# TODO
|
||||
IncreaseOrderOfApproximation,
|
||||
ShowStepFunctionIn2dView,
|
||||
StepFunctionIntegral,
|
||||
GeneralChallenge,
|
||||
|
||||
# Oldies
|
||||
# FourierSeriesIllustraiton,
|
||||
# FourierNameIntro,
|
||||
# CircleAnimationOfF,
|
||||
]
|
||||
5
from_3b1b/active/diffyq/all_part5_scenes.py
Normal file
5
from_3b1b/active/diffyq/all_part5_scenes.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from active_projects.diffyq.part5.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part5"
|
||||
SCENES_IN_ORDER = [
|
||||
]
|
||||
23
from_3b1b/active/diffyq/fourier_montage_scenes.py
Normal file
23
from_3b1b/active/diffyq/fourier_montage_scenes.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ZoomedInFourierSeriesExample,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample100x,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier,
|
||||
SigmaZoomedInFourierSeriesExample,
|
||||
SigmaFourierSeriesExampleWithRectForZoom,
|
||||
NailAndGearZoomedInFourierSeriesExample,
|
||||
NailAndGearFourierSeriesExampleWithRectForZoom,
|
||||
TrebleClefZoomedInFourierSeriesExample,
|
||||
TrebleClefFourierSeriesExampleWithRectForZoom,
|
||||
FourierOfSeattle,
|
||||
FourierOfSeattleZoomedIn,
|
||||
FourierOfBritain,
|
||||
FourierOfBritainZoomedIn,
|
||||
FourierOfHilbert,
|
||||
FourierOfHilbertZoomedIn,
|
||||
]
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class Pendulum(VGroup):
|
||||
@@ -254,7 +254,7 @@ class ThetaVsTAxes(Axes):
|
||||
"tick_frequency": PI / 8,
|
||||
"unit_size": 1.5,
|
||||
},
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"color": "#EEEEEE",
|
||||
"stroke_width": 2,
|
||||
"include_tip": False,
|
||||
@@ -371,7 +371,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
||||
"tip_length": 0.3,
|
||||
},
|
||||
"x_max": 12,
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"stroke_width": 2,
|
||||
}
|
||||
},
|
||||
@@ -750,7 +750,7 @@ class LowAnglePendulum(Scene):
|
||||
"number_scale_val": 0.5,
|
||||
},
|
||||
"x_max": 25,
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
@@ -837,7 +837,7 @@ class MediumAnglePendulum(LowAnglePendulum):
|
||||
"y_axis_config": {"unit_size": 0.75},
|
||||
"y_max": PI / 2,
|
||||
"y_min": -PI / 2,
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
@@ -867,7 +867,7 @@ class HighAnglePendulum(LowAnglePendulum):
|
||||
"y_axis_config": {"unit_size": 0.5},
|
||||
"y_max": PI,
|
||||
"y_min": -PI,
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
@@ -888,7 +888,7 @@ class VeryLowAnglePendulum(LowAnglePendulum):
|
||||
"y_axis_config": {"unit_size": 2},
|
||||
"y_max": PI / 4,
|
||||
"y_min": -PI / 4,
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.ode.part1.pendulum import Pendulum
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.pendulum import Pendulum
|
||||
|
||||
|
||||
# TODO: Arguably separate the part showing many
|
||||
@@ -2012,11 +2012,18 @@ class ManyStepsFromDifferentStartingPoints(TakeManyTinySteps):
|
||||
class Thumbnail(IntroduceVectorField):
|
||||
CONFIG = {
|
||||
"vector_field_config": {
|
||||
"delta_x": 0.5,
|
||||
"delta_y": 0.5,
|
||||
# "delta_x": 0.5,
|
||||
# "delta_y": 0.5,
|
||||
# "max_magnitude": 5,
|
||||
# "length_func": lambda norm: 0.5 * sigmoid(norm),
|
||||
"delta_x": 1,
|
||||
"delta_y": 1,
|
||||
"max_magnitude": 5,
|
||||
"length_func": lambda norm: 0.5 * sigmoid(norm),
|
||||
}
|
||||
"length_func": lambda norm: 0.9 * sigmoid(norm),
|
||||
},
|
||||
"big_pendulum_config": {
|
||||
"damping": 0.4,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
@@ -2027,7 +2034,7 @@ class Thumbnail(IntroduceVectorField):
|
||||
field = self.vector_field
|
||||
field.set_stroke(width=5)
|
||||
for vector in field:
|
||||
vector.set_stroke(width=3)
|
||||
vector.set_stroke(width=8)
|
||||
vector.tip.set_stroke(width=0)
|
||||
vector.tip.scale(1.5, about_point=vector.get_last_point())
|
||||
vector.set_opacity(1)
|
||||
@@ -2063,17 +2070,43 @@ class Thumbnail(IntroduceVectorField):
|
||||
new_mob.set_stroke(width=0)
|
||||
black_parts.add(new_mob)
|
||||
|
||||
for vect in field:
|
||||
for mob in title.family_members_with_points():
|
||||
for p in [vect.get_start(), vect.get_end()]:
|
||||
x, y = p[:2]
|
||||
x0, y0 = mob.get_corner(DL)[:2]
|
||||
x1, y1 = mob.get_corner(UR)[:2]
|
||||
if x0 < x < x1 and y0 < y < y1:
|
||||
vect.set_opacity(0.25)
|
||||
vect.tip.set_stroke(width=0)
|
||||
# for vect in field:
|
||||
# for mob in title.family_members_with_points():
|
||||
# for p in [vect.get_start(), vect.get_end()]:
|
||||
# x, y = p[:2]
|
||||
# x0, y0 = mob.get_corner(DL)[:2]
|
||||
# x1, y1 = mob.get_corner(UR)[:2]
|
||||
# if x0 < x < x1 and y0 < y < y1:
|
||||
# vect.set_opacity(0.25)
|
||||
# vect.tip.set_stroke(width=0)
|
||||
|
||||
self.add(self.plane)
|
||||
self.add(field)
|
||||
self.add(black_parts)
|
||||
self.add(title)
|
||||
# self.add(black_parts)
|
||||
# self.add(title)
|
||||
|
||||
self.add_line(self.plane)
|
||||
|
||||
def add_line(self, axes):
|
||||
func = self.vector_field_func
|
||||
|
||||
line = VMobject()
|
||||
line.start_new_path(axes.c2p(-TAU, 3.5))
|
||||
|
||||
dt = 0.1
|
||||
t = 0
|
||||
total_time = 40
|
||||
|
||||
while t < total_time:
|
||||
t += dt
|
||||
last_point = line.get_last_point()
|
||||
new_point = last_point + dt * func(last_point)
|
||||
if new_point[0] > FRAME_WIDTH / 2:
|
||||
new_point = last_point + FRAME_WIDTH * LEFT
|
||||
line.start_new_path(new_point)
|
||||
else:
|
||||
line.add_smooth_curve_to(new_point)
|
||||
|
||||
line.set_stroke(WHITE, 6)
|
||||
line.make_smooth()
|
||||
self.add(line)
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SomeOfYouWatching(TeacherStudentsScene):
|
||||
@@ -1,10 +1,10 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.ode.part1.pendulum import Pendulum
|
||||
from active_projects.ode.part1.pendulum import ThetaVsTAxes
|
||||
from active_projects.ode.part1.phase_space import IntroduceVectorField
|
||||
from old_projects.div_curl import PhaseSpaceOfPopulationModel
|
||||
from old_projects.div_curl import ShowTwoPopulations
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.pendulum import Pendulum
|
||||
from active_projects.diffyq.part1.pendulum import ThetaVsTAxes
|
||||
from active_projects.diffyq.part1.phase_space import IntroduceVectorField
|
||||
from from_3b1b.old.div_curl import PhaseSpaceOfPopulationModel
|
||||
from from_3b1b.old.div_curl import ShowTwoPopulations
|
||||
|
||||
|
||||
# Scenes
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SmallAngleApproximationTex(Scene):
|
||||
@@ -29,6 +29,8 @@ class FourierCirclesScene(Scene):
|
||||
"slow_factor": 0.25,
|
||||
"center_point": ORIGIN,
|
||||
"parametric_function_step_size": 0.001,
|
||||
"drawn_path_color": YELLOW,
|
||||
"drawn_path_stroke_width": 2,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
@@ -95,7 +97,6 @@ class FourierCirclesScene(Scene):
|
||||
phase = np.log(coefficient).imag
|
||||
vector.rotate(phase, about_point=ORIGIN)
|
||||
vector.freq = freq
|
||||
vector.phase = phase
|
||||
vector.coefficient = coefficient
|
||||
vector.center_func = center_func
|
||||
vector.add_updater(self.update_vector)
|
||||
@@ -103,12 +104,13 @@ class FourierCirclesScene(Scene):
|
||||
|
||||
def update_vector(self, vector, dt):
|
||||
time = self.get_vector_time()
|
||||
vector.set_angle(
|
||||
vector.phase + time * vector.freq * TAU
|
||||
)
|
||||
vector.shift(
|
||||
vector.center_func() - vector.get_start()
|
||||
)
|
||||
coef = vector.coefficient
|
||||
freq = vector.freq
|
||||
phase = np.log(coef).imag
|
||||
|
||||
vector.set_length(abs(coef))
|
||||
vector.set_angle(phase + time * freq * TAU)
|
||||
vector.shift(vector.center_func() - vector.get_start())
|
||||
return vector
|
||||
|
||||
def get_circles(self, vectors):
|
||||
@@ -155,14 +157,19 @@ class FourierCirclesScene(Scene):
|
||||
return path
|
||||
|
||||
# TODO, this should be a general animated mobect
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
def get_drawn_path_alpha(self):
|
||||
return self.get_vector_time()
|
||||
|
||||
def get_drawn_path(self, vectors, stroke_width=None, **kwargs):
|
||||
if stroke_width is None:
|
||||
stroke_width = self.drawn_path_stroke_width
|
||||
path = self.get_vector_sum_path(vectors, **kwargs)
|
||||
broken_path = CurvesAsSubmobjects(path)
|
||||
broken_path.curr_time = 0
|
||||
|
||||
def update_path(path, dt):
|
||||
# alpha = path.curr_time * self.get_slow_factor()
|
||||
alpha = self.get_vector_time()
|
||||
alpha = self.get_drawn_path_alpha()
|
||||
n_curves = len(path)
|
||||
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
||||
b = alpha - a
|
||||
@@ -174,7 +181,7 @@ class FourierCirclesScene(Scene):
|
||||
path.curr_time += dt
|
||||
return path
|
||||
|
||||
broken_path.set_color(YELLOW)
|
||||
broken_path.set_color(self.drawn_path_color)
|
||||
broken_path.add_updater(update_path)
|
||||
return broken_path
|
||||
|
||||
@@ -365,48 +372,74 @@ class FourierOfPiSymbol(FourierCirclesScene):
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfName(FourierOfPiSymbol):
|
||||
class FourierOfTexPaths(FourierOfPiSymbol, MovingCameraScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"name_color": WHITE,
|
||||
"name_text": "Abc",
|
||||
"animated_name": "Abc",
|
||||
"time_per_symbol": 5,
|
||||
"slow_factor": 1 / 5,
|
||||
"parametric_function_step_size": 0.01,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
name = TextMobject(self.name_text)
|
||||
name = TextMobject(self.animated_name)
|
||||
max_width = FRAME_WIDTH - 2
|
||||
max_height = FRAME_HEIGHT - 2
|
||||
name.set_width(max_width)
|
||||
if name.get_height() > max_height:
|
||||
name.set_height(max_height)
|
||||
|
||||
frame = self.camera.frame
|
||||
frame.save_state()
|
||||
|
||||
vectors = VGroup(VectorizedPoint())
|
||||
circles = VGroup(VectorizedPoint())
|
||||
for path in name.family_members_with_points():
|
||||
for subpath in path.get_subpaths():
|
||||
sp_mob = VMobject()
|
||||
sp_mob.set_points(subpath)
|
||||
coefs = self.get_coefficients_of_path(sp_mob)
|
||||
new_circles = self.get_circles(
|
||||
new_vectors = self.get_rotating_vectors(
|
||||
coefficients=coefs
|
||||
)
|
||||
new_circles = self.get_circles(new_vectors)
|
||||
self.set_decreasing_stroke_widths(new_circles)
|
||||
drawn_path = self.get_drawn_path(new_circles)
|
||||
|
||||
drawn_path = self.get_drawn_path(new_vectors)
|
||||
drawn_path.clear_updaters()
|
||||
drawn_path.set_stroke(self.name_color, 3)
|
||||
|
||||
new_circles.suspend_updating()
|
||||
self.play(ReplacementTransform(circles, new_circles))
|
||||
new_circles.resume_updating()
|
||||
circles = new_circles
|
||||
static_vectors = VMobject().become(new_vectors)
|
||||
static_circles = VMobject().become(new_circles)
|
||||
# static_circles = new_circles.deepcopy()
|
||||
# static_vectors.clear_updaters()
|
||||
# static_circles.clear_updaters()
|
||||
|
||||
self.play(
|
||||
Transform(vectors, static_vectors, remover=True),
|
||||
Transform(circles, static_circles, remover=True),
|
||||
frame.set_height, 1.5 * name.get_height(),
|
||||
frame.move_to, path,
|
||||
)
|
||||
|
||||
self.add(new_vectors, new_circles)
|
||||
self.vector_clock.set_value(0)
|
||||
self.play(
|
||||
ShowCreation(drawn_path),
|
||||
rate_func=linear,
|
||||
run_time=self.time_per_symbol
|
||||
)
|
||||
circles.suspend_updating()
|
||||
self.play(FadeOut(circles))
|
||||
self.remove(new_vectors, new_circles)
|
||||
self.add(static_vectors, static_circles)
|
||||
|
||||
vectors = static_vectors
|
||||
circles = static_circles
|
||||
self.play(
|
||||
FadeOut(vectors),
|
||||
Restore(frame),
|
||||
run_time=2
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.shared_constructs import *
|
||||
from active_projects.diffyq.part2.shared_constructs import *
|
||||
|
||||
|
||||
class TwoDBodyWithManyTemperatures(ThreeDScene):
|
||||
@@ -164,8 +164,12 @@ class BringTwoRodsTogether(Scene):
|
||||
"tick_frequency": 10,
|
||||
},
|
||||
},
|
||||
"y_labels": range(20, 100, 20),
|
||||
"graph_x_min": 0,
|
||||
"graph_x_max": 10,
|
||||
"midpoint": 5,
|
||||
"max_temp": 90,
|
||||
"min_temp": 10,
|
||||
"wait_time": 30,
|
||||
"default_n_rod_pieces": 20,
|
||||
"alpha": 1.0,
|
||||
@@ -187,9 +191,7 @@ class BringTwoRodsTogether(Scene):
|
||||
y_label.to_edge(UP)
|
||||
axes.y_axis.label = y_label
|
||||
axes.y_axis.add(y_label)
|
||||
axes.y_axis.add_numbers(
|
||||
*range(20, 100, 20)
|
||||
)
|
||||
axes.y_axis.add_numbers(*self.y_labels)
|
||||
|
||||
self.axes = axes
|
||||
self.y_label = y_label
|
||||
@@ -200,7 +202,7 @@ class BringTwoRodsTogether(Scene):
|
||||
x_min=self.graph_x_min,
|
||||
x_max=self.graph_x_max,
|
||||
step_size=self.step_size,
|
||||
discontinuities=[5],
|
||||
discontinuities=[self.midpoint],
|
||||
)
|
||||
graph.color_using_background_image("VerticalTempGradient")
|
||||
|
||||
@@ -315,20 +317,27 @@ class BringTwoRodsTogether(Scene):
|
||||
rods.add_updater(self.update_rods)
|
||||
|
||||
self.play(
|
||||
ClockPassesTime(
|
||||
self.clock,
|
||||
run_time=self.wait_time,
|
||||
hours_passed=self.wait_time,
|
||||
),
|
||||
self.get_clock_anim(self.wait_time),
|
||||
FadeOut(labels)
|
||||
)
|
||||
|
||||
#
|
||||
def get_clock_anim(self, time, **kwargs):
|
||||
config = {
|
||||
"run_time": time,
|
||||
"hours_passed": time,
|
||||
}
|
||||
config.update(kwargs)
|
||||
return ClockPassesTime(self.clock, **config)
|
||||
|
||||
def initial_function(self, x):
|
||||
if x <= 5:
|
||||
return 90
|
||||
epsilon = 1e-10
|
||||
if x < self.midpoint - epsilon:
|
||||
return self.max_temp
|
||||
elif x > self.midpoint + epsilon:
|
||||
return self.min_temp
|
||||
else:
|
||||
return 10
|
||||
return (self.min_temp + self.max_temp) / 2
|
||||
|
||||
def update_graph(self, graph, dt, alpha=None, n_mini_steps=500):
|
||||
if alpha is None:
|
||||
@@ -432,7 +441,10 @@ class BringTwoRodsTogether(Scene):
|
||||
)
|
||||
|
||||
def y_to_color(self, y):
|
||||
return temperature_to_color((y - 45) / 45)
|
||||
y_max = self.max_temp
|
||||
y_min = self.min_temp
|
||||
alpha = inverse_interpolate(y_min, y_max, y)
|
||||
return temperature_to_color(interpolate(-0.8, 0.8, alpha))
|
||||
|
||||
def rod_point_to_color(self, point):
|
||||
return self.y_to_color(
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
from active_projects.diffyq.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.staging import TourOfDifferentialEquations
|
||||
from active_projects.diffyq.part1.staging import TourOfDifferentialEquations
|
||||
|
||||
|
||||
class PartTwoOfTour(TourOfDifferentialEquations):
|
||||
@@ -210,7 +210,7 @@ class BlackScholes(AltBrownianMotion):
|
||||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject("Black-Sholes equations")
|
||||
title = TextMobject("Black-Scholes equations")
|
||||
title.scale(1.5)
|
||||
title.next_to(2 * UP, UP)
|
||||
|
||||
@@ -235,7 +235,7 @@ class BlackScholes(AltBrownianMotion):
|
||||
x_max=20,
|
||||
y_min=0,
|
||||
y_max=10,
|
||||
number_line_config={
|
||||
axis_config={
|
||||
"unit_size": 0.5,
|
||||
},
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
|
||||
|
||||
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class IveHeardOfThis(TeacherStudentsScene):
|
||||
@@ -1,6 +1,6 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
from active_projects.ode.part2.fourier_series import FourierOfTrebleClef
|
||||
from active_projects.diffyq.part2.fourier_series import FourierOfTrebleClef
|
||||
|
||||
|
||||
class FourierNameIntro(Scene):
|
||||
@@ -234,7 +234,7 @@ class FourierSeriesIllustraiton(Scene):
|
||||
CONFIG = {
|
||||
"n_range": range(1, 31, 2),
|
||||
"axes_config": {
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"include_tip": False,
|
||||
},
|
||||
"x_axis_config": {
|
||||
@@ -245,42 +245,20 @@ class FourierSeriesIllustraiton(Scene):
|
||||
"x_max": 1,
|
||||
"y_min": -1,
|
||||
"y_max": 1,
|
||||
}
|
||||
},
|
||||
"colors": [BLUE, GREEN, RED, YELLOW, PINK],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
n_range = self.n_range
|
||||
aaa_group = self.get_axes_arrow_axes()
|
||||
aaa_group.shift(2 * UP)
|
||||
aaa_group.shift_onto_screen()
|
||||
axes1, arrow, axes2 = aaa_group
|
||||
|
||||
axes1 = Axes(**self.axes_config)
|
||||
axes1.x_axis.add_numbers(
|
||||
0.5, 1,
|
||||
number_config={"num_decimal_places": 1}
|
||||
)
|
||||
axes2 = axes1.copy()
|
||||
target_func_graph = self.get_target_func_graph(axes2)
|
||||
axes2.add(target_func_graph)
|
||||
axes2.add(self.get_target_func_graph(axes2))
|
||||
|
||||
arrow = Arrow(LEFT, RIGHT, color=WHITE)
|
||||
group = VGroup(axes1, arrow, axes2)
|
||||
group.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
group.shift(2 * UP)
|
||||
group.shift_onto_screen()
|
||||
|
||||
sine_graphs = VGroup(*[
|
||||
axes1.get_graph(self.generate_nth_func(n))
|
||||
for n in n_range
|
||||
])
|
||||
sine_graphs.set_stroke(width=3)
|
||||
sine_graphs.set_color_by_gradient(
|
||||
BLUE, GREEN, RED, YELLOW, PINK,
|
||||
BLUE, GREEN, RED, YELLOW, PINK,
|
||||
)
|
||||
|
||||
partial_sums = VGroup(*[
|
||||
axes1.get_graph(self.generate_kth_partial_sum_func(k + 1))
|
||||
for k in range(len(n_range))
|
||||
])
|
||||
partial_sums.match_style(sine_graphs)
|
||||
sine_graphs = self.get_sine_graphs(axes1)
|
||||
partial_sums = self.get_partial_sums(axes1, sine_graphs)
|
||||
|
||||
sum_tex = self.get_sum_tex()
|
||||
sum_tex.next_to(axes1, DOWN, LARGE_BUFF)
|
||||
@@ -311,7 +289,6 @@ class FourierSeriesIllustraiton(Scene):
|
||||
)
|
||||
|
||||
self.add(axes1, arrow, axes2)
|
||||
self.add(target_func_graph)
|
||||
self.add(sum_tex, eq, target_func_tex)
|
||||
self.add(range_words)
|
||||
|
||||
@@ -340,6 +317,42 @@ class FourierSeriesIllustraiton(Scene):
|
||||
self.play(*anims2)
|
||||
curr_partial_sum = partial_sum
|
||||
|
||||
def get_axes_arrow_axes(self):
|
||||
axes1 = Axes(**self.axes_config)
|
||||
axes1.x_axis.add_numbers(
|
||||
0.5, 1,
|
||||
number_config={"num_decimal_places": 1}
|
||||
)
|
||||
axes1.y_axis.add_numbers(
|
||||
-1, 1,
|
||||
number_config={"num_decimal_places": 1},
|
||||
direction=LEFT,
|
||||
)
|
||||
axes2 = axes1.deepcopy()
|
||||
|
||||
arrow = Arrow(LEFT, RIGHT, color=WHITE)
|
||||
group = VGroup(axes1, arrow, axes2)
|
||||
group.arrange(RIGHT, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
def get_sine_graphs(self, axes):
|
||||
sine_graphs = VGroup(*[
|
||||
axes.get_graph(self.generate_nth_func(n))
|
||||
for n in self.n_range
|
||||
])
|
||||
sine_graphs.set_stroke(width=3)
|
||||
for graph, color in zip(sine_graphs, it.cycle(self.colors)):
|
||||
graph.set_color(color)
|
||||
return sine_graphs
|
||||
|
||||
def get_partial_sums(self, axes, sine_graphs):
|
||||
partial_sums = VGroup(*[
|
||||
axes.get_graph(self.generate_kth_partial_sum_func(k + 1))
|
||||
for k in range(len(self.n_range))
|
||||
])
|
||||
partial_sums.match_style(sine_graphs)
|
||||
return partial_sums
|
||||
|
||||
def get_sum_tex(self):
|
||||
return TexMobject(
|
||||
"\\frac{4}{\\pi} \\left(",
|
||||
@@ -1,7 +1,7 @@
|
||||
from scipy import integrate
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
|
||||
|
||||
class TemperatureGraphScene(SpecialThreeDScene):
|
||||
@@ -137,19 +137,19 @@ class TemperatureGraphScene(SpecialThreeDScene):
|
||||
|
||||
def get_surface(self, axes, func, **kwargs):
|
||||
config = {
|
||||
"u_min": axes.x_min,
|
||||
"u_max": axes.x_max,
|
||||
"v_min": axes.y_min,
|
||||
"v_max": axes.y_max,
|
||||
"u_min": axes.y_min,
|
||||
"u_max": axes.y_max,
|
||||
"v_min": axes.x_min,
|
||||
"v_max": axes.x_max,
|
||||
"resolution": (
|
||||
(axes.x_max - axes.x_min) // axes.x_axis.tick_frequency,
|
||||
(axes.y_max - axes.y_min) // axes.y_axis.tick_frequency,
|
||||
(axes.x_max - axes.x_min) // axes.x_axis.tick_frequency,
|
||||
),
|
||||
}
|
||||
config.update(self.default_surface_config)
|
||||
config.update(kwargs)
|
||||
return ParametricSurface(
|
||||
lambda x, t: axes.c2p(
|
||||
lambda t, x: axes.c2p(
|
||||
x, t, func(x, t)
|
||||
),
|
||||
**config
|
||||
@@ -181,13 +181,12 @@ class TemperatureGraphScene(SpecialThreeDScene):
|
||||
fill_color=WHITE,
|
||||
fill_opacity=0.2
|
||||
)
|
||||
plane.add_updater(lambda m: m.move_to(
|
||||
plane.add_updater(lambda m: m.shift(
|
||||
axes.c2p(
|
||||
axes.x_min,
|
||||
t_tracker.get_value(),
|
||||
axes.z_min,
|
||||
),
|
||||
IN + LEFT,
|
||||
) - plane.points[0]
|
||||
))
|
||||
plane.t_tracker = t_tracker
|
||||
return plane
|
||||
@@ -380,6 +379,10 @@ class BreakDownAFunction(SimpleCosExpGraph):
|
||||
"z_min": -2,
|
||||
"y_max": 20,
|
||||
},
|
||||
"low_axes_config": {
|
||||
"z_min": -3,
|
||||
"z_axis_config": {"unit_size": 1}
|
||||
},
|
||||
"n_low_axes": 4,
|
||||
"k": 0.2,
|
||||
}
|
||||
@@ -403,10 +406,7 @@ class BreakDownAFunction(SimpleCosExpGraph):
|
||||
top_axes.center()
|
||||
top_axes.to_edge(UP)
|
||||
|
||||
low_axes = self.get_three_d_axes(
|
||||
z_min=-3,
|
||||
z_axis_config={"unit_size": 1}
|
||||
)
|
||||
low_axes = self.get_three_d_axes(**self.low_axes_config)
|
||||
low_axes.y_axis.set_opacity(0)
|
||||
for axis in low_axes:
|
||||
axis.label.fade(1)
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class ThreeMainObservations(Scene):
|
||||
712
from_3b1b/active/diffyq/part4/complex_functions.py
Normal file
712
from_3b1b/active/diffyq/part4/complex_functions.py
Normal file
@@ -0,0 +1,712 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class GeneralizeToComplexFunctions(Scene):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_min": 0,
|
||||
"x_max": 10,
|
||||
"x_axis_config": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_min": -2.5,
|
||||
"y_max": 2.5,
|
||||
"y_axis_config": {
|
||||
"tick_frequency": 0.25,
|
||||
"unit_size": 1.5,
|
||||
"include_tip": False,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
},
|
||||
"complex_plane_config": {
|
||||
"axis_config": {
|
||||
"unit_size": 2
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_cosine_wave()
|
||||
self.transition_to_complex_plane()
|
||||
self.add_rotating_vectors_making_cos()
|
||||
|
||||
def show_cosine_wave(self):
|
||||
axes = Axes(**self.axes_config)
|
||||
axes.shift(2 * LEFT - axes.c2p(0, 0))
|
||||
y_axis = axes.y_axis
|
||||
y_labels = y_axis.get_number_mobjects(
|
||||
*range(-2, 3),
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
|
||||
t_tracker = ValueTracker(0)
|
||||
t_tracker.add_updater(lambda t, dt: t.increment_value(dt))
|
||||
get_t = t_tracker.get_value
|
||||
|
||||
def func(x):
|
||||
return 2 * np.cos(x)
|
||||
|
||||
cos_x_max = 20
|
||||
cos_wave = axes.get_graph(func, x_max=cos_x_max)
|
||||
cos_wave.set_color(YELLOW)
|
||||
shown_cos_wave = cos_wave.copy()
|
||||
shown_cos_wave.add_updater(
|
||||
lambda m: m.pointwise_become_partial(
|
||||
cos_wave, 0,
|
||||
np.clip(get_t() / cos_x_max, 0, 1),
|
||||
),
|
||||
)
|
||||
|
||||
dot = Dot()
|
||||
dot.set_color(PINK)
|
||||
dot.add_updater(lambda d: d.move_to(
|
||||
y_axis.n2p(func(get_t())),
|
||||
))
|
||||
|
||||
h_line = always_redraw(lambda: Line(
|
||||
dot.get_right(),
|
||||
shown_cos_wave.get_end(),
|
||||
stroke_width=1,
|
||||
))
|
||||
|
||||
real_words = TextMobject(
|
||||
"Real number\\\\output"
|
||||
)
|
||||
real_words.to_edge(LEFT)
|
||||
real_words.shift(2 * UP)
|
||||
real_arrow = Arrow()
|
||||
real_arrow.add_updater(
|
||||
lambda m: m.put_start_and_end_on(
|
||||
real_words.get_corner(DR),
|
||||
dot.get_center(),
|
||||
).scale(0.9),
|
||||
)
|
||||
|
||||
self.add(t_tracker)
|
||||
self.add(axes)
|
||||
self.add(y_labels)
|
||||
self.add(shown_cos_wave)
|
||||
self.add(dot)
|
||||
self.add(h_line)
|
||||
|
||||
self.wait(2)
|
||||
self.play(
|
||||
FadeInFrom(real_words, RIGHT),
|
||||
FadeIn(real_arrow),
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
y_axis.generate_target()
|
||||
y_axis.target.rotate(-90 * DEGREES)
|
||||
y_axis.target.center()
|
||||
y_axis.target.scale(2 / 1.5)
|
||||
y_labels.generate_target()
|
||||
for label in y_labels.target:
|
||||
label.next_to(
|
||||
y_axis.target.n2p(label.get_value()),
|
||||
DOWN, MED_SMALL_BUFF,
|
||||
)
|
||||
self.play(
|
||||
FadeOut(shown_cos_wave),
|
||||
FadeOut(axes.x_axis),
|
||||
FadeOut(h_line),
|
||||
)
|
||||
self.play(
|
||||
MoveToTarget(y_axis),
|
||||
MoveToTarget(y_labels),
|
||||
real_words.shift, 2 * RIGHT + UP,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.y_axis = y_axis
|
||||
self.y_labels = y_labels
|
||||
self.real_words = real_words
|
||||
self.real_arrow = real_arrow
|
||||
self.dot = dot
|
||||
self.t_tracker = t_tracker
|
||||
|
||||
def transition_to_complex_plane(self):
|
||||
y_axis = self.y_axis
|
||||
y_labels = self.y_labels
|
||||
|
||||
plane = self.get_complex_plane()
|
||||
plane_words = plane.label
|
||||
|
||||
self.add(plane, *self.get_mobjects())
|
||||
self.play(
|
||||
FadeOut(y_labels),
|
||||
FadeOut(y_axis),
|
||||
ShowCreation(plane),
|
||||
)
|
||||
self.play(Write(plane_words))
|
||||
self.wait()
|
||||
|
||||
self.plane = plane
|
||||
self.plane_words = plane_words
|
||||
|
||||
def add_rotating_vectors_making_cos(self):
|
||||
plane = self.plane
|
||||
real_words = self.real_words
|
||||
real_arrow = self.real_arrow
|
||||
t_tracker = self.t_tracker
|
||||
get_t = t_tracker.get_value
|
||||
|
||||
v1 = Vector(2 * RIGHT)
|
||||
v2 = Vector(2 * RIGHT)
|
||||
v1.set_color(BLUE)
|
||||
v2.set_color(interpolate_color(GREY_BROWN, WHITE, 0.5))
|
||||
v1.add_updater(
|
||||
lambda v: v.set_angle(get_t())
|
||||
)
|
||||
v2.add_updater(
|
||||
lambda v: v.set_angle(-get_t())
|
||||
)
|
||||
v1.add_updater(
|
||||
lambda v: v.shift(plane.n2p(0) - v.get_start())
|
||||
)
|
||||
# Change?
|
||||
v2.add_updater(
|
||||
lambda v: v.shift(plane.n2p(0) - v.get_start())
|
||||
)
|
||||
|
||||
ghost_v1 = v1.copy()
|
||||
ghost_v1.set_opacity(0.5)
|
||||
ghost_v1.add_updater(
|
||||
lambda v: v.shift(
|
||||
v2.get_end() - v.get_start()
|
||||
)
|
||||
)
|
||||
|
||||
ghost_v2 = v2.copy()
|
||||
ghost_v2.set_opacity(0.5)
|
||||
ghost_v2.add_updater(
|
||||
lambda v: v.shift(
|
||||
v1.get_end() - v.get_start()
|
||||
)
|
||||
)
|
||||
|
||||
circle = Circle(color=GREY_BROWN)
|
||||
circle.set_stroke(width=1)
|
||||
circle.set_width(2 * v1.get_length())
|
||||
circle.move_to(plane.n2p(0))
|
||||
|
||||
formula = TexMobject(
|
||||
# "\\cos(x) ="
|
||||
# "{1 \\over 2}e^{ix} +"
|
||||
# "{1 \\over 2}e^{-ix}",
|
||||
"2\\cos(x) =",
|
||||
"e^{ix}", "+", "e^{-ix}",
|
||||
tex_to_color_map={
|
||||
"e^{ix}": v1.get_color(),
|
||||
"e^{-ix}": v2.get_color(),
|
||||
}
|
||||
)
|
||||
formula.next_to(ORIGIN, UP, buff=0.75)
|
||||
# formula.add_background_rectangle()
|
||||
formula.set_stroke(BLACK, 3, background=True)
|
||||
formula.to_edge(LEFT, buff=MED_SMALL_BUFF)
|
||||
formula_brace = Brace(formula[1:], UP)
|
||||
formula_words = formula_brace.get_text(
|
||||
"Sum of\\\\rotations"
|
||||
)
|
||||
formula_words.set_stroke(BLACK, 3, background=True)
|
||||
|
||||
randy = Randolph()
|
||||
randy.to_corner(DL)
|
||||
randy.look_at(formula)
|
||||
|
||||
self.play(
|
||||
FadeOut(real_words),
|
||||
FadeOut(real_arrow),
|
||||
)
|
||||
self.play(
|
||||
FadeIn(v1),
|
||||
FadeIn(v2),
|
||||
FadeIn(circle),
|
||||
FadeIn(ghost_v1),
|
||||
FadeIn(ghost_v2),
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeInFromDown(formula))
|
||||
self.play(
|
||||
GrowFromCenter(formula_brace),
|
||||
FadeIn(formula_words),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(FadeIn(randy))
|
||||
self.play(randy.change, "pleading")
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
self.play(randy.change, "confused")
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
self.play(FadeOut(randy))
|
||||
self.wait(20)
|
||||
|
||||
#
|
||||
def get_complex_plane(self):
|
||||
plane = ComplexPlane(**self.complex_plane_config)
|
||||
plane.add_coordinates()
|
||||
|
||||
plane.label = TextMobject("Complex plane")
|
||||
plane.label.scale(1.5)
|
||||
plane.label.to_corner(UR, buff=MED_SMALL_BUFF)
|
||||
return plane
|
||||
|
||||
|
||||
class ClarifyInputAndOutput(GeneralizeToComplexFunctions):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"stroke_color": WHITE,
|
||||
"stroke_width": 1,
|
||||
"fill_color": DARKER_GREY,
|
||||
"fill_opacity": 1,
|
||||
"width": 6,
|
||||
"height": 2,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
|
||||
self.describe_input()
|
||||
self.describe_output()
|
||||
|
||||
def setup_plane(self):
|
||||
plane = self.get_complex_plane()
|
||||
plane.sublabel = TextMobject("(Output space)")
|
||||
plane.sublabel.add_background_rectangle()
|
||||
plane.sublabel.next_to(plane.label, DOWN)
|
||||
self.add(plane, plane.label)
|
||||
self.plane = plane
|
||||
|
||||
def setup_input_space(self):
|
||||
rect = Rectangle(**self.input_space_rect_config)
|
||||
rect.to_corner(UL, buff=SMALL_BUFF)
|
||||
|
||||
input_line = self.get_input_line(rect)
|
||||
input_words = TextMobject("Input space")
|
||||
input_words.next_to(
|
||||
rect.get_bottom(), UP,
|
||||
SMALL_BUFF,
|
||||
)
|
||||
|
||||
self.add(rect)
|
||||
self.add(input_line)
|
||||
|
||||
self.input_rect = rect
|
||||
self.input_line = input_line
|
||||
self.input_words = input_words
|
||||
|
||||
def setup_input_trackers(self):
|
||||
plane = self.plane
|
||||
input_line = self.input_line
|
||||
input_tracker = ValueTracker(0)
|
||||
get_input = input_tracker.get_value
|
||||
|
||||
input_dot = Dot()
|
||||
input_dot.set_color(PINK)
|
||||
f_always(
|
||||
input_dot.move_to,
|
||||
lambda: input_line.n2p(get_input())
|
||||
)
|
||||
|
||||
input_decimal = DecimalNumber()
|
||||
input_decimal.scale(0.7)
|
||||
always(input_decimal.next_to, input_dot, UP)
|
||||
f_always(input_decimal.set_value, get_input)
|
||||
|
||||
path = self.get_path()
|
||||
|
||||
def get_output_point():
|
||||
return path.point_from_proportion(
|
||||
get_input()
|
||||
)
|
||||
|
||||
output_dot = Dot()
|
||||
output_dot.match_style(input_dot)
|
||||
f_always(output_dot.move_to, get_output_point)
|
||||
|
||||
output_vector = Vector()
|
||||
output_vector.set_color(WHITE)
|
||||
output_vector.add_updater(
|
||||
lambda v: v.put_start_and_end_on(
|
||||
plane.n2p(0),
|
||||
get_output_point()
|
||||
)
|
||||
)
|
||||
|
||||
output_decimal = DecimalNumber()
|
||||
output_decimal.scale(0.7)
|
||||
always(output_decimal.next_to, output_dot, UR, SMALL_BUFF)
|
||||
f_always(
|
||||
output_decimal.set_value,
|
||||
lambda: plane.p2n(get_output_point()),
|
||||
)
|
||||
|
||||
self.input_tracker = input_tracker
|
||||
self.input_dot = input_dot
|
||||
self.input_decimal = input_decimal
|
||||
self.path = path
|
||||
self.output_dot = output_dot
|
||||
self.output_vector = output_vector
|
||||
self.output_decimal = output_decimal
|
||||
|
||||
def describe_input(self):
|
||||
input_tracker = self.input_tracker
|
||||
|
||||
self.play(FadeInFrom(self.input_words, UP))
|
||||
self.play(
|
||||
FadeInFromLarge(self.input_dot),
|
||||
FadeIn(self.input_decimal),
|
||||
)
|
||||
for value in 1, 0:
|
||||
self.play(
|
||||
input_tracker.set_value, value,
|
||||
run_time=2
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def describe_output(self):
|
||||
path = self.path
|
||||
output_dot = self.output_dot
|
||||
output_decimal = self.output_decimal
|
||||
input_dot = self.input_dot
|
||||
input_tracker = self.input_tracker
|
||||
plane = self.plane
|
||||
real_line = plane.x_axis.copy()
|
||||
real_line.set_stroke(RED, 4)
|
||||
real_words = TextMobject("Real number line")
|
||||
real_words.next_to(ORIGIN, UP)
|
||||
real_words.to_edge(RIGHT)
|
||||
|
||||
traced_path = TracedPath(output_dot.get_center)
|
||||
traced_path.match_style(path)
|
||||
|
||||
self.play(
|
||||
ShowCreation(real_line),
|
||||
FadeInFrom(real_words, DOWN)
|
||||
)
|
||||
self.play(
|
||||
FadeOut(real_line),
|
||||
FadeOut(real_words),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(plane.sublabel, UP)
|
||||
)
|
||||
self.play(
|
||||
FadeIn(output_decimal),
|
||||
TransformFromCopy(input_dot, output_dot),
|
||||
)
|
||||
|
||||
kw = {
|
||||
"run_time": 10,
|
||||
"rate_func": lambda t: smooth(t, 1),
|
||||
}
|
||||
self.play(
|
||||
ApplyMethod(input_tracker.set_value, 1, **kw),
|
||||
ShowCreation(path.copy(), remover=True, **kw),
|
||||
)
|
||||
self.add(path)
|
||||
self.add(output_dot)
|
||||
self.wait()
|
||||
|
||||
# Flatten to 1d
|
||||
real_function_word = TextMobject(
|
||||
"Real-valued function"
|
||||
)
|
||||
real_function_word.next_to(ORIGIN, DOWN, MED_LARGE_BUFF)
|
||||
path.generate_target()
|
||||
path.target.stretch(0, 1)
|
||||
path.target.move_to(plane.n2p(0))
|
||||
|
||||
self.play(
|
||||
FadeIn(real_function_word),
|
||||
MoveToTarget(path),
|
||||
)
|
||||
input_tracker.set_value(0)
|
||||
self.play(
|
||||
input_tracker.set_value, 1,
|
||||
**kw
|
||||
)
|
||||
|
||||
#
|
||||
def get_input_line(self, input_rect):
|
||||
input_line = UnitInterval()
|
||||
input_line.move_to(input_rect)
|
||||
input_line.shift(0.25 * UP)
|
||||
input_line.set_width(
|
||||
input_rect.get_width() - 1
|
||||
)
|
||||
input_line.add_numbers(0, 0.5, 1)
|
||||
return input_line
|
||||
|
||||
def get_path(self):
|
||||
# mob = SVGMobject("BatmanLogo")
|
||||
mob = TexMobject("\\pi")
|
||||
path = mob.family_members_with_points()[0]
|
||||
path.set_height(3.5)
|
||||
path.move_to(2 * DOWN, DOWN)
|
||||
path.set_stroke(YELLOW, 2)
|
||||
path.set_fill(opacity=0)
|
||||
return path
|
||||
|
||||
|
||||
class GraphForFlattenedPi(ClarifyInputAndOutput):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
plane = self.plane
|
||||
self.remove(plane, plane.label)
|
||||
|
||||
path = self.get_path()
|
||||
|
||||
axes = Axes(
|
||||
x_min=0,
|
||||
x_max=1,
|
||||
x_axis_config={
|
||||
"unit_size": 7,
|
||||
"include_tip": False,
|
||||
"tick_frequency": 0.1,
|
||||
},
|
||||
y_min=-1.5,
|
||||
y_max=1.5,
|
||||
y_axis_config={
|
||||
"include_tip": False,
|
||||
"unit_size": 2.5,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
)
|
||||
axes.set_width(FRAME_WIDTH - 1)
|
||||
axes.set_height(FRAME_HEIGHT - 1, stretch=True)
|
||||
axes.center()
|
||||
|
||||
axes.x_axis.add_numbers(
|
||||
0.5, 1.0,
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
axes.y_axis.add_numbers(
|
||||
-1.0, 1.0,
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
|
||||
def func(t):
|
||||
return plane.x_axis.p2n(
|
||||
path.point_from_proportion(t)
|
||||
)
|
||||
|
||||
graph = axes.get_graph(func)
|
||||
graph.set_color(PINK)
|
||||
|
||||
v_line = always_redraw(lambda: Line(
|
||||
axes.x_axis.n2p(axes.x_axis.p2n(graph.get_end())),
|
||||
graph.get_end(),
|
||||
stroke_width=1,
|
||||
))
|
||||
|
||||
self.add(axes)
|
||||
self.add(v_line)
|
||||
|
||||
kw = {
|
||||
"run_time": 10,
|
||||
"rate_func": lambda t: smooth(t, 1),
|
||||
}
|
||||
self.play(ShowCreation(graph, **kw))
|
||||
self.wait()
|
||||
|
||||
|
||||
class SimpleComplexExponentExample(ClarifyInputAndOutput):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"width": 14,
|
||||
"height": 1.5,
|
||||
},
|
||||
"input_line_config": {
|
||||
"unit_size": 0.5,
|
||||
"x_min": 0,
|
||||
"x_max": 25,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"input_numbers": range(0, 30, 5),
|
||||
"input_tex_args": ["t", "="],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
self.setup_output_trackers()
|
||||
|
||||
# Testing
|
||||
time = self.input_line.x_max
|
||||
self.play(
|
||||
self.input_tracker.set_value, time,
|
||||
run_time=time,
|
||||
rate_func=linear,
|
||||
)
|
||||
|
||||
def setup_plane(self):
|
||||
plane = ComplexPlane()
|
||||
plane.scale(2)
|
||||
plane.add_coordinates()
|
||||
plane.shift(DOWN)
|
||||
self.plane = plane
|
||||
self.add(plane)
|
||||
|
||||
def setup_input_trackers(self):
|
||||
input_line = self.input_line
|
||||
input_tracker = ValueTracker(0)
|
||||
get_input = input_tracker.get_value
|
||||
|
||||
input_tip = ArrowTip(start_angle=-TAU / 4)
|
||||
input_tip.scale(0.5)
|
||||
input_tip.set_color(PINK)
|
||||
f_always(
|
||||
input_tip.move_to,
|
||||
lambda: input_line.n2p(get_input()),
|
||||
lambda: DOWN,
|
||||
)
|
||||
|
||||
input_label = VGroup(
|
||||
TexMobject(*self.input_tex_args),
|
||||
DecimalNumber(),
|
||||
)
|
||||
input_label[0].set_color_by_tex("t", PINK)
|
||||
input_label.scale(0.7)
|
||||
input_label.add_updater(
|
||||
lambda m: m.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
)
|
||||
input_label.add_updater(
|
||||
lambda m: m[1].set_value(get_input())
|
||||
)
|
||||
input_label.add_updater(
|
||||
lambda m: m.next_to(input_tip, UP, SMALL_BUFF)
|
||||
)
|
||||
|
||||
self.input_tracker = input_tracker
|
||||
self.input_tip = input_tip
|
||||
self.input_label = input_label
|
||||
|
||||
self.add(input_tip, input_label)
|
||||
|
||||
def setup_output_trackers(self):
|
||||
plane = self.plane
|
||||
get_input = self.input_tracker.get_value
|
||||
|
||||
def get_output():
|
||||
return np.exp(complex(0, get_input()))
|
||||
|
||||
def get_output_point():
|
||||
return plane.n2p(get_output())
|
||||
|
||||
output_label, static_output_label = [
|
||||
TexMobject(
|
||||
"e^{i t}" + s,
|
||||
tex_to_color_map={"t": PINK},
|
||||
background_stroke_width=3,
|
||||
)
|
||||
for s in ["", "\\approx"]
|
||||
]
|
||||
output_label.scale(1.2)
|
||||
output_label.add_updater(
|
||||
lambda m: m.shift(
|
||||
-m.get_bottom() +
|
||||
get_output_point() +
|
||||
rotate_vector(
|
||||
0.35 * RIGHT,
|
||||
get_input(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
output_vector = Vector()
|
||||
output_vector.set_opacity(0.75)
|
||||
output_vector.add_updater(
|
||||
lambda m: m.put_start_and_end_on(
|
||||
plane.n2p(0), get_output_point(),
|
||||
)
|
||||
)
|
||||
|
||||
t_max = 40
|
||||
full_output_path = ParametricFunction(
|
||||
lambda t: plane.n2p(np.exp(complex(0, t))),
|
||||
t_min=0,
|
||||
t_max=t_max
|
||||
)
|
||||
output_path = VMobject()
|
||||
output_path.set_stroke(YELLOW, 2)
|
||||
output_path.add_updater(
|
||||
lambda m: m.pointwise_become_partial(
|
||||
full_output_path,
|
||||
0, get_input() / t_max,
|
||||
)
|
||||
)
|
||||
|
||||
static_output_label.next_to(plane.c2p(1, 1), UR)
|
||||
output_decimal = DecimalNumber(
|
||||
include_sign=True,
|
||||
)
|
||||
output_decimal.scale(0.8)
|
||||
output_decimal.set_stroke(BLACK, 3, background=True)
|
||||
output_decimal.add_updater(
|
||||
lambda m: m.set_value(get_output())
|
||||
)
|
||||
output_decimal.add_updater(
|
||||
lambda m: m.next_to(
|
||||
static_output_label,
|
||||
RIGHT, 2 * SMALL_BUFF,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
)
|
||||
|
||||
self.add(output_path)
|
||||
self.add(output_vector)
|
||||
self.add(output_label)
|
||||
self.add(static_output_label)
|
||||
self.add(BackgroundRectangle(output_decimal))
|
||||
self.add(output_decimal)
|
||||
|
||||
#
|
||||
def get_input_line(self, input_rect):
|
||||
input_line = NumberLine(**self.input_line_config)
|
||||
input_line.move_to(input_rect)
|
||||
input_line.set_width(
|
||||
input_rect.get_width() - 1.5,
|
||||
stretch=True,
|
||||
)
|
||||
input_line.add_numbers(*self.input_numbers)
|
||||
return input_line
|
||||
|
||||
|
||||
class TRangingFrom0To1(SimpleComplexExponentExample):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"width": 6,
|
||||
"height": 2,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
|
||||
self.play(
|
||||
self.input_tracker.set_value, 1,
|
||||
run_time=10,
|
||||
rate_func=linear
|
||||
)
|
||||
|
||||
def get_input_line(self, rect):
|
||||
result = ClarifyInputAndOutput.get_input_line(self, rect)
|
||||
result.stretch(0.9, 0)
|
||||
result.set_stroke(width=2)
|
||||
for sm in result.get_family():
|
||||
if isinstance(sm, DecimalNumber):
|
||||
sm.stretch(1 / 0.9, 0)
|
||||
sm.set_stroke(width=0)
|
||||
return result
|
||||
1893
from_3b1b/active/diffyq/part4/fourier_series_scenes.py
Normal file
1893
from_3b1b/active/diffyq/part4/fourier_series_scenes.py
Normal file
File diff suppressed because it is too large
Load Diff
242
from_3b1b/active/diffyq/part4/long_fourier_scenes.py
Normal file
242
from_3b1b/active/diffyq/part4/long_fourier_scenes.py
Normal file
@@ -0,0 +1,242 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
from active_projects.diffyq.part4.fourier_series_scenes import ComplexFourierSeriesExample
|
||||
from manimlib.once_useful_constructs.fractals import HilbertCurve
|
||||
|
||||
|
||||
class FourierSeriesExampleWithRectForZoom(ComplexFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"slow_factor": 0.01,
|
||||
"rect_scale_factor": 0.1,
|
||||
"start_drawn": True,
|
||||
"drawing_height": 7,
|
||||
"rect_stroke_width": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.circles.set_stroke(opacity=0.5)
|
||||
rect = self.rect = self.get_rect()
|
||||
rect.set_height(self.rect_scale_factor * FRAME_HEIGHT)
|
||||
rect.add_updater(lambda m: m.move_to(
|
||||
self.get_rect_center()
|
||||
))
|
||||
self.add(rect)
|
||||
self.run_one_cycle()
|
||||
|
||||
def get_rect_center(self):
|
||||
return center_of_mass([
|
||||
v.get_end()
|
||||
for v in self.vectors
|
||||
])
|
||||
|
||||
def get_rect(self):
|
||||
return ScreenRectangle(
|
||||
color=BLUE,
|
||||
stroke_width=self.rect_stroke_width,
|
||||
)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample(FourierSeriesExampleWithRectForZoom, MovingCameraScene):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15,
|
||||
"tip_length": 0.05,
|
||||
},
|
||||
"parametric_function_step_size": 0.001,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
ComplexFourierSeriesExample.setup(self)
|
||||
MovingCameraScene.setup(self)
|
||||
|
||||
def get_rect(self):
|
||||
return self.camera_frame
|
||||
|
||||
def add_vectors_circles_path(self):
|
||||
super().add_vectors_circles_path()
|
||||
for v in self.vectors:
|
||||
if v.get_stroke_width() < 1:
|
||||
v.set_stroke(width=1)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample100x(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15 * 0.4,
|
||||
"tip_length": 0.05 * 0.2,
|
||||
"max_stroke_width_to_length_ratio": 80,
|
||||
"stroke_width": 3,
|
||||
},
|
||||
"max_circle_stroke_width": 0.5,
|
||||
"rect_scale_factor": 0.01,
|
||||
# "parametric_function_step_size": 0.01,
|
||||
}
|
||||
|
||||
def get_rect_center(self):
|
||||
return self.vectors[-1].get_end()
|
||||
|
||||
# def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
# return self.get_path_end(vectors, stroke_width, **kwargs)
|
||||
|
||||
|
||||
class TrebleClefFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "TrebleClef",
|
||||
"drawn_path_stroke_width": 10,
|
||||
}
|
||||
|
||||
|
||||
class TrebleClefZoomedInFourierSeriesExample(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "TrebleClef",
|
||||
}
|
||||
|
||||
|
||||
class NailAndGearFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "Nail_And_Gear",
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": "#39FF14",
|
||||
}
|
||||
|
||||
|
||||
class NailAndGearZoomedInFourierSeriesExample(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "Nail_And_Gear",
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": "#39FF14",
|
||||
}
|
||||
|
||||
|
||||
class SigmaFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": PINK,
|
||||
"rect_stroke_width": 0,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
return TexMobject("\\Sigma")
|
||||
|
||||
|
||||
class SigmaZoomedInFourierSeriesExample(SigmaFourierSeriesExampleWithRectForZoom, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfFourier(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"n_vectors": 300,
|
||||
"rect_stroke_width": 1,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfFourierZoomedIn(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"max_circle_stroke_width": 0.3,
|
||||
"n_vectors": 300,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfFourier100xZoom(ZoomedInFourierSeriesExample100x):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"max_circle_stroke_width": 0.3,
|
||||
"n_vectors": 300,
|
||||
"slow_factor": 0.001,
|
||||
}
|
||||
|
||||
def run_one_cycle(self):
|
||||
self.vector_clock.set_value(0.3)
|
||||
self.wait(40)
|
||||
|
||||
|
||||
class FourierOfHilbert(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"n_vectors": 300,
|
||||
"rect_stroke_width": 1,
|
||||
"drawn_path_stroke_width": 4,
|
||||
"drawn_path_color": BLUE,
|
||||
}
|
||||
|
||||
def get_path(self):
|
||||
path = HilbertCurve(order=5)
|
||||
path.set_height(self.drawing_height)
|
||||
path.to_edge(DOWN)
|
||||
combined_path = VMobject()
|
||||
for sm in path.family_members_with_points():
|
||||
combined_path.append_vectorized_mobject(sm)
|
||||
start = combined_path.get_start()
|
||||
end = combined_path.get_end()
|
||||
points = [
|
||||
interpolate(end, start, alpha)
|
||||
for alpha in np.linspace(0, 1, 10)
|
||||
]
|
||||
for point in points:
|
||||
combined_path.add_line_to(point)
|
||||
|
||||
combined_path.set_stroke(width=0)
|
||||
return combined_path
|
||||
|
||||
|
||||
class FourierOfHilbertZoomedIn(FourierOfHilbert, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfBritain(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "Britain",
|
||||
"n_vectors": 500,
|
||||
"drawn_path_color": RED,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfBritainZoomedIn(FourierOfBritain, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfSeattle(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "SeattleSkyline",
|
||||
"drawing_height": 7,
|
||||
"n_vectors": 400,
|
||||
"drawn_path_color": TEAL,
|
||||
"drawn_path_stroke_width": 5,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfSeattleZoomedIn(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "SeattleSkyline",
|
||||
"drawing_height": 7,
|
||||
"n_vectors": 400,
|
||||
"drawn_path_color": TEAL,
|
||||
"drawn_path_stroke_width": 5,
|
||||
"max_circle_stroke_width": 0.3,
|
||||
}
|
||||
|
||||
|
||||
class VideoWrapper(Scene):
|
||||
def construct(self):
|
||||
fade_rect = FullScreenFadeRectangle()
|
||||
fade_rect.set_fill(DARK_GREY, 1)
|
||||
screen_rect = ScreenRectangle()
|
||||
screen_rect.set_height(4)
|
||||
screen_rect.set_fill(BLACK, 1)
|
||||
screen_rect.set_stroke(width=0)
|
||||
|
||||
boundary = AnimatedBoundary(screen_rect)
|
||||
|
||||
title = TextMobject("Learn the math")
|
||||
title.scale(1.5)
|
||||
title.next_to(screen_rect, UP)
|
||||
|
||||
self.add(fade_rect)
|
||||
self.add(screen_rect)
|
||||
self.add(boundary)
|
||||
|
||||
self.play(FadeInFromDown(title))
|
||||
self.wait(19)
|
||||
235
from_3b1b/active/diffyq/part4/pi_creature_scenes.py
Normal file
235
from_3b1b/active/diffyq/part4/pi_creature_scenes.py
Normal file
@@ -0,0 +1,235 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WhyWouldYouCare(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Who cares!",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
added_anims=[self.teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[2]),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(
|
||||
"pondering", "erm", "thinking",
|
||||
look_at_arg=self.screen,
|
||||
)
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class SolveForWavesNothingElse(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Sure, we can\\\\solve it for\\\\sums of waves...",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.change_student_modes("pondering", "pondering", "sassy")
|
||||
self.look_at(self.screen)
|
||||
self.wait(4)
|
||||
self.student_says(
|
||||
"But nothing else!",
|
||||
target_mode="angry",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"concerned_musician",
|
||||
"concerned_musician",
|
||||
"angry",
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class HangOnThere(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
student = self.students[2]
|
||||
|
||||
axes1 = Axes(
|
||||
x_min=0,
|
||||
x_max=1,
|
||||
y_min=-1.5,
|
||||
y_max=1.5,
|
||||
x_axis_config={
|
||||
"tick_frequency": 0.25,
|
||||
"include_tip": False,
|
||||
"unit_size": 3,
|
||||
},
|
||||
y_axis_config={
|
||||
"tick_frequency": 0.5,
|
||||
"include_tip": False,
|
||||
},
|
||||
)
|
||||
axes1.set_stroke(width=2)
|
||||
axes2 = axes1.deepcopy()
|
||||
neq = TexMobject("\\neq")
|
||||
neq.scale(2)
|
||||
|
||||
group = VGroup(axes1, neq, axes2)
|
||||
group.arrange(RIGHT)
|
||||
group.set_height(4)
|
||||
group.next_to(
|
||||
student.get_corner(UL), UP,
|
||||
buff=LARGE_BUFF,
|
||||
)
|
||||
|
||||
step_graph = axes1.get_graph(
|
||||
lambda x: (1 if x < 0.5 else -1),
|
||||
discontinuities=[0.5],
|
||||
)
|
||||
step_graph.set_color(YELLOW)
|
||||
wave_graphs = VGroup(*[
|
||||
axes2.get_graph(
|
||||
lambda x: (4 / PI) * np.sum([
|
||||
(u / n) * np.cos(n * PI * x)
|
||||
for u, n in zip(
|
||||
it.cycle([1, -1]),
|
||||
range(1, max_n, 2),
|
||||
)
|
||||
]),
|
||||
)
|
||||
for max_n in range(3, 103, 2)
|
||||
])
|
||||
wave_graphs.set_stroke(width=3)
|
||||
wave_graphs.set_color_by_gradient(WHITE, PINK)
|
||||
last_wave_graph = wave_graphs[-1]
|
||||
last_wave_graph.set_stroke(PINK, 2)
|
||||
wave_graphs.remove(last_wave_graph)
|
||||
# wave_graphs[-1].set_stroke(width=3)
|
||||
# wave_graphs[-1].set_stroke(BLACK, 5, background=True)
|
||||
group.add(step_graph)
|
||||
|
||||
self.student_says(
|
||||
"Hang on\\\\hang on\\\\hang on...",
|
||||
target_mode="surprised",
|
||||
content_introduction_class=FadeIn,
|
||||
student_index=2,
|
||||
added_anims=[
|
||||
self.teacher.change, "guilty"
|
||||
],
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
RemovePiCreatureBubble(
|
||||
student,
|
||||
target_mode="raise_left_hand",
|
||||
look_at_arg=group,
|
||||
),
|
||||
FadeInFromDown(group),
|
||||
)
|
||||
|
||||
last_wg = VectorizedPoint()
|
||||
n_first_fades = 4
|
||||
for wg in wave_graphs[:n_first_fades]:
|
||||
self.play(
|
||||
last_wg.set_stroke, {"width": 0.1},
|
||||
FadeIn(wg),
|
||||
)
|
||||
last_wg = wg
|
||||
self.play(
|
||||
LaggedStart(
|
||||
*[
|
||||
UpdateFromAlphaFunc(
|
||||
wg,
|
||||
lambda m, a: m.set_stroke(
|
||||
width=(3 * there_and_back(a) + 0.1 * a)
|
||||
),
|
||||
)
|
||||
for wg in wave_graphs[n_first_fades:]
|
||||
],
|
||||
run_time=5,
|
||||
lag_ratio=0.2,
|
||||
),
|
||||
ApplyMethod(
|
||||
last_wg.set_stroke, {"width": 0.1},
|
||||
run_time=0.25,
|
||||
),
|
||||
FadeIn(
|
||||
last_wave_graph,
|
||||
rate_func=squish_rate_func(smooth, 0.9, 1),
|
||||
run_time=5,
|
||||
),
|
||||
self.teacher.change, "thinking",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "confused", "angry"
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class YouSaidThisWasEasier(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.change_all_student_modes(
|
||||
"confused", look_at_arg=self.screen,
|
||||
)
|
||||
self.student_says(
|
||||
"I'm sorry, you said\\\\this was easier?",
|
||||
target_mode="sassy"
|
||||
)
|
||||
self.play(self.teacher.change, "guilty")
|
||||
self.wait(3)
|
||||
self.teacher_says(
|
||||
"Bear with\\\\me",
|
||||
bubble_kwargs={"height": 3, "width": 3},
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class LooseWithLanguage(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
terms = VGroup(
|
||||
TextMobject("``Complex number''"),
|
||||
TextMobject("``Vector''"),
|
||||
)
|
||||
colors = [YELLOW, BLUE]
|
||||
for term, color in zip(terms, colors):
|
||||
term.set_color(color)
|
||||
|
||||
terms.scale(1.5)
|
||||
terms.arrange(DOWN, buff=LARGE_BUFF)
|
||||
terms.to_edge(UP)
|
||||
terms.match_x(self.students)
|
||||
|
||||
self.teacher_says(
|
||||
"Loose with\\\\language",
|
||||
bubble_kwargs={"width": 3, "height": 3},
|
||||
run_time=2,
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(terms[1], DOWN),
|
||||
self.get_student_changes(
|
||||
"thinking", "pondering", "erm",
|
||||
look_at_arg=terms,
|
||||
)
|
||||
)
|
||||
self.play(FadeInFromDown(terms[0]))
|
||||
self.wait()
|
||||
self.play(Swap(*terms))
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FormulaOutOfContext(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
formula = TexMobject(
|
||||
"c_{n} = \\int_0^1 e^{-2\\pi i {n} {t}}f({t}){dt}",
|
||||
tex_to_color_map={
|
||||
"{n}": YELLOW,
|
||||
"{t}": PINK,
|
||||
}
|
||||
)
|
||||
formula.scale(1.5)
|
||||
formula.next_to(self.students, UP, LARGE_BUFF)
|
||||
|
||||
self.add(formula)
|
||||
self.change_all_student_modes(
|
||||
"horrified",
|
||||
look_at_arg=formula,
|
||||
)
|
||||
self.play(self.teacher.change, "tease")
|
||||
self.wait(3)
|
||||
2471
from_3b1b/active/diffyq/part4/staging.py
Normal file
2471
from_3b1b/active/diffyq/part4/staging.py
Normal file
File diff suppressed because it is too large
Load Diff
371
from_3b1b/active/diffyq/part4/temperature_scenes.py
Normal file
371
from_3b1b/active/diffyq/part4/temperature_scenes.py
Normal file
@@ -0,0 +1,371 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.diffyq.part2.heat_equation import BringTwoRodsTogether
|
||||
from active_projects.diffyq.part3.staging import FourierSeriesIllustraiton
|
||||
|
||||
|
||||
class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"y_min": -1.5,
|
||||
"y_max": 1.5,
|
||||
"y_axis_config": {
|
||||
"unit_size": 2.5,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
"x_min": 0,
|
||||
"x_max": 1,
|
||||
"x_axis_config": {
|
||||
"unit_size": 8,
|
||||
"tick_frequency": 0.1,
|
||||
"include_tip": False,
|
||||
},
|
||||
},
|
||||
"y_labels": [-1, 1],
|
||||
"graph_x_min": 0,
|
||||
"graph_x_max": 1,
|
||||
"midpoint": 0.5,
|
||||
"min_temp": -1,
|
||||
"max_temp": 1,
|
||||
"alpha": 0.25,
|
||||
"step_size": 0.01,
|
||||
"n_range": range(1, 41, 2),
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.setup_graph()
|
||||
self.setup_clock()
|
||||
|
||||
self.bring_rods_together()
|
||||
self.let_evolve_for_a_bit()
|
||||
self.add_labels()
|
||||
self.compare_to_sine_wave()
|
||||
self.sum_of_sine_waves()
|
||||
|
||||
def bring_rods_together(self):
|
||||
rods = VGroup(
|
||||
self.get_rod(0, 0.5),
|
||||
self.get_rod(0.5, 1),
|
||||
)
|
||||
rods.add_updater(self.update_rods)
|
||||
|
||||
arrows = VGroup(
|
||||
Vector(RIGHT).next_to(rods[0], UP),
|
||||
Vector(LEFT).next_to(rods[1], UP),
|
||||
)
|
||||
|
||||
words = VGroup(
|
||||
TextMobject("Hot").next_to(rods[0], DOWN),
|
||||
TextMobject("Cold").next_to(rods[1], DOWN),
|
||||
)
|
||||
|
||||
for pair in rods, words:
|
||||
pair.save_state()
|
||||
pair.space_out_submobjects(1.2)
|
||||
|
||||
black_rects = VGroup(*[
|
||||
Square(
|
||||
side_length=1,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_width=0,
|
||||
).move_to(self.axes.c2p(0, u))
|
||||
for u in [1, -1]
|
||||
])
|
||||
black_rects[0].add_updater(
|
||||
lambda m: m.align_to(rods[0].get_right(), LEFT)
|
||||
)
|
||||
black_rects[1].add_updater(
|
||||
lambda m: m.align_to(rods[1].get_left(), RIGHT)
|
||||
)
|
||||
|
||||
self.add(
|
||||
self.axes,
|
||||
self.graph,
|
||||
self.clock,
|
||||
)
|
||||
self.add(rods, words)
|
||||
self.add(black_rects)
|
||||
|
||||
kw = {
|
||||
"run_time": 2,
|
||||
"rate_func": rush_into,
|
||||
}
|
||||
self.play(
|
||||
Restore(rods, **kw),
|
||||
Restore(words, **kw),
|
||||
*map(ShowCreation, arrows)
|
||||
)
|
||||
self.remove(black_rects)
|
||||
|
||||
self.to_fade = VGroup(words, arrows)
|
||||
self.rods = rods
|
||||
|
||||
def let_evolve_for_a_bit(self):
|
||||
rods = self.rods
|
||||
# axes = self.axes
|
||||
time_label = self.time_label
|
||||
graph = self.graph
|
||||
graph.save_state()
|
||||
|
||||
graph.add_updater(self.update_graph)
|
||||
time_label.next_to(self.clock, DOWN)
|
||||
time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
rods.add_updater(self.update_rods)
|
||||
|
||||
self.add(time_label)
|
||||
self.play(
|
||||
FadeOut(self.to_fade),
|
||||
self.get_clock_anim(1)
|
||||
)
|
||||
self.play(self.get_clock_anim(3))
|
||||
|
||||
time_label.clear_updaters()
|
||||
graph.clear_updaters()
|
||||
self.play(
|
||||
self.get_clock_anim(
|
||||
-4,
|
||||
run_time=1,
|
||||
rate_func=smooth,
|
||||
),
|
||||
graph.restore,
|
||||
time_label.set_value, 0,
|
||||
)
|
||||
rods.clear_updaters()
|
||||
self.wait()
|
||||
|
||||
def add_labels(self):
|
||||
axes = self.axes
|
||||
y_axis = axes.y_axis
|
||||
x_axis = axes.x_axis
|
||||
y_numbers = y_axis.get_number_mobjects(
|
||||
*np.arange(-1, 1.5, 0.5),
|
||||
number_config={
|
||||
"unit": "^\\circ",
|
||||
"num_decimal_places": 1,
|
||||
}
|
||||
)
|
||||
x_numbers = x_axis.get_number_mobjects(
|
||||
*np.arange(0.2, 1.2, 0.2),
|
||||
number_config={
|
||||
"num_decimal_places": 1,
|
||||
},
|
||||
)
|
||||
|
||||
self.play(FadeIn(y_numbers))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[-1]))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[0]))
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, x_numbers,
|
||||
lambda m: (m, UP)
|
||||
),
|
||||
self.rods.set_opacity, 0.8,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def compare_to_sine_wave(self):
|
||||
phi_tracker = ValueTracker(0)
|
||||
get_phi = phi_tracker.get_value
|
||||
k_tracker = ValueTracker(TAU)
|
||||
get_k = k_tracker.get_value
|
||||
A_tracker = ValueTracker(1)
|
||||
get_A = A_tracker.get_value
|
||||
|
||||
sine_wave = always_redraw(lambda: self.axes.get_graph(
|
||||
lambda x: get_A() * np.sin(
|
||||
get_k() * x - get_phi()
|
||||
),
|
||||
x_min=self.graph_x_min,
|
||||
x_max=self.graph_x_max,
|
||||
).color_using_background_image("VerticalTempGradient"))
|
||||
|
||||
self.play(ShowCreation(sine_wave, run_time=3))
|
||||
self.wait()
|
||||
self.play(A_tracker.set_value, 1.25)
|
||||
self.play(A_tracker.set_value, 0.75)
|
||||
self.play(phi_tracker.set_value, -PI / 2)
|
||||
self.play(k_tracker.set_value, 3 * TAU)
|
||||
self.play(k_tracker.set_value, 2 * TAU)
|
||||
self.play(
|
||||
k_tracker.set_value, PI,
|
||||
A_tracker.set_value, 4 / PI,
|
||||
run_time=3
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.sine_wave = sine_wave
|
||||
|
||||
def sum_of_sine_waves(self):
|
||||
curr_sine_wave = self.sine_wave
|
||||
axes = self.axes
|
||||
|
||||
sine_graphs = self.get_sine_graphs(axes)
|
||||
partial_sums = self.get_partial_sums(axes, sine_graphs)
|
||||
|
||||
curr_partial_sum = partial_sums[0]
|
||||
curr_partial_sum.set_color(WHITE)
|
||||
self.play(
|
||||
FadeOut(curr_sine_wave),
|
||||
FadeIn(curr_partial_sum),
|
||||
FadeOut(self.rods),
|
||||
)
|
||||
# Copy-pasting from superclass...in theory,
|
||||
# this should be better abstracted, but eh.
|
||||
pairs = list(zip(sine_graphs, partial_sums))[1:]
|
||||
for sine_graph, partial_sum in pairs:
|
||||
anims1 = [
|
||||
ShowCreation(sine_graph)
|
||||
]
|
||||
partial_sum.set_stroke(BLACK, 4, background=True)
|
||||
anims2 = [
|
||||
curr_partial_sum.set_stroke,
|
||||
{"width": 1, "opacity": 0.25},
|
||||
curr_partial_sum.set_stroke,
|
||||
{"width": 0, "background": True},
|
||||
ReplacementTransform(
|
||||
sine_graph, partial_sum,
|
||||
remover=True
|
||||
),
|
||||
]
|
||||
self.play(*anims1)
|
||||
self.play(*anims2)
|
||||
curr_partial_sum = partial_sum
|
||||
|
||||
#
|
||||
def setup_axes(self):
|
||||
super().setup_axes()
|
||||
self.axes.shift(
|
||||
self.axes.c2p(0, 0)[1] * DOWN
|
||||
)
|
||||
|
||||
|
||||
class BreakDownStepFunction(StepFunctionExample):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_axis_config": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_axis_config": {
|
||||
"tick_frequency": 0.25,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_min": -1.25,
|
||||
"y_max": 1.25,
|
||||
},
|
||||
"alpha": 0.1,
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.setup_graph()
|
||||
self.setup_clock()
|
||||
self.add_rod()
|
||||
|
||||
self.wait()
|
||||
self.init_updaters()
|
||||
self.play(
|
||||
self.get_clock_anim(self.wait_time)
|
||||
)
|
||||
|
||||
def setup_axes(self):
|
||||
super().setup_axes()
|
||||
axes = self.axes
|
||||
axes.to_edge(LEFT)
|
||||
|
||||
mini_axes = VGroup(*[
|
||||
axes.deepcopy()
|
||||
for x in range(4)
|
||||
])
|
||||
for n, ma in zip(it.count(1, 2), mini_axes):
|
||||
if n == 1:
|
||||
t1 = TexMobject("1")
|
||||
t2 = TexMobject("-1")
|
||||
else:
|
||||
t1 = TexMobject("1 / " + str(n))
|
||||
t2 = TexMobject("-1 / " + str(n))
|
||||
VGroup(t1, t2).scale(1.5)
|
||||
t1.next_to(ma.y_axis.n2p(1), LEFT, MED_SMALL_BUFF)
|
||||
t2.next_to(ma.y_axis.n2p(-1), LEFT, MED_SMALL_BUFF)
|
||||
ma.y_axis.numbers.set_opacity(0)
|
||||
ma.y_axis.add(t1, t2)
|
||||
|
||||
for mob in mini_axes.get_family():
|
||||
if isinstance(mob, Line):
|
||||
mob.set_stroke(width=1, family=False)
|
||||
mini_axes.arrange(DOWN, buff=2)
|
||||
mini_axes.set_height(FRAME_HEIGHT - 1.5)
|
||||
mini_axes.to_corner(UR)
|
||||
self.scale_factor = fdiv(
|
||||
mini_axes[0].get_width(),
|
||||
axes.get_width(),
|
||||
)
|
||||
|
||||
# mini_axes.arrange(RIGHT, buff=2)
|
||||
# mini_axes.set_width(FRAME_WIDTH - 1.5)
|
||||
# mini_axes.to_edge(LEFT)
|
||||
|
||||
dots = TexMobject("\\vdots")
|
||||
dots.next_to(mini_axes, DOWN)
|
||||
dots.shift_onto_screen()
|
||||
|
||||
self.add(axes)
|
||||
self.add(mini_axes)
|
||||
self.add(dots)
|
||||
|
||||
self.mini_axes = mini_axes
|
||||
|
||||
def setup_graph(self):
|
||||
super().setup_graph()
|
||||
graph = self.graph
|
||||
self.add(graph)
|
||||
|
||||
mini_axes = self.mini_axes
|
||||
mini_graphs = VGroup()
|
||||
for axes, u, n in zip(mini_axes, it.cycle([1, -1]), it.count(1, 2)):
|
||||
mini_graph = axes.get_graph(
|
||||
lambda x: (4 / PI) * (u / 1) * np.cos(PI * n * x),
|
||||
)
|
||||
mini_graph.set_stroke(WHITE, width=2)
|
||||
mini_graphs.add(mini_graph)
|
||||
# mini_graphs.set_color_by_gradient(
|
||||
# BLUE, GREEN, RED, YELLOW,
|
||||
# )
|
||||
|
||||
self.mini_graphs = mini_graphs
|
||||
self.add(mini_graphs)
|
||||
|
||||
def setup_clock(self):
|
||||
super().setup_clock()
|
||||
clock = self.clock
|
||||
time_label = self.time_label
|
||||
|
||||
clock.move_to(3 * RIGHT)
|
||||
clock.to_corner(UP)
|
||||
time_label.next_to(clock, DOWN)
|
||||
|
||||
self.add(clock)
|
||||
self.add(time_label)
|
||||
|
||||
def add_rod(self):
|
||||
self.rod = self.get_rod(0, 1)
|
||||
self.add(self.rod)
|
||||
|
||||
def init_updaters(self):
|
||||
self.graph.add_updater(self.update_graph)
|
||||
for mg in self.mini_graphs:
|
||||
mg.add_updater(
|
||||
lambda m, dt: self.update_graph(
|
||||
m, dt,
|
||||
alpha=self.scale_factor * self.alpha
|
||||
)
|
||||
)
|
||||
self.time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
self.rod.add_updater(
|
||||
lambda r: self.update_rods([r])
|
||||
)
|
||||
@@ -1,107 +1,6 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part3.temperature_graphs import TemperatureGraphScene
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class RelationToOtherVideos(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"background_color": DARK_GREY,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
# Show three videos
|
||||
videos = self.get_video_thumbnails()
|
||||
brace = Brace(videos, UP)
|
||||
text = TextMobject("Heat equation")
|
||||
text.scale(2)
|
||||
text.next_to(brace, UP)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, videos,
|
||||
lambda m: (m, LEFT),
|
||||
lag_ratio=0.4,
|
||||
run_time=2,
|
||||
),
|
||||
GrowFromCenter(brace),
|
||||
FadeInFromDown(text),
|
||||
)
|
||||
self.wait()
|
||||
group = Group(text, brace, videos)
|
||||
|
||||
# Show Fourier thinking
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
fourier.set_height(4)
|
||||
fourier.to_edge(RIGHT)
|
||||
group.generate_target()
|
||||
group.target.to_edge(DOWN)
|
||||
fourier.align_to(group.target[0], DOWN)
|
||||
bubble = ThoughtBubble(
|
||||
direction=RIGHT,
|
||||
width=3,
|
||||
height=2,
|
||||
fill_opacity=0.5,
|
||||
stroke_color=WHITE,
|
||||
)
|
||||
bubble[-1].shift(0.25 * DOWN + 0.5 * LEFT)
|
||||
bubble[:-1].rotate(20 * DEGREES)
|
||||
for mob in bubble[:-1]:
|
||||
mob.rotate(-20 * DEGREES)
|
||||
bubble.move_tip_to(
|
||||
fourier.get_corner(UL) + DOWN
|
||||
)
|
||||
bubble.to_edge(UP, buff=SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(group),
|
||||
FadeInFrom(fourier, LEFT)
|
||||
)
|
||||
self.play(Write(bubble, run_time=1))
|
||||
self.wait()
|
||||
|
||||
# Discount first two
|
||||
first_two = videos[:2]
|
||||
first_two.generate_target()
|
||||
first_two.target.scale(0.5)
|
||||
first_two.target.to_corner(DL)
|
||||
new_brace = Brace(first_two.target, UP)
|
||||
|
||||
self.play(
|
||||
# fourier.scale, 0.8,
|
||||
fourier.match_x, new_brace,
|
||||
fourier.to_edge, UP,
|
||||
MoveToTarget(first_two),
|
||||
Transform(brace, new_brace),
|
||||
text.scale, 0.7,
|
||||
text.next_to, new_brace, UP,
|
||||
FadeOutAndShift(bubble, LEFT),
|
||||
)
|
||||
self.play(
|
||||
videos[2].scale, 1.7,
|
||||
videos[2].to_corner, UR,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def get_video_thumbnails(self):
|
||||
thumbnails = Group(
|
||||
ImageMobject("diffyq_part2_thumbnail"),
|
||||
ImageMobject("diffyq_part3_thumbnail"),
|
||||
ImageMobject("diffyq_part4_thumbnail"),
|
||||
)
|
||||
for thumbnail in thumbnails:
|
||||
thumbnail.set_height(4)
|
||||
thumbnail.add(SurroundingRectangle(
|
||||
thumbnail,
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
buff=0
|
||||
))
|
||||
thumbnails.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
thumbnails.set_width(FRAME_WIDTH - 1)
|
||||
return thumbnails
|
||||
from active_projects.diffyq.part3.temperature_graphs import TemperatureGraphScene
|
||||
from active_projects.diffyq.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
@@ -293,8 +192,8 @@ class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
self.play(s2.set_value, -0.5, **kw)
|
||||
self.play(s1.set_value, -0.2, **kw)
|
||||
self.play(s2.set_value, 1.5, **kw)
|
||||
self.play(s1.set_value, 1.2)
|
||||
self.play(s2.set_value, 0.3)
|
||||
self.play(s1.set_value, 1.2, **kw)
|
||||
self.play(s2.set_value, 0.3, **kw)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
@@ -308,8 +207,8 @@ class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
axes_group.to_edge(DOWN, buff=1)
|
||||
return axes_group
|
||||
|
||||
def get_axes(self):
|
||||
axes = self.get_three_d_axes()
|
||||
def get_axes(self, **kwargs):
|
||||
axes = self.get_three_d_axes(**kwargs)
|
||||
# axes.input_plane.set_fill(opacity=0)
|
||||
# axes.input_plane.set_stroke(width=0.5)
|
||||
# axes.add(axes.input_plane)
|
||||
@@ -341,5 +240,235 @@ class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
)
|
||||
|
||||
result = always_redraw(get_surface_graph_group)
|
||||
result.func = func
|
||||
result.suspend_updating()
|
||||
return result
|
||||
|
||||
|
||||
class CombineSeveralSolutions(ShowLinearity):
|
||||
CONFIG = {
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16),
|
||||
# "resolution": (4, 4),
|
||||
},
|
||||
"n_top_graphs": 5,
|
||||
"axes_config": {
|
||||
"y_max": 15,
|
||||
},
|
||||
"target_scalars": [
|
||||
0.81, -0.53, 0.41, 0.62, -0.95
|
||||
],
|
||||
"final_run_time": 14,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_all_axes()
|
||||
self.setup_all_graphs()
|
||||
self.show_infinite_family()
|
||||
self.show_sum()
|
||||
self.show_time_passing()
|
||||
|
||||
def add_all_axes(self):
|
||||
top_axes_group = VGroup(*[
|
||||
self.get_axes(
|
||||
z_min=-1.25,
|
||||
z_max=1.25,
|
||||
z_axis_config={
|
||||
"unit_size": 2,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
)
|
||||
for x in range(self.n_top_graphs)
|
||||
])
|
||||
top_axes_group.arrange(RIGHT, buff=2)
|
||||
top_axes_group.set_width(FRAME_WIDTH - 1.5)
|
||||
top_axes_group.to_corner(UL)
|
||||
dots = TexMobject("\\dots")
|
||||
dots.next_to(top_axes_group, RIGHT)
|
||||
|
||||
low_axes = self.get_axes()
|
||||
low_axes.center()
|
||||
low_axes.scale(1.2)
|
||||
low_axes.to_edge(DOWN, buff=SMALL_BUFF)
|
||||
|
||||
self.add(top_axes_group)
|
||||
self.add(dots)
|
||||
self.add(low_axes)
|
||||
|
||||
self.top_axes_group = top_axes_group
|
||||
self.low_axes = low_axes
|
||||
|
||||
def setup_all_graphs(self):
|
||||
scalar_trackers = Group(*[
|
||||
ValueTracker(1)
|
||||
for x in range(self.n_top_graphs)
|
||||
])
|
||||
freqs = np.arange(self.n_top_graphs)
|
||||
freqs += 1
|
||||
self.top_graphs = VGroup(*[
|
||||
self.get_graph(axes, [n], [st])
|
||||
for axes, n, st in zip(
|
||||
self.top_axes_group,
|
||||
freqs,
|
||||
scalar_trackers,
|
||||
)
|
||||
])
|
||||
self.low_graph = self.get_graph(
|
||||
self.low_axes, freqs, scalar_trackers
|
||||
)
|
||||
|
||||
self.scalar_trackers = scalar_trackers
|
||||
|
||||
def show_infinite_family(self):
|
||||
top_axes_group = self.top_axes_group
|
||||
top_graphs = self.top_graphs
|
||||
scalar_trackers = self.scalar_trackers
|
||||
|
||||
decimals = self.get_decimals(
|
||||
top_axes_group, scalar_trackers
|
||||
)
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
AnimationGroup(
|
||||
Write(graph[0]),
|
||||
FadeIn(graph[1]),
|
||||
)
|
||||
for graph in top_graphs
|
||||
]))
|
||||
self.wait()
|
||||
self.play(FadeIn(decimals))
|
||||
for graph in top_graphs:
|
||||
graph.resume_updating()
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
ApplyMethod(st.set_value, value)
|
||||
for st, value in zip(
|
||||
scalar_trackers,
|
||||
self.target_scalars,
|
||||
)
|
||||
]), run_time=3)
|
||||
self.wait()
|
||||
|
||||
def show_sum(self):
|
||||
top_graphs = self.top_graphs
|
||||
low_graph = self.low_graph
|
||||
low_graph.resume_updating()
|
||||
low_graph.update()
|
||||
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
Transform(
|
||||
top_graph.copy().set_fill(opacity=0),
|
||||
low_graph.copy().set_fill(opacity=0),
|
||||
remover=True,
|
||||
)
|
||||
for top_graph in top_graphs
|
||||
]),
|
||||
FadeIn(
|
||||
low_graph,
|
||||
rate_func=squish_rate_func(smooth, 0.7, 1)
|
||||
),
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def show_time_passing(self):
|
||||
all_graphs = [*self.top_graphs, self.low_graph]
|
||||
all_axes = [*self.top_axes_group, self.low_axes]
|
||||
|
||||
time_tracker = ValueTracker(0)
|
||||
get_t = time_tracker.get_value
|
||||
|
||||
anims = [
|
||||
ApplyMethod(
|
||||
time_tracker.set_value, 1,
|
||||
run_time=1,
|
||||
rate_func=linear
|
||||
)
|
||||
]
|
||||
|
||||
for axes, graph_group in zip(all_axes, all_graphs):
|
||||
graph_group.clear_updaters()
|
||||
surface, gslice = graph_group
|
||||
plane = self.get_const_time_plane(axes)
|
||||
plane.t_tracker.add_updater(
|
||||
lambda m: m.set_value(get_t())
|
||||
)
|
||||
gslice.axes = axes
|
||||
gslice.func = graph_group.func
|
||||
gslice.add_updater(lambda m: m.become(
|
||||
self.get_time_slice_graph(
|
||||
m.axes, m.func, t=get_t()
|
||||
)
|
||||
))
|
||||
self.add(gslice)
|
||||
self.add(plane.t_tracker)
|
||||
anims.append(FadeIn(plane))
|
||||
|
||||
self.play(*anims)
|
||||
run_time = self.final_run_time
|
||||
self.play(
|
||||
time_tracker.increment_value, run_time,
|
||||
run_time=run_time,
|
||||
rate_func=linear,
|
||||
)
|
||||
|
||||
#
|
||||
def get_decimals(self, axes_group, scalar_trackers):
|
||||
result = VGroup()
|
||||
for axes, st in zip(axes_group, scalar_trackers):
|
||||
decimal = DecimalNumber()
|
||||
decimal.move_to(axes.get_bottom(), UP)
|
||||
decimal.shift(SMALL_BUFF * RIGHT)
|
||||
decimal.set_color(YELLOW)
|
||||
decimal.scalar_tracker = st
|
||||
times = TexMobject("\\times")
|
||||
times.next_to(decimal, LEFT, SMALL_BUFF)
|
||||
decimal.add_updater(lambda d: d.set_value(
|
||||
d.scalar_tracker.get_value()
|
||||
))
|
||||
group = VGroup(times, decimal)
|
||||
group.scale(0.7)
|
||||
result.add(group)
|
||||
return result
|
||||
|
||||
|
||||
class CycleThroughManyLinearCombinations(CombineSeveralSolutions):
|
||||
CONFIG = {
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16),
|
||||
# "resolution": (4, 4),
|
||||
},
|
||||
"n_cycles": 10,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_all_axes()
|
||||
self.setup_all_graphs()
|
||||
#
|
||||
self.cycle_through_superpositions()
|
||||
|
||||
def cycle_through_superpositions(self):
|
||||
top_graphs = self.top_graphs
|
||||
low_graph = self.low_graph
|
||||
scalar_trackers = self.scalar_trackers
|
||||
self.add(self.get_decimals(
|
||||
self.top_axes_group, scalar_trackers
|
||||
))
|
||||
|
||||
for graph in [low_graph, *top_graphs]:
|
||||
graph.resume_updating()
|
||||
self.add(graph)
|
||||
|
||||
nst = len(scalar_trackers)
|
||||
for x in range(self.n_cycles):
|
||||
self.play(LaggedStart(*[
|
||||
ApplyMethod(st.set_value, value)
|
||||
for st, value in zip(
|
||||
scalar_trackers,
|
||||
3 * np.random.random(nst) - 1.5
|
||||
)
|
||||
]), run_time=3)
|
||||
self.wait()
|
||||
1586
from_3b1b/active/diffyq/part5/staging.py
Normal file
1586
from_3b1b/active/diffyq/part5/staging.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
from old_projects.crypto import sha256_tex_mob, bit_string_to_mobject, BitcoinLogo
|
||||
from from_3b1b.old.crypto import sha256_tex_mob, bit_string_to_mobject, BitcoinLogo
|
||||
|
||||
def get_google_logo():
|
||||
result = SVGMobject(
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
from old_projects.uncertainty import Flash
|
||||
from old_projects.WindingNumber import *
|
||||
from from_3b1b.old.uncertainty import Flash
|
||||
from from_3b1b.old.WindingNumber import *
|
||||
|
||||
|
||||
# Warning, this file uses ContinualChangingDecimal,
|
||||
@@ -746,7 +746,7 @@ class StartingCalc101(PiCreatureScene):
|
||||
def get_aha_image(self):
|
||||
creature = self.pi_creature.copy()
|
||||
creature.change_mode("hooray")
|
||||
from old_projects.eoc.chapter3 import NudgeSideLengthOfCube
|
||||
from from_3b1b.old.eoc.chapter3 import NudgeSideLengthOfCube
|
||||
scene = NudgeSideLengthOfCube(
|
||||
end_at_animation_number=7,
|
||||
skip_animations=True
|
||||
@@ -1,7 +1,7 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.lost_lecture import GeometryProofLand
|
||||
from old_projects.quaternions import SpecialThreeDScene
|
||||
from old_projects.uncertainty import Flash
|
||||
from from_3b1b.old.lost_lecture import GeometryProofLand
|
||||
from from_3b1b.old.quaternions import SpecialThreeDScene
|
||||
from from_3b1b.old.uncertainty import Flash
|
||||
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
@@ -807,7 +807,7 @@ class FunctionGOutputSpace(FunctionGInputSpace):
|
||||
x_max=2.5,
|
||||
y_min=-2.5,
|
||||
y_max=2.5,
|
||||
number_line_config={'unit_size': 1.5}
|
||||
axis_config={'unit_size': 1.5}
|
||||
)
|
||||
for axis in axes:
|
||||
numbers = list(range(-2, 3))
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.brachistochrone.curves import *
|
||||
from from_3b1b.old.brachistochrone.curves import *
|
||||
|
||||
class RollAlongVector(Animation):
|
||||
CONFIG = {
|
||||
@@ -3,7 +3,7 @@ import itertools as it
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
from old_projects.brachistochrone.curves import Cycloid
|
||||
from from_3b1b.old.brachistochrone.curves import Cycloid
|
||||
|
||||
class MultilayeredGlass(PhotonScene, ZoomedScene):
|
||||
CONFIG = {
|
||||
@@ -3,7 +3,7 @@ import itertools as it
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
from old_projects.brachistochrone.curves import \
|
||||
from from_3b1b.old.brachistochrone.curves import \
|
||||
Cycloid, PathSlidingScene, RANDY_SCALE_FACTOR, TryManyPaths
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import numpy as np
|
||||
import itertools as it
|
||||
|
||||
from manimlib.imports import *
|
||||
from old_projects.brachistochrone.curves import Cycloid
|
||||
from from_3b1b.old.brachistochrone.curves import Cycloid
|
||||
|
||||
class PhysicalIntuition(Scene):
|
||||
def construct(self):
|
||||
@@ -2,8 +2,8 @@ import numpy as np
|
||||
import itertools as it
|
||||
|
||||
from manimlib.imports import *
|
||||
from old_projects.brachistochrone.light import PhotonScene
|
||||
from old_projects.brachistochrone.curves import *
|
||||
from from_3b1b.old.brachistochrone.light import PhotonScene
|
||||
from from_3b1b.old.brachistochrone.curves import *
|
||||
|
||||
|
||||
class MultilayeredScene(Scene):
|
||||
@@ -3,7 +3,7 @@ import itertools as it
|
||||
import os
|
||||
|
||||
from manimlib.imports import *
|
||||
from old_projects.brachistochrone.drawing_images import sort_by_color
|
||||
from from_3b1b.old.brachistochrone.drawing_images import sort_by_color
|
||||
|
||||
class Intro(Scene):
|
||||
def construct(self):
|
||||
@@ -1,10 +1,10 @@
|
||||
from old_projects.clacks import question
|
||||
from old_projects.clacks.solution2 import block_collision_scenes
|
||||
from old_projects.clacks.solution2 import mirror_scenes
|
||||
from old_projects.clacks.solution2 import pi_creature_scenes
|
||||
from old_projects.clacks.solution2 import position_phase_space
|
||||
from old_projects.clacks.solution2 import simple_scenes
|
||||
from old_projects.clacks.solution2 import wordy_scenes
|
||||
from from_3b1b.old.clacks import question
|
||||
from from_3b1b.old.clacks.solution2 import block_collision_scenes
|
||||
from from_3b1b.old.clacks.solution2 import mirror_scenes
|
||||
from from_3b1b.old.clacks.solution2 import pi_creature_scenes
|
||||
from from_3b1b.old.clacks.solution2 import position_phase_space
|
||||
from from_3b1b.old.clacks.solution2 import simple_scenes
|
||||
from from_3b1b.old.clacks.solution2 import wordy_scenes
|
||||
|
||||
OUTPUT_DIRECTORY = "clacks/solution2"
|
||||
SCENES_IN_ORDER = [
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
from manimlib.imports import *
|
||||
from old_projects.clacks.question import BlocksAndWallExample
|
||||
from from_3b1b.old.clacks.question import BlocksAndWallExample
|
||||
|
||||
|
||||
class NameBump(BlocksAndWallExample):
|
||||
@@ -325,8 +325,8 @@ class BlocksAndWallScene(Scene):
|
||||
counter_mob = Integer(self.n_clacks)
|
||||
counter_mob.next_to(
|
||||
counter_label[-1], RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
counter_mob.align_to(counter_label[-1][-1], DOWN)
|
||||
counter_group = VGroup(
|
||||
counter_label,
|
||||
counter_mob,
|
||||
@@ -747,7 +747,7 @@ class BlocksAndWallExampleMass1e2(BlocksAndWallExample):
|
||||
"velocity": -0.6,
|
||||
}
|
||||
},
|
||||
"wait_time": 25,
|
||||
"wait_time": 35,
|
||||
}
|
||||
|
||||
|
||||
@@ -888,7 +888,7 @@ class PiComputingAlgorithmsAxes(Scene):
|
||||
y_min=0,
|
||||
x_max=9,
|
||||
y_max=5,
|
||||
number_line_config={
|
||||
axis_config={
|
||||
"tick_frequency": 100,
|
||||
"numbers_with_elongated_ticks": [],
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.clacks.question import *
|
||||
from old_projects.div_curl import ShowTwoPopulations
|
||||
from from_3b1b.old.clacks.question import *
|
||||
from from_3b1b.old.div_curl import ShowTwoPopulations
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "clacks/solution1"
|
||||
@@ -633,7 +633,7 @@ class IntroduceVelocityPhaseSpace(AskAboutFindingNewVelocities):
|
||||
"x_min": -3.5,
|
||||
"x_max": 4,
|
||||
},
|
||||
"number_line_config": {
|
||||
"axis_config": {
|
||||
"unit_size": 0.7,
|
||||
},
|
||||
},
|
||||
@@ -1204,6 +1204,8 @@ class CircleDiagramFromSlidingBlocks(Scene):
|
||||
"fill_color": GREEN,
|
||||
"fill_opacity": 0.3,
|
||||
},
|
||||
"show_dot": True,
|
||||
"show_vector": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
@@ -1211,6 +1213,9 @@ class CircleDiagramFromSlidingBlocks(Scene):
|
||||
show_flash_animations=False,
|
||||
write_to_movie=False,
|
||||
wait_time=0,
|
||||
file_writer_config={
|
||||
"output_directory": ".",
|
||||
}
|
||||
)
|
||||
blocks = sliding_blocks_scene.blocks
|
||||
times = [pair[1] for pair in blocks.clack_data]
|
||||
@@ -1229,7 +1234,17 @@ class CircleDiagramFromSlidingBlocks(Scene):
|
||||
dot = Dot(color=RED, radius=0.06)
|
||||
dot.move_to(lines[0].get_start())
|
||||
|
||||
self.add(end_zone, axes, circle, dot)
|
||||
vector = Vector(lines[0].get_start())
|
||||
vector.set_color(RED)
|
||||
vector.add_updater(lambda v: v.put_start_and_end_on(
|
||||
ORIGIN, dot.get_center()
|
||||
))
|
||||
vector.set_stroke(BLACK, 2, background=True)
|
||||
|
||||
dot.set_opacity(int(self.show_dot))
|
||||
vector.set_opacity(int(self.show_vector))
|
||||
|
||||
self.add(end_zone, axes, circle, dot, vector)
|
||||
|
||||
last_time = 0
|
||||
for time, line in zip(times, lines):
|
||||
@@ -1238,7 +1253,7 @@ class CircleDiagramFromSlidingBlocks(Scene):
|
||||
self.wait(time - last_time)
|
||||
last_time = time
|
||||
dot.move_to(line.get_end())
|
||||
self.add(line, dot)
|
||||
self.add(line, dot, vector)
|
||||
self.wait()
|
||||
|
||||
def get_circle(self):
|
||||
@@ -2597,7 +2612,7 @@ class UnitCircleIntuition(Scene):
|
||||
def draw_unit_circle(self):
|
||||
unit_size = 2.5
|
||||
axes = Axes(
|
||||
number_line_config={"unit_size": unit_size},
|
||||
axis_config={"unit_size": unit_size},
|
||||
x_min=-2.5, x_max=2.5,
|
||||
y_min=-1.5, y_max=1.5,
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.clacks.question import BlocksAndWallExample
|
||||
from from_3b1b.old.clacks.question import BlocksAndWallExample
|
||||
|
||||
|
||||
class PreviousTwoVideos(BlocksAndWallExample):
|
||||
@@ -1,7 +1,7 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.clacks.question import Block
|
||||
from old_projects.clacks.question import Wall
|
||||
from old_projects.clacks.question import ClackFlashes
|
||||
from from_3b1b.old.clacks.question import Block
|
||||
from from_3b1b.old.clacks.question import Wall
|
||||
from from_3b1b.old.clacks.question import ClackFlashes
|
||||
|
||||
|
||||
class PositionPhaseSpaceScene(Scene):
|
||||
@@ -1,7 +1,7 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.lost_lecture import ShowWord
|
||||
from old_projects.clacks.solution2.mirror_scenes import ReflectWorldThroughMirrorNew
|
||||
from old_projects.clacks.question import Thumbnail
|
||||
from from_3b1b.old.lost_lecture import ShowWord
|
||||
from from_3b1b.old.clacks.solution2.mirror_scenes import ReflectWorldThroughMirrorNew
|
||||
from from_3b1b.old.clacks.question import Thumbnail
|
||||
|
||||
|
||||
class WrapperScene(Scene):
|
||||
@@ -1,5 +1,5 @@
|
||||
from manimlib.imports import *
|
||||
from old_projects.clacks.solution2.position_phase_space import ShowMomentumConservation
|
||||
from from_3b1b.old.clacks.solution2.position_phase_space import ShowMomentumConservation
|
||||
|
||||
|
||||
class ConnectionToOptics(Scene):
|
||||
@@ -1,7 +1,7 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
from old_projects.lost_lecture import Orbiting
|
||||
from old_projects.lost_lecture import ShowWord
|
||||
from from_3b1b.old.lost_lecture import Orbiting
|
||||
from from_3b1b.old.lost_lecture import ShowWord
|
||||
|
||||
|
||||
class LogoGeneration(LogoGenerationTemplate):
|
||||
@@ -2925,7 +2925,7 @@ class PhaseSpaceOfPopulationModel(ShowTwoPopulations, PiCreatureScene, MovingCam
|
||||
y_min=0,
|
||||
y_max=55,
|
||||
y_axis_config={"unit_size": 0.09},
|
||||
number_line_config={
|
||||
axis_config={
|
||||
"tick_frequency": 10,
|
||||
},
|
||||
)
|
||||
@@ -4217,7 +4217,7 @@ class BroughtToYouBy(PiCreatureScene):
|
||||
|
||||
spiral = Line(0.5 * RIGHT, 0.5 * RIGHT + 70 * UP)
|
||||
spiral.insert_n_curves(1000)
|
||||
from old_projects.zeta import zeta
|
||||
from from_3b1b.old.zeta import zeta
|
||||
spiral.apply_complex_function(zeta)
|
||||
step = 0.1
|
||||
spiral = VGroup(*[
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user