mirror of
https://github.com/3b1b/manim.git
synced 2026-01-13 08:27:54 -05:00
Compare commits
1563 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ec00629a5 | ||
|
|
aa6335cd90 | ||
|
|
7093f7d02d | ||
|
|
fad9ed2df7 | ||
|
|
725155409b | ||
|
|
a6675eb043 | ||
|
|
5d2dcec307 | ||
|
|
f60dc7cd07 | ||
|
|
6c39cac62b | ||
|
|
2bd25a55fa | ||
|
|
0e4edfdd79 | ||
|
|
277256a407 | ||
|
|
831b7d455c | ||
|
|
1d14a23af9 | ||
|
|
dffa70ea15 | ||
|
|
31976063df | ||
|
|
aa135280ac | ||
|
|
f0160822ba | ||
|
|
48e07d1817 | ||
|
|
3ef5899a24 | ||
|
|
f895455264 | ||
|
|
3baa14103e | ||
|
|
c315300ff1 | ||
|
|
3b17d6d0eb | ||
|
|
8a29de5ef0 | ||
|
|
ecb729850a | ||
|
|
a770291053 | ||
|
|
27c666fab5 | ||
|
|
942a7e71b8 | ||
|
|
ebb75d1235 | ||
|
|
9af23415a2 | ||
|
|
19778e405a | ||
|
|
833e40c2d4 | ||
|
|
9df53b8a18 | ||
|
|
ff86b0e378 | ||
|
|
92adcd75d4 | ||
|
|
240f5020b4 | ||
|
|
e8205a5049 | ||
|
|
6c8dd14adc | ||
|
|
07f84e2676 | ||
|
|
8db1164ece | ||
|
|
790bf0a104 | ||
|
|
8205edcc4c | ||
|
|
05b3c9852e | ||
|
|
925f2e123f | ||
|
|
565763a2ff | ||
|
|
6a74c241b8 | ||
|
|
416cc8e6d5 | ||
|
|
d694aed452 | ||
|
|
11379283aa | ||
|
|
dd13559b11 | ||
|
|
1658438fef | ||
|
|
f4eb2724c5 | ||
|
|
33f720c73a | ||
|
|
bbb4fa155c | ||
|
|
2318c9e716 | ||
|
|
e80dd243f1 | ||
|
|
3ffe300f96 | ||
|
|
24e3caa072 | ||
|
|
9efd02c500 | ||
|
|
0a318486c5 | ||
|
|
919133c6bf | ||
|
|
066a2ed5dc | ||
|
|
09ced7ce9a | ||
|
|
505b229117 | ||
|
|
5aa8d15d85 | ||
|
|
7aa05572ab | ||
|
|
f1996f8479 | ||
|
|
37b63ca956 | ||
|
|
84fd657d9b | ||
|
|
b489490f41 | ||
|
|
bbf45f95c6 | ||
|
|
b61f1473a5 | ||
|
|
e3d5b49a55 | ||
|
|
4d6a0db1e1 | ||
|
|
0af46e149d | ||
|
|
896b011d76 | ||
|
|
3adaf8e325 | ||
|
|
8762177df5 | ||
|
|
a1d51474ea | ||
|
|
83841ae415 | ||
|
|
b81f244c3c | ||
|
|
7023548ec6 | ||
|
|
758f329a06 | ||
|
|
8f1dfabff0 | ||
|
|
7fa01d5de8 | ||
|
|
0de303d5e0 | ||
|
|
155839bde9 | ||
|
|
3a1e5e1bcf | ||
|
|
264f7b1172 | ||
|
|
85e90a1488 | ||
|
|
f8e6e7df3c | ||
|
|
5dd7cce67f | ||
|
|
f21a4a4696 | ||
|
|
98b0d266d2 | ||
|
|
6821a7c20e | ||
|
|
00f72da493 | ||
|
|
744916507c | ||
|
|
88d863c1d7 | ||
|
|
d7dcc9d76f | ||
|
|
4631508b7d | ||
|
|
8803088121 | ||
|
|
1d466cb299 | ||
|
|
5a1f00b1cb | ||
|
|
17d31045b2 | ||
|
|
950466c1da | ||
|
|
62151e52f1 | ||
|
|
b4ce0b910c | ||
|
|
9dd1f47dab | ||
|
|
49743daf32 | ||
|
|
ba23fbe71e | ||
|
|
ee1594a3cb | ||
|
|
e9afb0ee33 | ||
|
|
8b1715379d | ||
|
|
2501fac32f | ||
|
|
1aec0462ec | ||
|
|
83c70a59d8 | ||
|
|
9b8a6e7ff8 | ||
|
|
758f2ec236 | ||
|
|
d9cac38618 | ||
|
|
e8ebfa312b | ||
|
|
dae24891fa | ||
|
|
a4f9de1ca1 | ||
|
|
697028cd4c | ||
|
|
c84acc0023 | ||
|
|
b1d869cd11 | ||
|
|
13a5f6d6ff | ||
|
|
e3f87d835b | ||
|
|
7ffab788b7 | ||
|
|
bcd09906be | ||
|
|
407c53f97c | ||
|
|
eea3c6b294 | ||
|
|
d2182b9112 | ||
|
|
fbc329d7ce | ||
|
|
25045143a1 | ||
|
|
e899604a2d | ||
|
|
0b898a5594 | ||
|
|
ee2f68cd49 | ||
|
|
2cce4ccdd7 | ||
|
|
f3ecebee43 | ||
|
|
e764da3c3a | ||
|
|
fbbea47d11 | ||
|
|
781a9934fd | ||
|
|
a7173142bf | ||
|
|
0e78027186 | ||
|
|
82bd02d21f | ||
|
|
d065e1973d | ||
|
|
7070777408 | ||
|
|
5c2a9f2129 | ||
|
|
1b695e1c19 | ||
|
|
da1cc44d90 | ||
|
|
3bbb759112 | ||
|
|
41c6cbcb59 | ||
|
|
5930e6a176 | ||
|
|
8f3ff91165 | ||
|
|
b12677bc1a | ||
|
|
cdec64e3f1 | ||
|
|
2dc8bc9b9c | ||
|
|
94f0bf557a | ||
|
|
e20690b7c1 | ||
|
|
2c7689ed9e | ||
|
|
c73d507c76 | ||
|
|
317a5d6226 | ||
|
|
4339f97c56 | ||
|
|
81c3ae3037 | ||
|
|
61b04079f5 | ||
|
|
5a0e5a16ea | ||
|
|
f0b5181694 | ||
|
|
185782a2e7 | ||
|
|
8ab95ebe9d | ||
|
|
77159eea2e | ||
|
|
6766e459f2 | ||
|
|
01f4ef3e5d | ||
|
|
b531c82bc4 | ||
|
|
5d942d5ac0 | ||
|
|
b285ca7c22 | ||
|
|
82540edae9 | ||
|
|
f9a6fa7036 | ||
|
|
4eabaecfc8 | ||
|
|
b881e55fca | ||
|
|
f1c50640a3 | ||
|
|
deb1311e48 | ||
|
|
82fa6ab125 | ||
|
|
4d91ff3f2f | ||
|
|
b6f9da87d0 | ||
|
|
c60e97ebf9 | ||
|
|
b1ed16e81a | ||
|
|
c94ebaa260 | ||
|
|
030fb52018 | ||
|
|
487f582302 | ||
|
|
6d0c55d2ba | ||
|
|
c82f60e29e | ||
|
|
c03279d626 | ||
|
|
7b72fa8ca1 | ||
|
|
8b454fbe93 | ||
|
|
f77e25ff86 | ||
|
|
872ef67cf7 | ||
|
|
305ca72ebe | ||
|
|
4d81d3678b | ||
|
|
55e968e174 | ||
|
|
97d1609849 | ||
|
|
e10f850d0d | ||
|
|
b8584fe5ab | ||
|
|
b6c23a09e9 | ||
|
|
0e574882b3 | ||
|
|
bee3470856 | ||
|
|
ed3d44120c | ||
|
|
4466cfe727 | ||
|
|
e9aba0b92c | ||
|
|
6cdbe0d67a | ||
|
|
7732d2f0ee | ||
|
|
f77482c864 | ||
|
|
23ebbb2af1 | ||
|
|
14fbed76da | ||
|
|
e10a752c00 | ||
|
|
fde82e09c0 | ||
|
|
cfd362aa56 | ||
|
|
329d2c6eae | ||
|
|
f22a341e84 | ||
|
|
2d115a2c90 | ||
|
|
c726eb7a18 | ||
|
|
33fa76dfac | ||
|
|
0021880fba | ||
|
|
ed99427a3b | ||
|
|
7425057d9f | ||
|
|
ef5253f1bc | ||
|
|
fbccb1ebf3 | ||
|
|
f626a1a1e2 | ||
|
|
c1242d2dd5 | ||
|
|
719c81d72b | ||
|
|
ed1fc4d5f9 | ||
|
|
3822b00bec | ||
|
|
2753beb7bb | ||
|
|
a4afbfd739 | ||
|
|
5f878a2c1a | ||
|
|
9483f26a3b | ||
|
|
b4132e3d5e | ||
|
|
e9b404406d | ||
|
|
b543cc0e32 | ||
|
|
d45ea28dc1 | ||
|
|
788775e419 | ||
|
|
1bca0e63e9 | ||
|
|
54ad3550ef | ||
|
|
d19b386415 | ||
|
|
e359f520bc | ||
|
|
696fc85ff7 | ||
|
|
add1daf500 | ||
|
|
242e4a3471 | ||
|
|
9e563ae3b4 | ||
|
|
da909c0df8 | ||
|
|
0239e12d8a | ||
|
|
0fd8fdc3ca | ||
|
|
762f1abef7 | ||
|
|
17c2772b84 | ||
|
|
0d2d1b5c03 | ||
|
|
4ce123be44 | ||
|
|
d5a88d0fa4 | ||
|
|
3b146636b4 | ||
|
|
b24ba19dec | ||
|
|
0dc096bf57 | ||
|
|
e40a2935b1 | ||
|
|
f84b8a66fe | ||
|
|
952a598e3b | ||
|
|
c635f19f2a | ||
|
|
8645894255 | ||
|
|
e712951f2d | ||
|
|
1b24074369 | ||
|
|
acba13f499 | ||
|
|
61aec6051a | ||
|
|
9a78d13212 | ||
|
|
0787c4f362 | ||
|
|
0b7b3f4f31 | ||
|
|
7356a36fa7 | ||
|
|
f3e3a7c56f | ||
|
|
a35dd5a3cb | ||
|
|
7b4199c674 | ||
|
|
d8378d8157 | ||
|
|
8647a6429d | ||
|
|
3bb8f3f042 | ||
|
|
56df15453f | ||
|
|
d50717a3fc | ||
|
|
ca9b70e218 | ||
|
|
25c5aa2c65 | ||
|
|
c08ea4e645 | ||
|
|
573d630e5b | ||
|
|
6d72893382 | ||
|
|
40290ada83 | ||
|
|
bd356daa99 | ||
|
|
b667db2d31 | ||
|
|
f92211b352 | ||
|
|
1c2b52a128 | ||
|
|
eb315daeda | ||
|
|
e151334675 | ||
|
|
bbeba108bc | ||
|
|
77ce17679c | ||
|
|
7fa2654d8a | ||
|
|
ec620fa849 | ||
|
|
da53a6f808 | ||
|
|
1e621e8278 | ||
|
|
31119b630e | ||
|
|
b0fd520382 | ||
|
|
c1e14ef5b6 | ||
|
|
e9470b6bde | ||
|
|
5c0a1e4b76 | ||
|
|
121e6215f8 | ||
|
|
3d5642f3d7 | ||
|
|
9df58e4ddf | ||
|
|
f09092024f | ||
|
|
4d65c97965 | ||
|
|
76966064ce | ||
|
|
152d03ed27 | ||
|
|
8624168ed9 | ||
|
|
354db4423f | ||
|
|
27344249de | ||
|
|
0b3a1b271c | ||
|
|
fd8904ec83 | ||
|
|
7da6179493 | ||
|
|
17452dcd10 | ||
|
|
2f5acc6a87 | ||
|
|
71f018dfff | ||
|
|
b3ae517a05 | ||
|
|
f7bb5c1b8c | ||
|
|
a3227dda67 | ||
|
|
2ed78c6e0f | ||
|
|
8aa004b0b1 | ||
|
|
45938dd76f | ||
|
|
3fe4d6d2d4 | ||
|
|
a18600e8a4 | ||
|
|
700418a79c | ||
|
|
4940ccac7d | ||
|
|
17d7f0b6f0 | ||
|
|
275cf94b06 | ||
|
|
54fff5523b | ||
|
|
5707585d17 | ||
|
|
0305582e64 | ||
|
|
a4c3bb03d1 | ||
|
|
b00d718431 | ||
|
|
6da5d4c8f6 | ||
|
|
01670cf823 | ||
|
|
5986d0e7d2 | ||
|
|
d384fc1e27 | ||
|
|
8aedb8f33e | ||
|
|
bccc17a3ac | ||
|
|
892df54c9f | ||
|
|
663c57ba74 | ||
|
|
26e9b9cd7c | ||
|
|
a99ccea02c | ||
|
|
892ce2db09 | ||
|
|
d14f22c5ba | ||
|
|
846c10a0ff | ||
|
|
128178b46e | ||
|
|
b4f23e8d8e | ||
|
|
5765ab9055 | ||
|
|
6eb7edc664 | ||
|
|
e836c3bb42 | ||
|
|
5ff8e28ba5 | ||
|
|
6dc1ecb00a | ||
|
|
be78f5257a | ||
|
|
798479536d | ||
|
|
226df63d0b | ||
|
|
b8fb69773e | ||
|
|
fec2306f9a | ||
|
|
17d75bd336 | ||
|
|
23662d093f | ||
|
|
34d4689672 | ||
|
|
607ef334e9 | ||
|
|
b4b4d39ec5 | ||
|
|
1c2942798e | ||
|
|
e9ea5fbea0 | ||
|
|
7ecfc041b3 | ||
|
|
44a9c6337e | ||
|
|
d1a5089acc | ||
|
|
9e5f39a4a9 | ||
|
|
6da93cde7b | ||
|
|
6340db1076 | ||
|
|
f45d81be11 | ||
|
|
baa2adc128 | ||
|
|
f16277f100 | ||
|
|
876f06cc37 | ||
|
|
f682bf97e3 | ||
|
|
025639f026 | ||
|
|
e885ec6ecd | ||
|
|
3b3150c3c5 | ||
|
|
33aa4e979a | ||
|
|
9de7a6477d | ||
|
|
19b8057136 | ||
|
|
b6dd6fe16d | ||
|
|
51b2984ee3 | ||
|
|
957eedc32c | ||
|
|
2614b34d11 | ||
|
|
4ea1d6d64f | ||
|
|
fd67858bb0 | ||
|
|
442e7fc14d | ||
|
|
bb27a78449 | ||
|
|
a06d5613f4 | ||
|
|
6605ab75e8 | ||
|
|
ed9a4bd9eb | ||
|
|
d54b796154 | ||
|
|
bb72718c3b | ||
|
|
d279272762 | ||
|
|
f2f652f85d | ||
|
|
bf9d797d84 | ||
|
|
29e5a8bc90 | ||
|
|
02bad81fc3 | ||
|
|
2bfe7e08ff | ||
|
|
e727faaccb | ||
|
|
6b911f5721 | ||
|
|
565ff09d58 | ||
|
|
4b4a973464 | ||
|
|
8e2799a499 | ||
|
|
a44e230a07 | ||
|
|
f9fb68c011 | ||
|
|
c1ad893030 | ||
|
|
65d0826b91 | ||
|
|
41120b096e | ||
|
|
1f6e911d60 | ||
|
|
c45ff910f0 | ||
|
|
15760cf253 | ||
|
|
f6291d7e82 | ||
|
|
b5e6177afd | ||
|
|
22d9c57f60 | ||
|
|
3a992e136d | ||
|
|
12ef0a26d7 | ||
|
|
7a11e3d20f | ||
|
|
cf63dfddf9 | ||
|
|
42d8888f8e | ||
|
|
322f138490 | ||
|
|
df657c06c2 | ||
|
|
0c61c908b2 | ||
|
|
82658e1db3 | ||
|
|
de9ecbd766 | ||
|
|
ca9f4357fa | ||
|
|
e95aa69c4c | ||
|
|
6997cc9501 | ||
|
|
7f47815230 | ||
|
|
d3e61b962b | ||
|
|
8999ebb556 | ||
|
|
88f0c24c69 | ||
|
|
09579fcd3e | ||
|
|
01d989ba23 | ||
|
|
6c3e4b94ea | ||
|
|
52baf5b7c2 | ||
|
|
fd18e4a21f | ||
|
|
2a1b023442 | ||
|
|
288983e7b9 | ||
|
|
f6ff070a8e | ||
|
|
5126dd1f52 | ||
|
|
8345ca6160 | ||
|
|
611ac7f448 | ||
|
|
933b7fd3da | ||
|
|
15f3b359ae | ||
|
|
0e326c7ac5 | ||
|
|
ed2e3e80d9 | ||
|
|
3c240478b8 | ||
|
|
120d26defa | ||
|
|
5c427ea287 | ||
|
|
503bd116a6 | ||
|
|
f5d5565af1 | ||
|
|
aedf5633aa | ||
|
|
63b497c352 | ||
|
|
531a031b50 | ||
|
|
b48ce3f1de | ||
|
|
5636b41dfd | ||
|
|
402c06c99a | ||
|
|
eec396681c | ||
|
|
d06b3769b8 | ||
|
|
8fcb069808 | ||
|
|
9fb6280f1d | ||
|
|
e35f8466be | ||
|
|
44df81fd70 | ||
|
|
d1fc6c8ed7 | ||
|
|
9d1c8df095 | ||
|
|
1d0b864001 | ||
|
|
5008e20b8e | ||
|
|
c92b6dbd0b | ||
|
|
9c23a5feef | ||
|
|
ba3bb64bce | ||
|
|
448d792473 | ||
|
|
2f202e26b2 | ||
|
|
f9b1167d14 | ||
|
|
4179c1c3e9 | ||
|
|
0c25b56afe | ||
|
|
0f95e80798 | ||
|
|
b7e2abb801 | ||
|
|
1543450a4f | ||
|
|
c9e223485c | ||
|
|
9bf51bda02 | ||
|
|
a46b7d6931 | ||
|
|
8f502f2790 | ||
|
|
c30b535504 | ||
|
|
a5d5e40f6a | ||
|
|
ad332c5863 | ||
|
|
96d9a66faf | ||
|
|
368a6c3d1c | ||
|
|
0c3b401d34 | ||
|
|
9df136c723 | ||
|
|
e1e7b1e6c1 | ||
|
|
e7240547fb | ||
|
|
9158b7a0c2 | ||
|
|
dba0550da5 | ||
|
|
5df4e68f1b | ||
|
|
787b3be357 | ||
|
|
c700a27cad | ||
|
|
d7f3f5ad24 | ||
|
|
1798875396 | ||
|
|
0cd0a56243 | ||
|
|
6e2dcae4d7 | ||
|
|
17b2efeb71 | ||
|
|
4ff876b536 | ||
|
|
cbe24daa98 | ||
|
|
fdb6673238 | ||
|
|
156b83c38e | ||
|
|
2d83cccc0a | ||
|
|
cfd32c79b1 | ||
|
|
d24ba30fde | ||
|
|
558f2652a4 | ||
|
|
de3916424f | ||
|
|
3bf956871b | ||
|
|
84f032610f | ||
|
|
36e8421395 | ||
|
|
3770fae6cf | ||
|
|
ddda43e03e | ||
|
|
cb4b67655b | ||
|
|
7c683c8992 | ||
|
|
6331f76c12 | ||
|
|
944128d9bf | ||
|
|
b374a07d76 | ||
|
|
24d9d9e45d | ||
|
|
f0cbc0571f | ||
|
|
608b2d9bce | ||
|
|
47d4b0236e | ||
|
|
41a02285bd | ||
|
|
00e9c426ff | ||
|
|
69235f0a21 | ||
|
|
e8f288f753 | ||
|
|
1084dfb681 | ||
|
|
12e8506841 | ||
|
|
f984443ed5 | ||
|
|
479aac1988 | ||
|
|
97e7b0568e | ||
|
|
9a79043640 | ||
|
|
4d644538b1 | ||
|
|
95191325e8 | ||
|
|
700d7c6def | ||
|
|
36107c28ef | ||
|
|
00fe33957c | ||
|
|
cbe016391b | ||
|
|
3fa68ad60c | ||
|
|
e3d09d161c | ||
|
|
2394bdc2e6 | ||
|
|
634c3d672e | ||
|
|
b558ae98cf | ||
|
|
e6fc323b6d | ||
|
|
c3ccfbfa65 | ||
|
|
6f69902892 | ||
|
|
1a5a59f40e | ||
|
|
2493458e45 | ||
|
|
1ab60f1c3e | ||
|
|
e677f4027a | ||
|
|
03bea8198c | ||
|
|
28650b27dc | ||
|
|
2c55f93512 | ||
|
|
567e62de03 | ||
|
|
a2f201f59e | ||
|
|
514301e0af | ||
|
|
71f328c7ef | ||
|
|
66817c4e2b | ||
|
|
f87b82a9e9 | ||
|
|
2a3db89a2d | ||
|
|
a63dd119c1 | ||
|
|
f786eb68d1 | ||
|
|
25cd846356 | ||
|
|
7a44d66ebc | ||
|
|
4de31aba7f | ||
|
|
43614394a4 | ||
|
|
ed0ac3bee4 | ||
|
|
94894c0fe3 | ||
|
|
f05f94fbf5 | ||
|
|
e7251bcc2f | ||
|
|
c0f6e94545 | ||
|
|
390bfac9df | ||
|
|
269128dfb6 | ||
|
|
8f52c7bda8 | ||
|
|
5eafed2c31 | ||
|
|
4b6a3a2599 | ||
|
|
0e5423807c | ||
|
|
60605e8442 | ||
|
|
b1efee5088 | ||
|
|
820e1840d3 | ||
|
|
10c1f054ca | ||
|
|
1727d4b86a | ||
|
|
2d4ffc989e | ||
|
|
a45e0afe0e | ||
|
|
f13c41bcbb | ||
|
|
65f4f4bd29 | ||
|
|
521e3ef143 | ||
|
|
7dffa24acd | ||
|
|
0726dccd0a | ||
|
|
003fafc20f | ||
|
|
d981ee47e2 | ||
|
|
46294a5fad | ||
|
|
d7e63d907a | ||
|
|
afd1ef65f2 | ||
|
|
5b9672bb59 | ||
|
|
c2b2cb3b7e | ||
|
|
c040dba835 | ||
|
|
0a5414553f | ||
|
|
6fde779944 | ||
|
|
c8f4c49720 | ||
|
|
5e3ed6f860 | ||
|
|
5a16e3a358 | ||
|
|
fc6953e102 | ||
|
|
3938f81c1b | ||
|
|
0c6149c9dd | ||
|
|
ddcd052036 | ||
|
|
2fbe0c6ee6 | ||
|
|
1097f0df96 | ||
|
|
04a259950f | ||
|
|
37f1130de6 | ||
|
|
dda9683fb7 | ||
|
|
729dae1376 | ||
|
|
32632367b6 | ||
|
|
46309e26c7 | ||
|
|
dcffbe21d5 | ||
|
|
c5b0040166 | ||
|
|
5b6997aea9 | ||
|
|
7a6a8556b8 | ||
|
|
e4df135bbe | ||
|
|
9916f56fb1 | ||
|
|
74365065fe | ||
|
|
7b614bc968 | ||
|
|
a4dbd0881b | ||
|
|
e9ec5e0c93 | ||
|
|
143634742b | ||
|
|
c32104b7ca | ||
|
|
2d19ee8264 | ||
|
|
f4c82b62af | ||
|
|
55e8d3bc55 | ||
|
|
be5762ba9c | ||
|
|
3ec8bb0d28 | ||
|
|
98a25eaefe | ||
|
|
fc01239c7a | ||
|
|
331e5a1c21 | ||
|
|
0e80799b1f | ||
|
|
fbb0d76f4f | ||
|
|
2061f95ef5 | ||
|
|
82eb0ae5be | ||
|
|
5cc30df2ac | ||
|
|
fb8280171b | ||
|
|
fc482c107f | ||
|
|
384304e92b | ||
|
|
fdcac10861 | ||
|
|
fe85d4e02f | ||
|
|
8f9ce57de5 | ||
|
|
1253c18c54 | ||
|
|
3dc0c7b0cb | ||
|
|
09ae714edb | ||
|
|
d6b23324a6 | ||
|
|
b63ba1c7a4 | ||
|
|
b00c93dc88 | ||
|
|
5fb06e77b5 | ||
|
|
d5d13c3174 | ||
|
|
9b3332ad02 | ||
|
|
3c0f8abe5f | ||
|
|
53cfbacab4 | ||
|
|
e3b74ffd7a | ||
|
|
52dd06ce6f | ||
|
|
90293f3907 | ||
|
|
32e5b2b4b1 | ||
|
|
c292046913 | ||
|
|
73edeaa153 | ||
|
|
375bc2073d | ||
|
|
b353c4f21c | ||
|
|
367e243066 | ||
|
|
5a2a363a87 | ||
|
|
baab9ddf02 | ||
|
|
c1ebb583c8 | ||
|
|
696e952a3a | ||
|
|
a3754fa606 | ||
|
|
5de62edfb8 | ||
|
|
c39d208ff0 | ||
|
|
a47b7c6bae | ||
|
|
4aa6be6e55 | ||
|
|
f900669bc4 | ||
|
|
06ba7031c7 | ||
|
|
2fd4d7a2c4 | ||
|
|
cd79151c10 | ||
|
|
a7697095d6 | ||
|
|
42c59f80c8 | ||
|
|
c68bf1c8f7 | ||
|
|
ddcfd01fa3 | ||
|
|
bb62ff4cd6 | ||
|
|
c0852eae88 | ||
|
|
4494d80a4c | ||
|
|
14cbfc0423 | ||
|
|
539f3b095a | ||
|
|
5dbc7d807f | ||
|
|
d04d451c6a | ||
|
|
a58772db87 | ||
|
|
0ac155d150 | ||
|
|
090743aacb | ||
|
|
9bd4f6714f | ||
|
|
e4f888fbc4 | ||
|
|
e08784400a | ||
|
|
20b787223b | ||
|
|
9a502cd83b | ||
|
|
78ac18496d | ||
|
|
59af903f14 | ||
|
|
e218105f73 | ||
|
|
f91c81dd6a | ||
|
|
3bd56bff07 | ||
|
|
68a8114d7a | ||
|
|
9c524fe3a7 | ||
|
|
b3c8940a18 | ||
|
|
1b1b138860 | ||
|
|
19e93454d9 | ||
|
|
86bfa4c39c | ||
|
|
cfa8577454 | ||
|
|
b7bd40a6f6 | ||
|
|
453ccc2765 | ||
|
|
f6b5edede2 | ||
|
|
3d118a5bb6 | ||
|
|
314c847463 | ||
|
|
7f27e926f2 | ||
|
|
5f6b653803 | ||
|
|
83a9217063 | ||
|
|
2daf62ecea | ||
|
|
c698c6ea44 | ||
|
|
4e4a7b9886 | ||
|
|
b423a423b5 | ||
|
|
d37de184d2 | ||
|
|
bec3ba70eb | ||
|
|
08e22cf859 | ||
|
|
1f3b058aa9 | ||
|
|
d4c89e520f | ||
|
|
7c04edcced | ||
|
|
97ecfcda9b | ||
|
|
c6fcaa93bb | ||
|
|
fa3cad18e0 | ||
|
|
f696ba4100 | ||
|
|
1d1706039e | ||
|
|
78848b971c | ||
|
|
79b8136330 | ||
|
|
f314054081 | ||
|
|
7b67f4556b | ||
|
|
8f6b006cc8 | ||
|
|
281b38b860 | ||
|
|
f90e4147b6 | ||
|
|
d53dbba346 | ||
|
|
098b939ec0 | ||
|
|
8b83c5e27d | ||
|
|
2c27511556 | ||
|
|
9f5f682351 | ||
|
|
39cdae0983 | ||
|
|
b40a3b5710 | ||
|
|
38b305bb19 | ||
|
|
8cc484943e | ||
|
|
d29cfd842f | ||
|
|
2e3a112ff8 | ||
|
|
d65a915e7b | ||
|
|
5f69899e65 | ||
|
|
5e09a80c5b | ||
|
|
f61dfe7948 | ||
|
|
bf3571c103 | ||
|
|
20593d8fa8 | ||
|
|
6537258f24 | ||
|
|
fda7fff146 | ||
|
|
00333d0a4d | ||
|
|
ad60b903d0 | ||
|
|
091cd355d4 | ||
|
|
dd2a459eaa | ||
|
|
c5aa330077 | ||
|
|
bbe79e0026 | ||
|
|
7af100489b | ||
|
|
f1c32b64cc | ||
|
|
cc094dd479 | ||
|
|
ab0d5c58d4 | ||
|
|
4abf93e2aa | ||
|
|
7c8162a6f7 | ||
|
|
c4f190cfc4 | ||
|
|
d60ec48591 | ||
|
|
ba8fb4a6b7 | ||
|
|
ca1c2f7797 | ||
|
|
0d238417cb | ||
|
|
ddfc3a6567 | ||
|
|
6b29691e0e | ||
|
|
6b451dcc22 | ||
|
|
4d9498322e | ||
|
|
d1b888958b | ||
|
|
d6a00bc32d | ||
|
|
c408adeefa | ||
|
|
a5dd08cca7 | ||
|
|
30dc8176ff | ||
|
|
96fbac85ad | ||
|
|
9314dfd933 | ||
|
|
b3335c65fb | ||
|
|
fb0de62ef4 | ||
|
|
bf73938fd1 | ||
|
|
8d14b66583 | ||
|
|
92b0953081 | ||
|
|
e98ebfe9e1 | ||
|
|
889acea380 | ||
|
|
0b41457d4e | ||
|
|
fdcc8d4257 | ||
|
|
a7af5e72c6 | ||
|
|
677d609870 | ||
|
|
a429a146c7 | ||
|
|
ac4755459a | ||
|
|
ff37b589ff | ||
|
|
81e359d22e | ||
|
|
632c35daef | ||
|
|
f47f848236 | ||
|
|
cb87912203 | ||
|
|
9a1e103a7f | ||
|
|
8c7e93f829 | ||
|
|
488387f1de | ||
|
|
7db1f7786a | ||
|
|
067f25d4b8 | ||
|
|
42a3c56898 | ||
|
|
7b8677fd6c | ||
|
|
5eee39803f | ||
|
|
6259d1c897 | ||
|
|
60c03831fb | ||
|
|
9122aa2419 | ||
|
|
007680a183 | ||
|
|
c2b5595fae | ||
|
|
5939f24cd4 | ||
|
|
cfe61a35af | ||
|
|
c1298bdffd | ||
|
|
e187728f0c | ||
|
|
4a19c48667 | ||
|
|
63692ed59a | ||
|
|
4ba5e733fb | ||
|
|
20f5ba409f | ||
|
|
c65a7fb340 | ||
|
|
b13b94938a | ||
|
|
825d6bdc5c | ||
|
|
2451f024f6 | ||
|
|
62bb40a7df | ||
|
|
065df65cf1 | ||
|
|
6486938c59 | ||
|
|
9d7b2873bb | ||
|
|
3c1ab6ce25 | ||
|
|
446a69f7c0 | ||
|
|
5b454a3ff7 | ||
|
|
9ee1a526ed | ||
|
|
06f0374143 | ||
|
|
dde085094f | ||
|
|
f07bd23235 | ||
|
|
c0b90b398c | ||
|
|
92386f4e20 | ||
|
|
38f9686d68 | ||
|
|
349a9c9cea | ||
|
|
556ffb192f | ||
|
|
bfa36a7659 | ||
|
|
2d709758d0 | ||
|
|
509f3db371 | ||
|
|
bc95013ab4 | ||
|
|
8644d71820 | ||
|
|
2cdebeda29 | ||
|
|
a6d484236c | ||
|
|
131794e53c | ||
|
|
a4ea4791e7 | ||
|
|
6c0f00b4a1 | ||
|
|
c87b2e272b | ||
|
|
31e6aa2ae0 | ||
|
|
369a7fc455 | ||
|
|
e2fc0ab1aa | ||
|
|
494f1899fd | ||
|
|
b22f1ab715 | ||
|
|
156ea11537 | ||
|
|
baff788217 | ||
|
|
e43b8ef4e4 | ||
|
|
b8b44f062c | ||
|
|
504f5c4329 | ||
|
|
a4b8a8d88c | ||
|
|
afebc29440 | ||
|
|
148afc29aa | ||
|
|
572383f541 | ||
|
|
c2b16d768e | ||
|
|
e5c79cbb90 | ||
|
|
16ea2fd9c1 | ||
|
|
5541d55094 | ||
|
|
05887d5039 | ||
|
|
d1c6b80622 | ||
|
|
3b26a6c260 | ||
|
|
32b76bf448 | ||
|
|
6da1836f02 | ||
|
|
e01496e8bd | ||
|
|
93fe783b80 | ||
|
|
7b3f4d08f5 | ||
|
|
d2518df82c | ||
|
|
f11ab03112 | ||
|
|
d4207540bb | ||
|
|
592432611b | ||
|
|
cf01a215db | ||
|
|
ba46164b49 | ||
|
|
525309f277 | ||
|
|
343253b787 | ||
|
|
123450c3f2 | ||
|
|
5424716877 | ||
|
|
2a61360786 | ||
|
|
471eb8b0d9 | ||
|
|
d221073360 | ||
|
|
8b2785fdc9 | ||
|
|
d28f30dc4a | ||
|
|
23af9c6c9c | ||
|
|
38b293c204 | ||
|
|
b54e9efccf | ||
|
|
e3acb920f4 | ||
|
|
915b7ea3ad | ||
|
|
23f7bce427 | ||
|
|
5a238f1551 | ||
|
|
3821dd358a | ||
|
|
68e47c839b | ||
|
|
e59d839806 | ||
|
|
e737ace268 | ||
|
|
3a1f07492c | ||
|
|
58dbec76da | ||
|
|
c3643cf4e3 | ||
|
|
917ff685bd | ||
|
|
1d5cee6f43 | ||
|
|
27cd86fde7 | ||
|
|
cc73075d63 | ||
|
|
607e918ab1 | ||
|
|
1237ecc8f0 | ||
|
|
df6ea06f89 | ||
|
|
2461248ef6 | ||
|
|
9dc4551685 | ||
|
|
d650cfd3e7 | ||
|
|
c71eddb9d3 | ||
|
|
6f81ec383c | ||
|
|
af0948ea15 | ||
|
|
d702396d87 | ||
|
|
b2f09dbdb1 | ||
|
|
bbfce0f5be | ||
|
|
c65dfb85d2 | ||
|
|
b64875fd55 | ||
|
|
6ead1ceca6 | ||
|
|
f08003fcb2 | ||
|
|
102af22182 | ||
|
|
f934bdc61e | ||
|
|
ba405521ce | ||
|
|
171042b8d7 | ||
|
|
25bab8c10e | ||
|
|
da972edfca | ||
|
|
32c5534099 | ||
|
|
1f36e83c9d | ||
|
|
4e54c6de54 | ||
|
|
3bc4416655 | ||
|
|
0dc8e4389d | ||
|
|
34ec0f4795 | ||
|
|
faa52d7dd4 | ||
|
|
d797e5f1fe | ||
|
|
99952067c1 | ||
|
|
30ae89464e | ||
|
|
1ecbbbbcd5 | ||
|
|
186b86cb70 | ||
|
|
4c42083ffc | ||
|
|
dec753fc26 | ||
|
|
08c90c272b | ||
|
|
be8b28dd9d | ||
|
|
d0dc7ed301 | ||
|
|
abc24f2d52 | ||
|
|
53756ea140 | ||
|
|
dcb608f258 | ||
|
|
05acf31e47 | ||
|
|
bc5c3968d9 | ||
|
|
11c451c2e9 | ||
|
|
52c5e32ba5 | ||
|
|
37efc93e9c | ||
|
|
d63f61b903 | ||
|
|
49d53d9a8f | ||
|
|
79bf87754a | ||
|
|
e336cf5ddc | ||
|
|
e9638aee2e | ||
|
|
169e99b69e | ||
|
|
34b4d90b11 | ||
|
|
f89676d53f | ||
|
|
821857afa8 | ||
|
|
35a2ade954 | ||
|
|
a42d9c6ecb | ||
|
|
9f945d9940 | ||
|
|
852e840523 | ||
|
|
054b828396 | ||
|
|
2dac041006 | ||
|
|
2708ecfd47 | ||
|
|
9084ddbd06 | ||
|
|
fc153bb49a | ||
|
|
537a2c74aa | ||
|
|
dd6e99ab2e | ||
|
|
26834178e7 | ||
|
|
fd17e42c23 | ||
|
|
c1143c875d | ||
|
|
a822c93019 | ||
|
|
caca6d0c0e | ||
|
|
c1a1b0f145 | ||
|
|
33d4dd7729 | ||
|
|
0c37d91af3 | ||
|
|
ae590e7fde | ||
|
|
150b03427d | ||
|
|
7556b99dc0 | ||
|
|
960e4e13eb | ||
|
|
e7a60c6c85 | ||
|
|
72472c5836 | ||
|
|
ae8e8040d7 | ||
|
|
5ee4b94ec3 | ||
|
|
93f7671732 | ||
|
|
cf0afb0259 | ||
|
|
dbe33f9382 | ||
|
|
f31cf2e30f | ||
|
|
81715adb05 | ||
|
|
9174ec335c | ||
|
|
25f672cc55 | ||
|
|
9a44794dc9 | ||
|
|
46b52a1bbc | ||
|
|
5e7913fdd4 | ||
|
|
61424dbfec | ||
|
|
2671817ae9 | ||
|
|
165bf2fe6e | ||
|
|
feb6a33135 | ||
|
|
cd371dc207 | ||
|
|
2b3bd2bfce | ||
|
|
978137b143 | ||
|
|
f11cb5a498 | ||
|
|
0b58572f41 | ||
|
|
439e83f40e | ||
|
|
279f66ceaf | ||
|
|
8af879236e | ||
|
|
1cab58ac49 | ||
|
|
41fd6d4f4b | ||
|
|
13bcd723cf | ||
|
|
14cac5ce71 | ||
|
|
6a735e49b8 | ||
|
|
b443c9e764 | ||
|
|
90db32ee55 | ||
|
|
54bde86c7b | ||
|
|
10c6bfe3ad | ||
|
|
26ce1d86ab | ||
|
|
6ba1eae8f6 | ||
|
|
60e1c88eb4 | ||
|
|
661b81ab17 | ||
|
|
5d371bfec9 | ||
|
|
4910501ee0 | ||
|
|
9a2b2ecd9e | ||
|
|
9d03f40be2 | ||
|
|
9795beba89 | ||
|
|
212cdbb4d2 | ||
|
|
72bfb0047e | ||
|
|
9b9dca7bed | ||
|
|
a05621e857 | ||
|
|
c2feb6fff1 | ||
|
|
21bf3c3e3a | ||
|
|
6451371a75 | ||
|
|
5b1ce542d7 | ||
|
|
1f6308577b | ||
|
|
c8195f72a1 | ||
|
|
c653610215 | ||
|
|
09df42a755 | ||
|
|
687d70e9b6 | ||
|
|
ea929d167f | ||
|
|
fd1f4313ec | ||
|
|
81f6063736 | ||
|
|
4fdd655564 | ||
|
|
bb66a7c977 | ||
|
|
d4635ab165 | ||
|
|
48801f2892 | ||
|
|
0a89a775a2 | ||
|
|
a0006426cc | ||
|
|
eee4054da8 | ||
|
|
b16b107f3e | ||
|
|
138c48c739 | ||
|
|
5ce8d08e0f | ||
|
|
d1f1ed6a1a | ||
|
|
8c9ea90d50 | ||
|
|
e6f73073fe | ||
|
|
c45fe52a70 | ||
|
|
6a458547c3 | ||
|
|
739667f8a9 | ||
|
|
edec91e1e4 | ||
|
|
1e6eef89ec | ||
|
|
9d772496dd | ||
|
|
7a152fed1c | ||
|
|
00ad9d7f95 | ||
|
|
222b6d1220 | ||
|
|
145c6a7e78 | ||
|
|
f5b4a86801 | ||
|
|
46bcf938ed | ||
|
|
81cedfbfda | ||
|
|
61a3bd8102 | ||
|
|
9d5282b74f | ||
|
|
512c42f4df | ||
|
|
62e5efe87b | ||
|
|
429d63eebf | ||
|
|
2317a7d982 | ||
|
|
8a060dfa3f | ||
|
|
a4d4ae9b47 | ||
|
|
cf8790eefa | ||
|
|
2208b51f1b | ||
|
|
5584521fb0 | ||
|
|
7c4874bdad | ||
|
|
3e913b6649 | ||
|
|
1f129f4a23 | ||
|
|
c7a50ac7a5 | ||
|
|
940432e320 | ||
|
|
ee7218745e | ||
|
|
b91284b4aa | ||
|
|
f0a36329b1 | ||
|
|
ccefbc0dea | ||
|
|
5d34cee014 | ||
|
|
be904774dd | ||
|
|
bab809b9a6 | ||
|
|
39230a805c | ||
|
|
596b7c0112 | ||
|
|
97304d9d86 | ||
|
|
2d19d76675 | ||
|
|
919f267f7f | ||
|
|
7e0566cc12 | ||
|
|
046caa7632 | ||
|
|
4968c7a8a1 | ||
|
|
4a3e4df2bd | ||
|
|
3a111cf3af | ||
|
|
58df38f74e | ||
|
|
a5f16f0c52 | ||
|
|
ba7a51931d | ||
|
|
b32c2937ae | ||
|
|
017961e892 | ||
|
|
b8a1853692 | ||
|
|
58fe0c79d8 | ||
|
|
7cec2e50d5 | ||
|
|
7c1f560ae2 | ||
|
|
98ac6a06f2 | ||
|
|
4385fc75d0 | ||
|
|
274ebe7a52 | ||
|
|
1a5fb207ae | ||
|
|
fbe917d461 | ||
|
|
5c23e93547 | ||
|
|
cbc5bff1c0 | ||
|
|
d89bf9b635 | ||
|
|
83b2932e02 | ||
|
|
51eb9de9d0 | ||
|
|
a204e422a5 | ||
|
|
e5a215cbd6 | ||
|
|
a3e76334a6 | ||
|
|
b4fb0955a6 | ||
|
|
b2137f2746 | ||
|
|
cacfe67fe1 | ||
|
|
efe15cf2f0 | ||
|
|
a62a4ae02b | ||
|
|
54598f92c7 | ||
|
|
0f998615ad | ||
|
|
2b931dc7a2 | ||
|
|
4c33b99d39 | ||
|
|
e4419204cb | ||
|
|
23bbdc63ba | ||
|
|
adac5690b7 | ||
|
|
a232c32756 | ||
|
|
38cc0a7174 | ||
|
|
725a7e3121 | ||
|
|
e882356264 | ||
|
|
00dcc14df1 | ||
|
|
435a2631c9 | ||
|
|
270e93f6f0 | ||
|
|
9a8323cbb7 | ||
|
|
593c249bbd | ||
|
|
ccb47db3bb | ||
|
|
82d6ad0ef5 | ||
|
|
3c1a6bb8b1 | ||
|
|
00ff47855e | ||
|
|
45c5ec7091 | ||
|
|
4d78e0c63e | ||
|
|
aff2d21bad | ||
|
|
c82b1fc2c9 | ||
|
|
ca0b7a6b06 | ||
|
|
d31be357e5 | ||
|
|
a529a59abf | ||
|
|
cf656e9c21 | ||
|
|
7f1a15b6ba | ||
|
|
f3f9d0dfb7 | ||
|
|
2f26a32f96 | ||
|
|
6a571262fd | ||
|
|
dbdd799696 | ||
|
|
d83fa90606 | ||
|
|
522a5b3c5f | ||
|
|
3362f93964 | ||
|
|
af65c9d5d4 | ||
|
|
f0cdcd90ba | ||
|
|
19e3c97589 | ||
|
|
811ee4d26b | ||
|
|
c847988e10 | ||
|
|
1bb2e8c237 | ||
|
|
77ab3b8d3a | ||
|
|
87d8671995 | ||
|
|
ec4a70ad35 | ||
|
|
f0796055cc | ||
|
|
93ebd66853 | ||
|
|
965564853b | ||
|
|
6e523ed960 | ||
|
|
2d0257562f | ||
|
|
0b8cb3b6e1 | ||
|
|
50e00a3a89 | ||
|
|
1525d5ff16 | ||
|
|
427ad698fe | ||
|
|
94c121bcf7 | ||
|
|
13f0ef30c0 | ||
|
|
abc018e0d8 | ||
|
|
abe1ea78d0 | ||
|
|
229c809a4b | ||
|
|
6eabbe943b | ||
|
|
1b125df572 | ||
|
|
2ce0b72c44 | ||
|
|
8384b8b46b | ||
|
|
7c0bf2c015 | ||
|
|
6fee2f5a0d | ||
|
|
f7ad9e71e0 | ||
|
|
6880ebcbc2 | ||
|
|
04459ae68d | ||
|
|
23440d020f | ||
|
|
ab817c0962 | ||
|
|
6c391a7580 | ||
|
|
0c9447a94a | ||
|
|
b0aacda655 | ||
|
|
d5b2160c64 | ||
|
|
627f122b3f | ||
|
|
48f2a1ec3c | ||
|
|
99519090fb | ||
|
|
85bfde68a1 | ||
|
|
3e84a2f30f | ||
|
|
aa016bf1ac | ||
|
|
e8b0ecfede | ||
|
|
5a780dfde3 | ||
|
|
2c80b6f62d | ||
|
|
0ad64329f6 | ||
|
|
ace2b7fea4 | ||
|
|
f83cfc42b1 | ||
|
|
7785a06441 | ||
|
|
cfe72922ca | ||
|
|
8fc6c8107a | ||
|
|
06123f956a | ||
|
|
ed1cbe32ff | ||
|
|
6593eab9a0 | ||
|
|
6e0ae83685 | ||
|
|
40b651d661 | ||
|
|
3cc9bf7052 | ||
|
|
f4776626e4 | ||
|
|
1b497d31ff | ||
|
|
d4790beb24 | ||
|
|
60b1e284f3 | ||
|
|
8485ff8c76 | ||
|
|
8159f701f4 | ||
|
|
d794ff8bc9 | ||
|
|
26dccfe9a7 | ||
|
|
da8dc4ea03 | ||
|
|
b0c80a7a91 | ||
|
|
34ae76ab7f | ||
|
|
f4a33c5bfb | ||
|
|
7b198545bb | ||
|
|
ed6085d07c | ||
|
|
11a4d7696e | ||
|
|
c8befa5b9a | ||
|
|
422e86e0da | ||
|
|
0b0dbcb5d8 | ||
|
|
2ca0726cd7 | ||
|
|
41e2fd76d1 | ||
|
|
68ac16e5fb | ||
|
|
fa7f340cd3 | ||
|
|
ea59950b2c | ||
|
|
b825b36b60 | ||
|
|
6be41fec6d | ||
|
|
bafc8c88d5 | ||
|
|
8d3ec1afd0 | ||
|
|
306344e9c1 | ||
|
|
eb121c922b | ||
|
|
ec017bd1ae | ||
|
|
16ea2a0104 | ||
|
|
c88bcc1a3c | ||
|
|
57b1523d96 | ||
|
|
c794039b9d | ||
|
|
0176bda584 | ||
|
|
b7f9257b3c | ||
|
|
ad1caca45e | ||
|
|
51167e19fe | ||
|
|
b373b7936a | ||
|
|
07cda695bb | ||
|
|
671042cd20 | ||
|
|
d24a757609 | ||
|
|
0be5abceb9 | ||
|
|
f1475463fc | ||
|
|
0ed5acd6c6 | ||
|
|
dd7f8aac8d | ||
|
|
ba0d677c15 | ||
|
|
b504899714 | ||
|
|
065979e2e1 | ||
|
|
8f8119509d | ||
|
|
6b69ed2174 | ||
|
|
01cda8a130 | ||
|
|
8ad1c58f9e | ||
|
|
e9504b7010 | ||
|
|
9f3551f43b | ||
|
|
26a872be94 | ||
|
|
54067db386 | ||
|
|
34a1896ea8 | ||
|
|
67d9762773 | ||
|
|
6e932a24d2 | ||
|
|
47daf8e7f7 | ||
|
|
9d4b16d03f | ||
|
|
673b85f129 | ||
|
|
da7864b28c | ||
|
|
6fe68dbc7a | ||
|
|
d03b32d249 | ||
|
|
3982303fcc | ||
|
|
aa06a3c111 | ||
|
|
dc8eb317dd | ||
|
|
8402b9ea53 | ||
|
|
9186fa5551 | ||
|
|
d061bafaa2 | ||
|
|
ba89ad7450 | ||
|
|
b73ebb9cf5 | ||
|
|
49d84fccde | ||
|
|
b0b71910a5 | ||
|
|
bf83aed43b | ||
|
|
1a0b0e748c | ||
|
|
0912043248 | ||
|
|
cfbcd9faa8 | ||
|
|
5df2d3db33 | ||
|
|
c654ca4506 | ||
|
|
c780a7471b | ||
|
|
095a3ef28c | ||
|
|
574b464a3c | ||
|
|
176079b678 | ||
|
|
8db7756d2e | ||
|
|
7789038409 | ||
|
|
53abf506fc | ||
|
|
183bae0825 | ||
|
|
c591954fc3 | ||
|
|
65828e0e36 | ||
|
|
e5d8f83dbf | ||
|
|
c896f58bbd | ||
|
|
3f0cc56665 | ||
|
|
50c7dd7d48 | ||
|
|
eb89d45937 | ||
|
|
cb31ce3049 | ||
|
|
ec90bb2e8a | ||
|
|
5cfae1ea75 | ||
|
|
4b827adfee | ||
|
|
c0a29c4c74 | ||
|
|
9835813679 | ||
|
|
c7a99769ce | ||
|
|
19814ecf87 | ||
|
|
ebd4016fb3 | ||
|
|
960e918e61 | ||
|
|
2cf21fd0ad | ||
|
|
15e3178721 | ||
|
|
052aa8afe2 | ||
|
|
699b886d68 | ||
|
|
3634cb712d | ||
|
|
f98513dfc2 | ||
|
|
7ce75bdb52 | ||
|
|
97a0a707d7 | ||
|
|
b243c522b1 | ||
|
|
1018cca4eb | ||
|
|
1e0c701733 | ||
|
|
247f3ac2c4 | ||
|
|
050ed718e5 | ||
|
|
9b3d294464 | ||
|
|
db0029c32b | ||
|
|
1a13d32452 | ||
|
|
6892e511fe | ||
|
|
10b9f2224f | ||
|
|
ccef2485b2 | ||
|
|
8c07fcca24 | ||
|
|
cf2d8d47e6 | ||
|
|
7685fd03c6 | ||
|
|
6db6e858c4 | ||
|
|
661bf33982 | ||
|
|
f8d7daa14f | ||
|
|
f8d293493f | ||
|
|
0a82229ac1 | ||
|
|
025f6d9524 | ||
|
|
c34bb7912c | ||
|
|
9da5ef4743 | ||
|
|
0fe05ce07d | ||
|
|
1549998a19 | ||
|
|
e185b87195 | ||
|
|
63e5f343a3 | ||
|
|
81dde53f5a | ||
|
|
8488b9053d | ||
|
|
ed376e475d | ||
|
|
24d3ba8680 | ||
|
|
13b69a14d8 | ||
|
|
8638f7303a | ||
|
|
3c57c461b5 | ||
|
|
30728879be | ||
|
|
edd447527d | ||
|
|
40c8b7db76 | ||
|
|
1609be6d49 | ||
|
|
1917349c4a | ||
|
|
cd14dea021 | ||
|
|
77acc999cd | ||
|
|
1279f040da | ||
|
|
0f71b0a408 | ||
|
|
ada09f1928 | ||
|
|
839fb4ff58 | ||
|
|
24d077fbce | ||
|
|
16f8c025cd | ||
|
|
b5a75c3250 | ||
|
|
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 | ||
|
|
36be369901 | ||
|
|
b3673e93d7 | ||
|
|
985ef4518f | ||
|
|
096f033954 | ||
|
|
92f4c0c001 | ||
|
|
10f2c105b1 | ||
|
|
34e343ec66 | ||
|
|
aec56c63be | ||
|
|
c6d6e500fb | ||
|
|
a3c1640fb7 | ||
|
|
0a695dd442 | ||
|
|
64c960041b | ||
|
|
f3048eb574 | ||
|
|
48f38b8940 | ||
|
|
a535c6917e | ||
|
|
0432514ccf | ||
|
|
a9baae4e98 | ||
|
|
0e44abe741 | ||
|
|
40e44e6dd7 | ||
|
|
02413d165a |
14
.github/ISSUE_TEMPLATE.md
vendored
14
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,14 +0,0 @@
|
||||
### If this is a support request:
|
||||
|
||||
**Please attempt to solve the problem on your own before opening an issue.**
|
||||
Between old issues, StackOverflow, and Google, you should be able to find
|
||||
solutions to most of the common problems.
|
||||
|
||||
Include at least:
|
||||
1. Steps to reproduce the issue (e.g. the command you ran)
|
||||
2. The unexpected behavior that occurred (e.g. error messages or screenshots)
|
||||
3. The environment (e.g. operating system and version of manim)
|
||||
|
||||
|
||||
### If this is a feature request:
|
||||
Include the motivation for making this change.
|
||||
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the bug
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**Code**:
|
||||
<!-- The code you run which reflect the bug. -->
|
||||
|
||||
**Wrong display or Error traceback**:
|
||||
<!-- the wrong display result of the code you run, or the error Traceback -->
|
||||
|
||||
### Additional context
|
||||
<!-- Add any other context about the problem here. -->
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ask A Question
|
||||
url: https://github.com/3b1b/manim/discussions/categories/q-a
|
||||
about: Please ask questions you encountered here.
|
||||
23
.github/ISSUE_TEMPLATE/error-when-using.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/error-when-using.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Error when using
|
||||
about: The error you encountered while using manim
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the error
|
||||
<!-- A clear and concise description of what you want to make. -->
|
||||
|
||||
### Code and Error
|
||||
**Code**:
|
||||
<!-- The code you run -->
|
||||
|
||||
**Error**:
|
||||
<!-- The error traceback you get when run your code -->
|
||||
|
||||
### Environment
|
||||
**OS System**:
|
||||
**manim version**: master <!-- make sure you are using the latest version of master branch -->
|
||||
**python version**:
|
||||
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,9 +1,18 @@
|
||||
Thanks for contributing to manim!
|
||||
<!-- Thanks for contributing to manim!
|
||||
Please ensure that your pull request works with the latest version of manim.
|
||||
-->
|
||||
|
||||
**Please ensure that your pull request works with the latest version of manim.**
|
||||
You should also include:
|
||||
## Motivation
|
||||
<!-- Outline your motivation: In what way do your changes improve the library? -->
|
||||
|
||||
1. The motivation for making this change (or link the relevant issues)
|
||||
2. How you tested the new behavior (e.g. a minimal working example, before/after
|
||||
screenshots, gifs, commands, etc.) This is rather informal at the moment, but
|
||||
the goal is to show us how you know the pull request works as intended.
|
||||
## Proposed changes
|
||||
<!-- What you changed in those files -->
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
## Test
|
||||
<!-- How do you test your changes -->
|
||||
**Code**:
|
||||
|
||||
**Result**:
|
||||
40
.github/workflows/docs.yml
vendored
Normal file
40
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: docs
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
name: build up document and deploy
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Install sphinx and manim env
|
||||
run: |
|
||||
pip3 install --upgrade pip
|
||||
sudo apt install python3-setuptools libpango1.0-dev
|
||||
pip3 install -r docs/requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
- name: Build document with Sphinx
|
||||
run: |
|
||||
cd docs
|
||||
export PATH="$PATH:/home/runner/.local/bin"
|
||||
export SPHINXBUILD="python3 -m sphinx"
|
||||
make html
|
||||
|
||||
- name: Deploy to GitHub pages
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.DOC_DEPLOY_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: docs/build/html
|
||||
30
.github/workflows/publish.yml
vendored
Normal file
30
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.8'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine build
|
||||
|
||||
- name: Build and publish
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
python -m build
|
||||
twine upload dist/*
|
||||
177
.gitignore
vendored
177
.gitignore
vendored
@@ -1,27 +1,152 @@
|
||||
*.pyc
|
||||
*.bak
|
||||
.DS_Store
|
||||
homeless.py
|
||||
playground.py
|
||||
cairo_test.py
|
||||
mayavi_test.py
|
||||
random_scenes/
|
||||
files/
|
||||
ben_playground.py
|
||||
ben_cairo_test.py
|
||||
.floo
|
||||
.flooignore
|
||||
.vscode
|
||||
.vs
|
||||
*.xml
|
||||
*.iml
|
||||
media
|
||||
manim.sublime-project
|
||||
manim.sublime-workspace
|
||||
.eggs/
|
||||
build/
|
||||
dist/
|
||||
manim.egg-info/
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
primes.py
|
||||
/media_dir.txt
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
manimlib.egg-info/
|
||||
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
pytestdebug.log
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
doc/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
pythonenv*
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# profiling data
|
||||
.prof
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
# Custom exclusions:
|
||||
.DS_Store
|
||||
|
||||
# For manim
|
||||
/videos
|
||||
/custom_config.yml
|
||||
|
||||
30
.travis.yml
30
.travis.yml
@@ -1,30 +0,0 @@
|
||||
language: python
|
||||
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
|
||||
python: "3.7"
|
||||
cache: pip
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
install:
|
||||
- pip install --upgrade pip
|
||||
- pip install -r requirements.txt
|
||||
- pip install flake8
|
||||
before_script:
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
- flake8 manimlib/ --count --select=E9,F63,F72,F82 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
- flake8 manimlib/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
script:
|
||||
- python setup.py test
|
||||
- python setup.py bdist_wheel
|
||||
after_success:
|
||||
- test $TRAVIS_BRANCH = "master" && test $TRAVIS_PULL_REQUEST = "false" && travis/build_docs.sh
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: eulertour
|
||||
on:
|
||||
tags: true
|
||||
password:
|
||||
secure: j5M2hiJo9kDWJhl0/iSuIQmfd2G2O1Qoc455AkUPMCheAcALnX9xJgFsYBmqfgOXTCtUCQf52XGdOIG4o4s5TY340NZ9eLKI9cWae+sTeSrDCkdwChUilm3D0jQf1FWPUf9ywScwGi20m0sRtzxEJyTuX+JMFd7PIa8bFoDXWPtEjoFOOJrfBusMsANzrI+j+vIMdJ48lc1J8UsQdZapwusTrYU9s12JLhKBPLavmaDKf0HDAJdEhFQ9SaINdkiW/QY8qbfJ/MVu5jHai168zXjD/IaswxoKqCO1G+fWlOq3KwVhG7gI7rwhnnuF+wcA7yLAaMdo0CjO2V7z15S6cG721V2Il2IIh1jq0F8irSH1ZOLOkv/fFk9hkSUQyEU0i8k4m1wE9L47a6GP/66+b+gI91PGfxBOqq4gE/1BdZJqceh0qc13KpcehtYrQwR05bSw0Ye5OoTkqAnCeON0B0Ur4ejfHd3TzkjgB06fw76cZtjAK8f/YjB3KyNCvysOixgzE4tRxlY92yX/tAKZ3iX3yD0MjsinSfwo52N5sIEaCS/FmPRMhJOQBa6ftkfbcUNQBTG9G3b134XXF/LbC4vBloCaTm5VSXagta+oY3SFKQxPAZXx7X+wcFGjqxDjZXG1e66QnA2JJH4aBDsRfSXmUtD8MblwFYdcCJWz+Ck=
|
||||
19
Dockerfile
19
Dockerfile
@@ -1,19 +0,0 @@
|
||||
FROM python:3.7
|
||||
RUN apt-get update \
|
||||
&& apt-get install -qqy --no-install-recommends \
|
||||
apt-utils \
|
||||
ffmpeg \
|
||||
sox \
|
||||
libcairo2-dev \
|
||||
texlive \
|
||||
texlive-fonts-extra \
|
||||
texlive-latex-extra \
|
||||
texlive-latex-recommended \
|
||||
texlive-science \
|
||||
tipa \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY . /manim
|
||||
RUN cd /manim \
|
||||
&& python setup.py sdist \
|
||||
&& python -m pip install dist/manimlib*
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
@@ -1,11 +1,6 @@
|
||||
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.
|
||||
|
||||
Any other file of this project is available under the MIT license as follow:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 3Blue1Brown LLC
|
||||
Copyright (c) 2020 3Blue1Brown LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
2
MANIFEST.in
Normal file
2
MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
graft manimlib
|
||||
recursive-exclude manimlib *.pyc *.DS_Store
|
||||
177
README.md
177
README.md
@@ -1,156 +1,117 @@
|
||||
<img src="logo/cropped.png"/>
|
||||
<p align="center">
|
||||
<a href="https://github.com/3b1b/manim">
|
||||
<img src="https://raw.githubusercontent.com/3b1b/manim/master/logo/cropped.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[](https://travis-ci.org/3b1b/manim)
|
||||
[](https://www.eulertour.com/learn/manim/)
|
||||
[](https://pypi.org/project/manimgl/)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
[](https://www.reddit.com/r/manim/)
|
||||
[](https://discord.gg/mMRrZQW)
|
||||
[](https://www.reddit.com/r/manim/)
|
||||
[](https://discord.com/invite/bYCyhM9Kz2)
|
||||
[](https://3b1b.github.io/manim/)
|
||||
|
||||
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/).
|
||||
Manim is an engine for precise programmatic animations, designed for creating explanatory math videos.
|
||||
|
||||
Note, there are two versions of manim. This repository began as a personal project by the author of [3Blue1Brown](https://www.3blue1brown.com/) for the purpose of animating those videos, with video-specific code available [here](https://github.com/3b1b/videos). In 2020 a group of developers forked it into what is now the [community edition](https://github.com/ManimCommunity/manim/), with a goal of being more stable, better tested, quicker to respond to community contributions, and all around friendlier to get started with. See [this page](https://docs.manim.community/en/stable/installation/versions.html?highlight=OpenGL#which-version-to-use) for more details.
|
||||
|
||||
## Installation
|
||||
Manim runs on python 3.7. You can install it from PyPI via pip
|
||||
> **WARNING:** These instructions are for ManimGL _only_. Trying to use these instructions to install [ManimCommunity/manim](https://github.com/ManimCommunity/manim) or instructions there to install this version will cause problems. You should first decide which version you wish to install, then only follow the instructions for your desired version.
|
||||
>
|
||||
> **Note**: To install manim directly through pip, please pay attention to the name of the installed package. This repository is ManimGL of 3b1b. The package name is `manimgl` instead of `manim` or `manimlib`. Please use `pip install manimgl` to install the version in this repository.
|
||||
|
||||
```sh
|
||||
pip3 install manimlib
|
||||
```
|
||||
Manim runs on Python 3.6 or higher (Python 3.8 is recommended).
|
||||
|
||||
System requirements are [cairo](https://www.cairographics.org), [ffmpeg](https://www.ffmpeg.org), [sox](http://sox.sourceforge.net), [latex](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
System requirements are [FFmpeg](https://ffmpeg.org/), [OpenGL](https://www.opengl.org/) and [LaTeX](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
For Linux, [Pango](https://pango.gnome.org) along with its development headers are required. See instruction [here](https://github.com/ManimCommunity/ManimPango#building).
|
||||
|
||||
You can now use it via the `manim` command. For example:
|
||||
|
||||
```sh
|
||||
manim my_project.py MyScene
|
||||
```
|
||||
|
||||
For more options, take a look at the “Using manim“ sections further below.
|
||||
|
||||
### Directly
|
||||
|
||||
```sh
|
||||
# Install manimgl
|
||||
pip install manimgl
|
||||
|
||||
# Try it out
|
||||
manimgl
|
||||
```
|
||||
|
||||
For more options, take a look at the [Using manim](#using-manim) sections further below.
|
||||
|
||||
If you want to hack on manimlib itself, clone this repository and in that directory execute:
|
||||
|
||||
```sh
|
||||
# Install python requirements
|
||||
python3 -m pip install -r requirements.txt
|
||||
# Install manimgl
|
||||
pip install -e .
|
||||
|
||||
# Try it out
|
||||
python3 ./manim.py example_scenes.py SquareToCircle -pl
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
# or
|
||||
manim-render example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
### 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.
|
||||
```sh
|
||||
pip3 install C:\path\to\wheel\pycairo‑1.18.0‑cp37‑cp37m‑win32.whl
|
||||
```
|
||||
3. Install a LaTeX distribution. [MiKTeX](https://miktex.org/download) is recommended.
|
||||
|
||||
4. [Install SoX](https://sourceforge.net/projects/sox/files/sox/).
|
||||
|
||||
5. Install the remaining Python packages. Make sure that ``pycairo==1.17.1`` is changed to ``pycairo==1.18.0`` in requirements.txt.
|
||||
2. Install a LaTeX distribution. [MiKTeX](https://miktex.org/download) is recommended.
|
||||
3. Install the remaining Python packages.
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
pip3 install -r requirements.txt
|
||||
python3 manim.py example_scenes.py SquareToCircle -pl
|
||||
pip install -e .
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
### Mac OSX
|
||||
|
||||
1. Install FFmpeg, LaTeX in terminal using homebrew.
|
||||
```sh
|
||||
brew install ffmpeg mactex
|
||||
```
|
||||
|
||||
2. Install latest version of manim using these command.
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
pip install -e .
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
## Anaconda Install
|
||||
|
||||
* Install sox and latex as above.
|
||||
* Create a conda environment using `conda env create -f environment.yml`
|
||||
* **WINDOWS ONLY** Install `pyreadline` via `pip install pyreadline`.
|
||||
1. Install LaTeX as above.
|
||||
2. Create a conda environment using `conda create -n manim python=3.8`.
|
||||
3. Activate the environment using `conda activate manim`.
|
||||
4. Install manimgl using `pip install -e .`.
|
||||
|
||||
|
||||
### Using `virtualenv` and `virtualenvwrapper`
|
||||
After installing `virtualenv` and `virtualenvwrapper`
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
mkvirtualenv -a manim -r requirements.txt manim
|
||||
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.
|
||||
`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
|
||||
```sh
|
||||
INPUT_PATH=/path/to/dir/containing/source/code \
|
||||
OUTPUT_PATH=/path/to/output/ \
|
||||
docker-compose run manim example_scenes.py SquareToCircle -l
|
||||
```
|
||||
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`.
|
||||
|
||||
`-p` won't work as manim would look for video player in the container system, which it does not have.
|
||||
|
||||
The first time you execute the above command, Docker will pull the image from Docker Hub and cache it. Any subsequent runs until the image is evicted will use the cached image.
|
||||
Note that the image doesn't have any development tools installed and can't preview animations. Its purpose is building and testing only.
|
||||
|
||||
## Using manim
|
||||
Try running the following:
|
||||
```sh
|
||||
python3 -m manim example_scenes.py SquareToCircle -pl
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
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:
|
||||
This should pop up a window playing a simple scene.
|
||||
|
||||
Some useful flags include:
|
||||
* `-w` to write the scene to a file
|
||||
* `-o` to write the scene to a file and open the result
|
||||
* `-s` to skip to the end and just show the final frame.
|
||||
* `-so` will save the final frame to an image and show it
|
||||
* `-n <number>` to skip ahead to the `n`'th animation of a scene.
|
||||
* `-f` to show the file in finder (for OSX).
|
||||
* `-f` to make the playback window fullscreen
|
||||
|
||||
Set `MEDIA_DIR` environment variable to specify where the image and animation files will be written.
|
||||
Take a look at custom_config.yml for further configuration. To add your customization, you can either edit this file, or add another file by the same name "custom_config.yml" to whatever directory you are running manim from. For example [this is the one](https://github.com/3b1b/videos/blob/master/custom_config.yml) for 3blue1brown videos. There you can specify where videos should be output to, where manim should look for image files and sounds you want to read in, and other defaults regarding style and video quality.
|
||||
|
||||
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.
|
||||
Look through the [example scenes](https://3b1b.github.io/manim/getting_started/example_scenes.html) to get a sense of how it is used, and feel free to look through the code behind [3blue1brown videos](https://github.com/3b1b/videos) for a much larger set of example. Note, however, that developments are often made to the library without considering backwards compatibility with those old videos. 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.
|
||||
|
||||
### Documentation
|
||||
Documentation is in progress at [manim.readthedocs.io](https://manim.readthedocs.io).
|
||||
Documentation is in progress at [3b1b.github.io/manim](https://3b1b.github.io/manim/). And there is also a Chinese version maintained by [**@manim-kindergarten**](https://manim.org.cn): [docs.manim.org.cn](https://docs.manim.org.cn/) (in Chinese).
|
||||
|
||||
### Walkthrough
|
||||
Todd Zimmerman put together a [tutorial](https://talkingphysics.wordpress.com/2019/01/08/getting-started-animating-with-manim-and-python-3-7/) on getting started with manim, which has been updated to run on python 3.7.
|
||||
|
||||
### 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).
|
||||
[manim-kindergarten](https://github.com/manim-kindergarten/) wrote and collected some useful extra classes and some codes of videos in [manim_sandbox repo](https://github.com/manim-kindergarten/manim_sandbox).
|
||||
|
||||
|
||||
## Contributing
|
||||
Is always welcome. In particular, there is a dire need for tests and documentation.
|
||||
Is always welcome. As mentioned above, the [community edition](https://github.com/ManimCommunity/manim) has the most active ecosystem for contributions, with testing and continuous integration, but pull requests are welcome here too. Please explain the motivation for a given change and examples of its effect.
|
||||
|
||||
|
||||
## License
|
||||
All files in the directories active_projects and old_projects, 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.
|
||||
This project falls under the MIT license.
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
def get_factors(n):
|
||||
return filter(
|
||||
lambda k: (n % k) == 0,
|
||||
range(1, n)
|
||||
)
|
||||
|
||||
|
||||
class AmicableNumbers(Scene):
|
||||
CONFIG = {
|
||||
"n1": 28,
|
||||
"n2": 284,
|
||||
"colors": [
|
||||
BLUE_C,
|
||||
BLUE_B,
|
||||
BLUE_D,
|
||||
GREY_BROWN,
|
||||
GREEN_C,
|
||||
GREEN_B,
|
||||
GREEN_D,
|
||||
GREY,
|
||||
]
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_n1()
|
||||
self.show_n1_factors()
|
||||
self.show_n1_factor_sum()
|
||||
self.show_n2_factors()
|
||||
self.show_n2_factor_sum()
|
||||
|
||||
def show_n1(self):
|
||||
dots = VGroup(*[Dot() for x in range(self.n1)])
|
||||
dots.set_color(BLUE)
|
||||
dots.set_sheen(0.2, UL)
|
||||
dots.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
dots.set_width(FRAME_WIDTH - 1)
|
||||
|
||||
rects = self.get_all_factor_rectangles(dots)
|
||||
rects.rotate(90 * DEGREES)
|
||||
rects.arrange(RIGHT, buff=MED_SMALL_BUFF, aligned_edge=DOWN)
|
||||
for rect in rects:
|
||||
rect.first_col.set_stroke(WHITE, 3)
|
||||
rects.set_height(FRAME_HEIGHT - 1)
|
||||
|
||||
self.add(rects)
|
||||
|
||||
def show_n1_factors(self):
|
||||
pass
|
||||
|
||||
def show_n1_factor_sum(self):
|
||||
pass
|
||||
|
||||
def show_n2_factors(self):
|
||||
pass
|
||||
|
||||
def show_n2_factor_sum(self):
|
||||
pass
|
||||
|
||||
#
|
||||
def show_factors(self, dot_group):
|
||||
pass
|
||||
|
||||
def get_all_factor_rectangles(self, dot_group):
|
||||
n = len(dot_group)
|
||||
factors = get_factors(n)
|
||||
colors = it.cycle(self.colors)
|
||||
result = VGroup()
|
||||
for k, color in zip(factors, colors):
|
||||
group = dot_group.copy()
|
||||
group.set_color(color)
|
||||
group.arrange_in_grid(n_rows=k, buff=SMALL_BUFF)
|
||||
group.first_col = group[::(n // k)]
|
||||
result.add(group)
|
||||
return result
|
||||
@@ -1,107 +0,0 @@
|
||||
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 *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
IntroducePendulum,
|
||||
MultiplePendulumsOverlayed,
|
||||
PeriodFormula,
|
||||
FormulasAreLies,
|
||||
MediumAnglePendulum,
|
||||
MediumHighAnglePendulum,
|
||||
HighAnglePendulum,
|
||||
LowAnglePendulum,
|
||||
SomeOfYouWatching,
|
||||
SmallAngleApproximationTex,
|
||||
VeryLowAnglePendulum,
|
||||
FormulasAreLies,
|
||||
TourOfDifferentialEquations,
|
||||
WherePendulumLeads,
|
||||
LongDoublePendulum,
|
||||
# FollowThisThread,
|
||||
StrogatzQuote,
|
||||
ShowHorizontalDashedLine,
|
||||
RabbitFoxPopulations,
|
||||
RabbitFoxEquation,
|
||||
# Something...
|
||||
ShowSimpleTrajectory,
|
||||
SimpleProjectileEquation,
|
||||
SimpleProjectileEquationVGraphFreedom,
|
||||
ShowGravityAcceleration,
|
||||
UniversalGravityLawSymbols,
|
||||
ExampleTypicalODE,
|
||||
AnalyzePendulumForce,
|
||||
ShowSineValues,
|
||||
BuildUpEquation,
|
||||
AirResistanceBrace,
|
||||
ShowDerivativeVideo,
|
||||
SubtleAirCurrents,
|
||||
SimpleDampenedPendulum,
|
||||
DefineODE,
|
||||
SecondOrderEquationExample,
|
||||
ODEvsPDEinFrames,
|
||||
ProveTeacherWrong,
|
||||
SetAsideSeekingSolution,
|
||||
#
|
||||
WriteInRadians,
|
||||
XEqLThetaToCorner,
|
||||
ComingUp,
|
||||
InputLabel,
|
||||
SoWhatIsThetaThen,
|
||||
ReallyHardToSolve,
|
||||
ReasonForSolution,
|
||||
PhysicistPhaseSpace,
|
||||
GleickQuote,
|
||||
SpectrumOfStartingStates,
|
||||
WritePhaseFlow,
|
||||
AskAboutStability,
|
||||
LoveExample,
|
||||
PassageOfTime,
|
||||
LovePhaseSpace,
|
||||
ComparePhysicsToLove,
|
||||
FramesComparingPhysicsToLove,
|
||||
SetupToTakingManyTinySteps,
|
||||
ShowClutterPrevention,
|
||||
# VisualizeHeightSlopeCurvature,
|
||||
VisualizeStates,
|
||||
ReferencePiCollisionStateSpaces,
|
||||
IntroduceVectorField,
|
||||
XComponentArrows,
|
||||
BreakingSecondOrderIntoTwoFirstOrder,
|
||||
ShowPendulumPhaseFlow,
|
||||
ShowHighVelocityCase,
|
||||
TweakMuInFormula,
|
||||
TweakMuInVectorField,
|
||||
FromODEToVectorField,
|
||||
LorenzVectorField,
|
||||
ThreeBodiesInSpace,
|
||||
AltThreeBodiesInSpace,
|
||||
TwoBodiesInSpace,
|
||||
TwoBodiesWithZPart,
|
||||
ThreeBodyTitle,
|
||||
ThreeBodySymbols,
|
||||
#
|
||||
HighAmplitudePendulum,
|
||||
WritePhaseSpace,
|
||||
#
|
||||
AskAboutActuallySolving,
|
||||
WriteODESolvingCode,
|
||||
TakeManyTinySteps,
|
||||
ManyStepsFromDifferentStartingPoints,
|
||||
InaccurateComputation,
|
||||
HungerForExactness,
|
||||
ShowRect,
|
||||
ShowSquare,
|
||||
JumpToThisPoint,
|
||||
ThreeBodyEquation,
|
||||
ItGetsWorse,
|
||||
ChaosTitle,
|
||||
RevisitQuote,
|
||||
EndScreen,
|
||||
Thumbnail,
|
||||
]
|
||||
@@ -1,41 +0,0 @@
|
||||
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 *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part2"
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
BrownianMotion,
|
||||
BlackScholes,
|
||||
ContrastChapters1And2,
|
||||
FourierSeriesIntro,
|
||||
FourierSeriesIntroBackground20,
|
||||
ExplainCircleAnimations,
|
||||
# FourierSeriesIntroBackground4,
|
||||
# FourierSeriesIntroBackground8,
|
||||
# FourierSeriesIntroBackground12,
|
||||
TwoDBodyWithManyTemperatures,
|
||||
TwoDBodyWithManyTemperaturesGraph,
|
||||
TwoDBodyWithManyTemperaturesContour,
|
||||
BringTwoRodsTogether,
|
||||
ShowEvolvingTempGraphWithArrows,
|
||||
# TodaysTargetWrapper,
|
||||
WriteHeatEquation,
|
||||
ReactionsToInitialHeatEquation,
|
||||
TalkThrough1DHeatGraph,
|
||||
ShowCubeFormation,
|
||||
CompareInputsOfGeneralCaseTo1D,
|
||||
ContrastXChangesToTChanges,
|
||||
ShowPartialDerivativeSymbols,
|
||||
WriteHeatEquation,
|
||||
ShowCurvatureToRateOfChangeIntuition,
|
||||
ContrastPDEToODE,
|
||||
TransitionToTempVsTime,
|
||||
Show1DAnd3DEquations,
|
||||
#
|
||||
AskAboutWhereEquationComesFrom,
|
||||
DiscreteSetup,
|
||||
]
|
||||
@@ -1,70 +0,0 @@
|
||||
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 *
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part3"
|
||||
SCENES_IN_ORDER = [
|
||||
LastChapterWrapper,
|
||||
ThreeConstraints,
|
||||
OceanOfPossibilities,
|
||||
ThreeMainObservations,
|
||||
SimpleCosExpGraph,
|
||||
AddMultipleSolutions,
|
||||
FourierSeriesIllustraiton,
|
||||
BreakDownAFunction,
|
||||
SineCurveIsUnrealistic,
|
||||
AnalyzeSineCurve,
|
||||
EquationAboveSineAnalysis,
|
||||
ExponentialDecay,
|
||||
InvestmentGrowth,
|
||||
GrowingPileOfMoney,
|
||||
CarbonDecayCurve,
|
||||
CarbonDecayingInMammoth,
|
||||
SineWaveScaledByExp,
|
||||
ShowSinExpDerivatives,
|
||||
IfOnly,
|
||||
BoundaryConditionInterlude,
|
||||
BoundaryConditionReference,
|
||||
GiantCross,
|
||||
SimulateRealSineCurve,
|
||||
DerivativesOfLinearFunction,
|
||||
StraightLine3DGraph,
|
||||
SimulateLinearGraph,
|
||||
EmphasizeBoundaryPoints,
|
||||
ShowNewRuleAtDiscreteBoundary,
|
||||
DiscreteEvolutionPoint25,
|
||||
DiscreteEvolutionPoint1,
|
||||
FlatEdgesForDiscreteEvolution,
|
||||
FlatEdgesForDiscreteEvolutionTinySteps,
|
||||
FlatEdgesContinuousEvolution,
|
||||
FlatAtBoundaryWords,
|
||||
SlopeToHeatFlow,
|
||||
CloserLookAtStraightLine,
|
||||
WriteOutBoundaryCondition,
|
||||
SoWeGotNowhere,
|
||||
ManipulateSinExpSurface,
|
||||
HeatEquationFrame,
|
||||
ShowFreq1CosExpDecay,
|
||||
ShowFreq2CosExpDecay,
|
||||
ShowFreq4CosExpDecay,
|
||||
CompareFreqDecays1to2,
|
||||
CompareFreqDecays1to4,
|
||||
CompareFreqDecays2to4,
|
||||
ShowHarmonics,
|
||||
ShowHarmonicSurfaces,
|
||||
|
||||
# SimpleCosExpGraph,
|
||||
# AddMultipleSolutions,
|
||||
# IveHeardOfThis,
|
||||
# FourierSeriesOfLineIllustration,
|
||||
# InFouriersShoes,
|
||||
]
|
||||
|
||||
PART_4_SCENES = [
|
||||
FourierSeriesIllustraiton,
|
||||
FourierNameIntro,
|
||||
CircleAnimationOfF,
|
||||
]
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,515 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SomeOfYouWatching(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"background_color": DARKER_GREY,
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
screen = self.screen
|
||||
screen.scale(1.25, about_edge=UL)
|
||||
screen.set_fill(BLACK, 1)
|
||||
self.add(screen)
|
||||
|
||||
self.teacher.change("raise_right_hand")
|
||||
for student in self.students:
|
||||
student.change("pondering", screen)
|
||||
|
||||
self.student_says(
|
||||
"Well...yeah",
|
||||
target_mode="tease"
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FormulasAreLies(PiCreatureScene):
|
||||
def construct(self):
|
||||
you = self.pi_creature
|
||||
t2c = {
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
"\\theta_0": WHITE,
|
||||
"\\sqrt{\\,": WHITE,
|
||||
}
|
||||
kwargs = {"tex_to_color_map": t2c}
|
||||
period_eq = TexMobject(
|
||||
"\\text{Period} = 2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**kwargs
|
||||
)
|
||||
theta_eq = TexMobject(
|
||||
"\\theta(t) = \\theta_0 \\cos\\left("
|
||||
"\\sqrt{\\,{L} / {g}} \\cdot t"
|
||||
"\\right)",
|
||||
**kwargs
|
||||
)
|
||||
equations = VGroup(theta_eq, period_eq)
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
|
||||
for eq in period_eq, theta_eq:
|
||||
i = eq.index_of_part_by_tex("\\sqrt")
|
||||
eq.sqrt_part = eq[i:i + 4]
|
||||
|
||||
theta0 = theta_eq.get_part_by_tex("\\theta_0")
|
||||
theta0_words = TextMobject("Starting angle")
|
||||
theta0_words.next_to(theta0, UL)
|
||||
theta0_words.shift(UP + 0.5 * RIGHT)
|
||||
arrow = Arrow(
|
||||
theta0_words.get_bottom(),
|
||||
theta0,
|
||||
color=WHITE,
|
||||
tip_length=0.25,
|
||||
)
|
||||
|
||||
bubble = SpeechBubble()
|
||||
bubble.pin_to(you)
|
||||
bubble.write("Lies!")
|
||||
bubble.content.scale(2)
|
||||
bubble.resize_to_content()
|
||||
|
||||
self.add(period_eq)
|
||||
you.change("pondering", period_eq)
|
||||
self.wait()
|
||||
theta_eq.remove(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
TransformFromCopy(
|
||||
period_eq.sqrt_part,
|
||||
theta_eq.sqrt_part,
|
||||
),
|
||||
FadeIn(theta_eq)
|
||||
)
|
||||
theta_eq.add(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
FadeInFrom(theta0_words, LEFT),
|
||||
GrowArrow(arrow),
|
||||
)
|
||||
self.wait()
|
||||
self.play(you.change, "confused")
|
||||
self.wait()
|
||||
self.play(
|
||||
you.change, "angry",
|
||||
ShowCreation(bubble),
|
||||
FadeInFromPoint(bubble.content, you.mouth),
|
||||
equations.to_edge, LEFT,
|
||||
FadeOut(arrow),
|
||||
FadeOut(theta0_words),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def create_pi_creature(self):
|
||||
return You().flip().to_corner(DR)
|
||||
|
||||
|
||||
# class TourOfDifferentialEquations(Scene):
|
||||
# def construct(self):
|
||||
# pass
|
||||
|
||||
|
||||
class SoWhatIsThetaThen(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
self.add(ode)
|
||||
|
||||
self.student_says(
|
||||
"Okay, but then\\\\"
|
||||
"what \\emph{is} $\\theta(t)$?"
|
||||
)
|
||||
self.wait()
|
||||
self.play(self.teacher.change, "happy")
|
||||
self.wait(2)
|
||||
self.teacher_says(
|
||||
"First, you must appreciate\\\\"
|
||||
"a deep truth...",
|
||||
added_anims=[self.get_student_changes(
|
||||
*3 * ["confused"]
|
||||
)]
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
class ProveTeacherWrong(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
tex_config = {
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": YELLOW,
|
||||
"{\\ddot\\theta}": RED,
|
||||
}
|
||||
}
|
||||
func = TexMobject(
|
||||
"{\\theta}(t)", "=",
|
||||
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
d_func = TexMobject(
|
||||
"{\\dot\\theta}(t)", "=",
|
||||
"-\\left(\\sqrt{g / L}\\right)",
|
||||
"\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
dd_func = TexMobject(
|
||||
"{\\ddot\\theta}(t)", "=",
|
||||
"-\\left(g / L\\right)",
|
||||
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
# ode = TexMobject(
|
||||
# "\\ddot {\\theta}({t})", "=",
|
||||
# "-\\mu \\dot {\\theta}({t})",
|
||||
# "-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
|
||||
# **tex_config,
|
||||
# )
|
||||
ode = get_ode()
|
||||
arrows = [TexMobject("\\Downarrow") for x in range(2)]
|
||||
|
||||
VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7)
|
||||
|
||||
teacher = self.teacher
|
||||
you = self.students[2]
|
||||
|
||||
self.student_thinks(ode)
|
||||
you.add_updater(lambda m: m.look_at(func))
|
||||
self.teacher_holds_up(func)
|
||||
self.wait()
|
||||
|
||||
group = VGroup(arrows[0], d_func, arrows[1], dd_func)
|
||||
group.arrange(DOWN)
|
||||
group.move_to(func, DOWN)
|
||||
|
||||
arrow = Arrow(
|
||||
group.get_corner(UL),
|
||||
ode.get_top(),
|
||||
path_arc=PI / 2,
|
||||
)
|
||||
q_marks = VGroup(*[
|
||||
TexMobject("?").scale(1.5).next_to(
|
||||
arrow.point_from_proportion(a),
|
||||
UP
|
||||
)
|
||||
for a in np.linspace(0.2, 0.8, 5)
|
||||
])
|
||||
cycle_animation(VFadeInThenOut(
|
||||
q_marks,
|
||||
lag_ratio=0.2,
|
||||
run_time=4,
|
||||
rate_func=squish_rate_func(smooth, 0, 0.5)
|
||||
))
|
||||
|
||||
self.play(
|
||||
func.next_to, group, UP,
|
||||
LaggedStartMap(
|
||||
FadeInFrom, group,
|
||||
lambda m: (m, UP)
|
||||
),
|
||||
teacher.change, "guilty",
|
||||
you.change, "sassy",
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(
|
||||
VGroup(group, func)
|
||||
)
|
||||
dashed_rect = DashedVMobject(rect, num_dashes=75)
|
||||
animated_rect = AnimatedBoundary(dashed_rect, cycle_rate=1)
|
||||
|
||||
self.wait()
|
||||
self.add(animated_rect, q_marks)
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
# FadeInFromDown(q_mark),
|
||||
self.get_student_changes("confused", "confused")
|
||||
)
|
||||
self.wait(4)
|
||||
self.change_student_modes(
|
||||
*3 * ["pondering"],
|
||||
self.teacher.change, "maybe"
|
||||
)
|
||||
self.wait(8)
|
||||
|
||||
|
||||
class PhysicistPhaseSpace(PiCreatureScene):
|
||||
def construct(self):
|
||||
physy = self.pi_creature
|
||||
name = TextMobject("Physicist")
|
||||
name.scale(1.5)
|
||||
name.to_corner(DL, buff=MED_SMALL_BUFF)
|
||||
physy.next_to(name, UP, SMALL_BUFF)
|
||||
VGroup(name, physy).shift_onto_screen()
|
||||
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=10,
|
||||
y_min=-1,
|
||||
y_max=7,
|
||||
)
|
||||
axes.set_height(6)
|
||||
axes.next_to(physy, RIGHT)
|
||||
axes.to_edge(UP)
|
||||
axes.set_stroke(width=1)
|
||||
x_label = TextMobject("Position")
|
||||
x_label.next_to(axes.x_axis.get_right(), UP)
|
||||
y_label = TextMobject("Momentum")
|
||||
y_label.next_to(axes.y_axis.get_top(), RIGHT)
|
||||
|
||||
title = TextMobject("Phase space")
|
||||
title.scale(1.5)
|
||||
title.set_color(YELLOW)
|
||||
title.move_to(axes)
|
||||
|
||||
self.add(name, physy)
|
||||
|
||||
self.play(
|
||||
physy.change, "angry",
|
||||
Write(axes),
|
||||
FadeInFromDown(title)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
GrowFromPoint(x_label, physy.get_corner(UR)),
|
||||
physy.change, "raise_right_hand",
|
||||
axes.x_axis.get_right()
|
||||
)
|
||||
self.play(
|
||||
GrowFromPoint(y_label, physy.get_corner(UR)),
|
||||
physy.look_at, axes.y_axis.get_top(),
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
def create_pi_creature(self):
|
||||
return PiCreature(color=GREY).to_corner(DL)
|
||||
|
||||
|
||||
class AskAboutActuallySolving(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
self.add(ode)
|
||||
morty = self.teacher
|
||||
|
||||
self.student_says(
|
||||
"Yeah yeah, but how do\\\\"
|
||||
"you actually \\emph{solve} it?",
|
||||
student_index=1,
|
||||
target_mode="sassy",
|
||||
added_anims=[morty.change, "thinking"],
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "sassy", "confused",
|
||||
look_at_arg=ode,
|
||||
)
|
||||
self.wait()
|
||||
self.teacher_says(
|
||||
"What do you mean\\\\ by ``solve''?",
|
||||
target_mode="speaking",
|
||||
added_anims=[self.get_student_changes(
|
||||
*3 * ["erm"]
|
||||
)]
|
||||
)
|
||||
self.play(self.students[1].change, "angry")
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class HungerForExactness(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
students = self.students
|
||||
you = students[2]
|
||||
teacher = self.teacher
|
||||
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
left_part = ode[:5]
|
||||
friction_part = ode[5:11]
|
||||
self.add(ode)
|
||||
|
||||
proposed_solution = TexMobject(
|
||||
"\\theta_0\\cos((\\sqrt{g/L})t)e^{-\\mu t}"
|
||||
)
|
||||
proposed_solution.next_to(
|
||||
you.get_corner(UL), UP, buff=0.7
|
||||
)
|
||||
proposed_solution_rect = SurroundingRectangle(
|
||||
proposed_solution, buff=MED_SMALL_BUFF,
|
||||
)
|
||||
proposed_solution_rect.set_color(BLUE)
|
||||
proposed_solution_rect.round_corners()
|
||||
|
||||
solution_p1 = TexMobject(
|
||||
"""
|
||||
\\theta(t) = 2\\text{am}\\left(
|
||||
\\frac{\\sqrt{2g + Lc_1} (t + c_2)}{2\\sqrt{L}},
|
||||
\\frac{4g}{2g + Lc_1}
|
||||
\\right)
|
||||
""",
|
||||
)
|
||||
solution_p1.to_corner(UL)
|
||||
solution_p2 = TexMobject(
|
||||
"c_1, c_2 = \\text{Constants depending on initial conditions}"
|
||||
)
|
||||
solution_p2.set_color(LIGHT_GREY)
|
||||
solution_p2.scale(0.75)
|
||||
solution_p3 = TexMobject(
|
||||
"""
|
||||
\\text{am}(u, k) =
|
||||
\\int_0^u \\text{dn}(v, k)\\,dv
|
||||
"""
|
||||
)
|
||||
solution_p3.name = TextMobject(
|
||||
"(Jacobi amplitude function)"
|
||||
)
|
||||
solution_p4 = TexMobject(
|
||||
"""
|
||||
\\text{dn}(u, k) =
|
||||
\\sqrt{1 - k^2 \\sin^2(\\phi)}
|
||||
"""
|
||||
)
|
||||
solution_p4.name = TextMobject(
|
||||
"(Jacobi elliptic function)"
|
||||
)
|
||||
solution_p5 = TextMobject("Where $\\phi$ satisfies")
|
||||
solution_p6 = TexMobject(
|
||||
"""
|
||||
u = \\int_0^\\phi \\frac{dt}{\\sqrt{1 - k^2 \\sin^2(t)}}
|
||||
"""
|
||||
)
|
||||
|
||||
solution = VGroup(
|
||||
solution_p1,
|
||||
solution_p2,
|
||||
solution_p3,
|
||||
solution_p4,
|
||||
solution_p5,
|
||||
solution_p6,
|
||||
)
|
||||
solution.arrange(DOWN)
|
||||
solution.scale(0.7)
|
||||
solution.to_corner(UL, buff=MED_SMALL_BUFF)
|
||||
solution.set_stroke(width=0, background=True)
|
||||
|
||||
solution.remove(solution_p2)
|
||||
solution_p1.add(solution_p2)
|
||||
solution.remove(solution_p5)
|
||||
solution_p6.add(solution_p5)
|
||||
|
||||
for part in [solution_p3, solution_p4]:
|
||||
part.name.scale(0.7 * 0.7)
|
||||
part.name.set_color(LIGHT_GREY)
|
||||
part.name.next_to(part, RIGHT)
|
||||
part.add(part.name)
|
||||
|
||||
self.student_says(
|
||||
"Right, but like,\\\\"
|
||||
"what \\emph{is} $\\theta(t)$?",
|
||||
target_mode="sassy",
|
||||
added_anims=[teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(proposed_solution),
|
||||
RemovePiCreatureBubble(
|
||||
you,
|
||||
target_mode="raise_left_hand",
|
||||
look_at_arg=proposed_solution,
|
||||
),
|
||||
teacher.change, "pondering",
|
||||
students[0].change, "pondering",
|
||||
students[1].change, "hesitant",
|
||||
)
|
||||
self.play(ShowCreation(proposed_solution_rect))
|
||||
self.play(
|
||||
proposed_solution.shift, 3 * RIGHT,
|
||||
proposed_solution_rect.shift, 3 * RIGHT,
|
||||
you.change, "raise_right_hand", teacher.eyes,
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
self.play(
|
||||
FadeOut(proposed_solution),
|
||||
FadeOut(proposed_solution_rect),
|
||||
ode.move_to, self.hold_up_spot, DOWN,
|
||||
ode.shift, LEFT,
|
||||
teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(*3 * ["pondering"])
|
||||
)
|
||||
self.wait()
|
||||
ode.save_state()
|
||||
self.play(
|
||||
left_part.move_to, friction_part, RIGHT,
|
||||
left_part.match_y, left_part,
|
||||
friction_part.to_corner, DR,
|
||||
friction_part.fade, 0.5,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
modes = ["erm", "sad", "sad", "horrified"]
|
||||
for part, mode in zip(solution, modes):
|
||||
self.play(
|
||||
FadeInFrom(part, UP),
|
||||
self.get_student_changes(
|
||||
*3 * [mode],
|
||||
look_at_arg=part,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
self.wait(3)
|
||||
self.change_student_modes("tired", "sad", "concerned_musician")
|
||||
self.wait(4)
|
||||
self.look_at(solution)
|
||||
self.wait(5)
|
||||
self.play(
|
||||
FadeOutAndShift(solution, 2 * LEFT),
|
||||
Restore(ode),
|
||||
self.get_student_changes(
|
||||
"sick", "angry", "tired",
|
||||
)
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
mystery = TexMobject(
|
||||
"\\theta(t) = ???",
|
||||
tex_to_color_map={"\\theta": BLUE},
|
||||
)
|
||||
mystery.scale(2)
|
||||
mystery.to_edge(UP)
|
||||
mystery.set_stroke(width=0, background=True)
|
||||
mystery_boundary = AnimatedBoundary(
|
||||
mystery, stroke_width=1
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(mystery),
|
||||
self.teacher.change, "pondering"
|
||||
)
|
||||
self.add(mystery_boundary, mystery)
|
||||
self.change_all_student_modes("sad")
|
||||
self.look_at(mystery)
|
||||
self.wait(5)
|
||||
|
||||
# Define
|
||||
self.student_says(
|
||||
"Let $\\text{P}(\\mu, g, L; t)$ be a\\\\"
|
||||
"function satisfying this ODE.",
|
||||
student_index=0,
|
||||
target_mode="speaking",
|
||||
added_anims=[
|
||||
FadeOut(mystery),
|
||||
FadeOut(mystery_boundary),
|
||||
ode.to_corner, UR
|
||||
]
|
||||
)
|
||||
self.change_student_modes(
|
||||
"hooray", "sassy", "sassy",
|
||||
look_at_arg=students[0].eyes.get_corner(UR),
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class ItGetsWorse(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("It gets\\\\worse")
|
||||
self.change_student_modes(
|
||||
"hesitant", "pleading", "erm"
|
||||
)
|
||||
self.wait(5)
|
||||
@@ -1,118 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
Lg_formula_config = {
|
||||
"tex_to_color_map": {
|
||||
"\\theta_0": WHITE,
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class You(PiCreature):
|
||||
CONFIG = {
|
||||
"color": BLUE_C,
|
||||
}
|
||||
|
||||
|
||||
def get_ode():
|
||||
tex_config = {
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": RED,
|
||||
"{\\ddot\\theta}": YELLOW,
|
||||
"{t}": WHITE,
|
||||
"{\\mu}": WHITE,
|
||||
}
|
||||
}
|
||||
ode = TexMobject(
|
||||
"{\\ddot\\theta}({t})", "=",
|
||||
"-{\\mu} {\\dot\\theta}({t})",
|
||||
"-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
|
||||
**tex_config,
|
||||
)
|
||||
return ode
|
||||
|
||||
|
||||
def get_period_formula():
|
||||
return TexMobject(
|
||||
"2\\pi", "\\sqrt{\\,", "L", "/", "g", "}",
|
||||
tex_to_color_map={
|
||||
"L": BLUE,
|
||||
"g": YELLOW,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def pendulum_vector_field_func(point, mu=0.1, g=9.8, L=3):
|
||||
theta, omega = point[:2]
|
||||
return np.array([
|
||||
omega,
|
||||
-np.sqrt(g / L) * np.sin(theta) - mu * omega,
|
||||
0,
|
||||
])
|
||||
|
||||
|
||||
def get_vector_symbol(*texs, **kwargs):
|
||||
config = {
|
||||
"include_background_rectangle": True,
|
||||
"bracket_h_buff": SMALL_BUFF,
|
||||
"bracket_v_buff": SMALL_BUFF,
|
||||
"element_alignment_corner": ORIGIN,
|
||||
}
|
||||
config.update(kwargs)
|
||||
array = [[tex] for tex in texs]
|
||||
return Matrix(array, **config)
|
||||
|
||||
|
||||
def get_heart_var(index):
|
||||
heart = SuitSymbol("hearts")
|
||||
if index == 1:
|
||||
heart.set_color(BLUE_C)
|
||||
elif index == 2:
|
||||
heart.set_color(GREEN)
|
||||
heart.set_height(0.7)
|
||||
index = Integer(index)
|
||||
index.move_to(heart.get_corner(DR))
|
||||
heart.add(index)
|
||||
return heart
|
||||
|
||||
|
||||
def get_heart_var_deriv(index):
|
||||
heart = get_heart_var(index)
|
||||
filler_tex = "T"
|
||||
deriv = TexMobject("{d", filler_tex, "\\over", "dt}")
|
||||
deriv.scale(2)
|
||||
filler = deriv.get_part_by_tex(filler_tex)
|
||||
heart.match_height(filler)
|
||||
heart.move_to(filler)
|
||||
heart.scale(1.5, about_edge=UL)
|
||||
deriv.remove(filler)
|
||||
deriv.add(heart)
|
||||
deriv.heart = heart
|
||||
return deriv
|
||||
|
||||
|
||||
def get_love_equation1():
|
||||
equation = VGroup(
|
||||
get_heart_var_deriv(1),
|
||||
TexMobject("=").scale(2),
|
||||
TexMobject("a").scale(2),
|
||||
get_heart_var(2)
|
||||
)
|
||||
equation.arrange(RIGHT)
|
||||
equation[-1].shift(SMALL_BUFF * DL)
|
||||
return equation
|
||||
|
||||
|
||||
def get_love_equation2():
|
||||
equation = VGroup(
|
||||
get_heart_var_deriv(2),
|
||||
TexMobject("=").scale(2),
|
||||
TexMobject("-b").scale(2),
|
||||
get_heart_var(1),
|
||||
)
|
||||
equation.arrange(RIGHT)
|
||||
equation[-1].shift(SMALL_BUFF * DL)
|
||||
return equation
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,855 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SmallAngleApproximationTex(Scene):
|
||||
def construct(self):
|
||||
approx = TexMobject(
|
||||
"\\sin", "(", "\\theta", ") \\approx \\theta",
|
||||
tex_to_color_map={"\\theta": RED},
|
||||
arg_separator="",
|
||||
)
|
||||
|
||||
implies = TexMobject("\\Downarrow")
|
||||
period = TexMobject(
|
||||
"\\text{Period}", "\\approx",
|
||||
"2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**Lg_formula_config,
|
||||
)
|
||||
group = VGroup(approx, implies, period)
|
||||
group.arrange(DOWN)
|
||||
|
||||
approx_brace = Brace(approx, UP, buff=SMALL_BUFF)
|
||||
approx_words = TextMobject(
|
||||
"For small $\\theta$",
|
||||
tex_to_color_map={"$\\theta$": RED},
|
||||
)
|
||||
approx_words.scale(0.75)
|
||||
approx_words.next_to(approx_brace, UP, SMALL_BUFF)
|
||||
|
||||
self.add(approx, approx_brace, approx_words)
|
||||
self.play(
|
||||
Write(implies),
|
||||
FadeInFrom(period, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class StrogatzQuote(Scene):
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
movers = VGroup(*quote[:-1].family_members_with_points())
|
||||
for mover in movers:
|
||||
mover.save_state()
|
||||
disc = Circle(radius=0.05)
|
||||
disc.set_stroke(width=0)
|
||||
disc.set_fill(BLACK, 0)
|
||||
disc.move_to(mover)
|
||||
mover.become(disc)
|
||||
self.play(
|
||||
FadeInFrom(quote.author_part, LEFT),
|
||||
LaggedStartMap(
|
||||
# FadeInFromLarge,
|
||||
# quote[:-1].family_members_with_points(),
|
||||
Restore, movers,
|
||||
lag_ratio=0.005,
|
||||
run_time=2,
|
||||
)
|
||||
# FadeInFromDown(quote[:-1]),
|
||||
# lag_ratio=0.01,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(quote.law_part.copy().set_color(YELLOW)),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(quote.language_part.copy().set_color(BLUE)),
|
||||
run_time=1.5,
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
def get_quote(self):
|
||||
law_words = "laws of physics"
|
||||
language_words = "language of differential equations"
|
||||
author = "-Steven Strogatz"
|
||||
quote = TextMobject(
|
||||
"""
|
||||
\\Large
|
||||
``Since Newton, mankind has come to realize
|
||||
that the laws of physics are always expressed
|
||||
in the language of differential equations.''\\\\
|
||||
""" + author,
|
||||
alignment="",
|
||||
arg_separator=" ",
|
||||
substrings_to_isolate=[law_words, language_words, author]
|
||||
)
|
||||
quote.law_part = quote.get_part_by_tex(law_words)
|
||||
quote.language_part = quote.get_part_by_tex(language_words)
|
||||
quote.author_part = quote.get_part_by_tex(author)
|
||||
quote.set_width(12)
|
||||
quote.to_edge(UP)
|
||||
quote[-2].shift(SMALL_BUFF * LEFT)
|
||||
quote.author_part.shift(RIGHT + 0.5 * DOWN)
|
||||
quote.author_part.scale(1.2, about_edge=UL)
|
||||
|
||||
return quote
|
||||
|
||||
|
||||
class WriteInRadians(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("In radians")
|
||||
words.set_color(YELLOW)
|
||||
square = SurroundingRectangle(TexMobject("\\theta"))
|
||||
square.next_to(words, UP)
|
||||
self.play(ShowCreation(square))
|
||||
self.play(Write(words), FadeOut(square))
|
||||
self.wait()
|
||||
|
||||
|
||||
class XEqLThetaToCorner(Scene):
|
||||
def construct(self):
|
||||
equation = TexMobject(
|
||||
"x = L\\theta",
|
||||
tex_to_color_map={
|
||||
"x": GREEN,
|
||||
"\\theta": BLUE,
|
||||
}
|
||||
)
|
||||
equation.move_to(DOWN + 3 * RIGHT)
|
||||
self.add(equation)
|
||||
self.play(equation.to_corner, DL, {"buff": LARGE_BUFF})
|
||||
self.wait()
|
||||
|
||||
|
||||
class ComingUp(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
frame = ScreenRectangle(
|
||||
stroke_width=0,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
height=6
|
||||
)
|
||||
title = TextMobject("Coming up")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
frame.next_to(title, DOWN)
|
||||
animated_frame = AnimatedBoundary(frame)
|
||||
self.add(frame, title, animated_frame)
|
||||
self.wait(10)
|
||||
|
||||
|
||||
class InputLabel(Scene):
|
||||
def construct(self):
|
||||
label = TextMobject("Input")
|
||||
label.scale(1.25)
|
||||
arrow = Vector(UP)
|
||||
arrow.next_to(label, UP)
|
||||
self.play(
|
||||
FadeInFrom(label, UP),
|
||||
GrowArrow(arrow)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ReallyHardToSolve(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject(
|
||||
"They're", "really\\\\",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
words.set_height(6)
|
||||
|
||||
self.wait()
|
||||
for word in words:
|
||||
wait_time = 0.05 * len(word)
|
||||
self.add(word)
|
||||
self.wait(wait_time)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ReasonForSolution(Scene):
|
||||
def construct(self):
|
||||
# Words
|
||||
eq_word = TextMobject("Differential\\\\Equation")
|
||||
s_word = TextMobject("Solution")
|
||||
u_word = TextMobject("Understanding")
|
||||
c_word = TextMobject("Computation")
|
||||
cu_group = VGroup(u_word, c_word)
|
||||
cu_group.arrange(DOWN, buff=2)
|
||||
group = VGroup(eq_word, s_word, cu_group)
|
||||
group.arrange(RIGHT, buff=2)
|
||||
# words = VGroup(eq_word, s_word, u_word, c_word)
|
||||
|
||||
# Arrows
|
||||
arrows = VGroup(
|
||||
Arrow(eq_word.get_right(), s_word.get_left()),
|
||||
Arrow(s_word.get_right(), u_word.get_left()),
|
||||
Arrow(s_word.get_right(), c_word.get_left()),
|
||||
)
|
||||
arrows.set_color(LIGHT_GREY)
|
||||
new_arrows = VGroup(
|
||||
Arrow(
|
||||
eq_word.get_corner(UR),
|
||||
u_word.get_left(),
|
||||
path_arc=-60 * DEGREES,
|
||||
),
|
||||
Arrow(
|
||||
eq_word.get_corner(DR),
|
||||
c_word.get_left(),
|
||||
path_arc=60 * DEGREES,
|
||||
),
|
||||
)
|
||||
new_arrows.set_color(BLUE)
|
||||
|
||||
# Define first examples
|
||||
t2c = {
|
||||
"{x}": BLUE,
|
||||
"{\\dot x}": RED,
|
||||
}
|
||||
equation = TexMobject(
|
||||
"{\\dot x}(t) = k {x}(t)",
|
||||
tex_to_color_map=t2c,
|
||||
)
|
||||
equation.next_to(eq_word, DOWN)
|
||||
solution = TexMobject(
|
||||
"{x}(t) = x_0 e^{kt}",
|
||||
tex_to_color_map=t2c,
|
||||
)
|
||||
solution.next_to(s_word, DOWN, MED_LARGE_BUFF)
|
||||
equation.align_to(solution, DOWN)
|
||||
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=5.5,
|
||||
y_min=-1,
|
||||
y_max=4.5,
|
||||
y_axis_config={"unit_size": 0.5}
|
||||
)
|
||||
axes.set_stroke(width=2)
|
||||
graph_line = axes.get_graph(
|
||||
lambda x: np.exp(0.4 * x)
|
||||
)
|
||||
graph_line.set_stroke(width=2)
|
||||
graph = VGroup(axes, graph_line)
|
||||
graph.scale(0.5)
|
||||
graph.next_to(u_word, UP)
|
||||
|
||||
computation = TexMobject(
|
||||
# "\\displaystyle "
|
||||
"e^x = \\sum_{n=0}^\\infty "
|
||||
"\\frac{x^n}{n!}"
|
||||
)
|
||||
computation.next_to(c_word, DOWN)
|
||||
|
||||
first_examples = VGroup(
|
||||
equation, solution, graph, computation
|
||||
)
|
||||
|
||||
# Second example
|
||||
ode = get_ode()
|
||||
ode.scale(0.75)
|
||||
second_examples = VGroup(
|
||||
ode,
|
||||
TexMobject("???").set_color(LIGHT_GREY),
|
||||
ScreenRectangle(
|
||||
height=2,
|
||||
stroke_width=1,
|
||||
),
|
||||
)
|
||||
for fe, se in zip(first_examples, second_examples):
|
||||
se.move_to(fe, DOWN)
|
||||
|
||||
ode.shift(2 * SMALL_BUFF * DOWN)
|
||||
ode.add_to_back(BackgroundRectangle(ode[-4:]))
|
||||
|
||||
self.add(eq_word)
|
||||
self.add(equation)
|
||||
self.play(
|
||||
FadeInFrom(s_word, LEFT),
|
||||
GrowArrow(arrows[0]),
|
||||
TransformFromCopy(equation, solution)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(c_word, UL),
|
||||
GrowArrow(arrows[2]),
|
||||
FadeInFrom(computation, UP)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(u_word, DL),
|
||||
GrowArrow(arrows[1]),
|
||||
FadeInFromDown(graph)
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
self.play(
|
||||
FadeOut(first_examples),
|
||||
FadeIn(second_examples[:2])
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
arrows.fade, 0.75,
|
||||
s_word.fade, 0.75,
|
||||
second_examples[1].fade, 0.75,
|
||||
ShowCreation(new_arrows[0]),
|
||||
FadeIn(second_examples[2])
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(new_arrows[1]),
|
||||
Animation(second_examples),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WritePhaseSpace(Scene):
|
||||
def construct(self):
|
||||
word = TextMobject("Phase space")
|
||||
word.scale(2)
|
||||
word.shift(FRAME_WIDTH * LEFT / 4)
|
||||
word.to_edge(UP)
|
||||
word.add_background_rectangle()
|
||||
|
||||
lines = VGroup(*[
|
||||
Line(v, 1.3 * v)
|
||||
for v in compass_directions(50)
|
||||
])
|
||||
lines.replace(word, stretch=True)
|
||||
lines.scale(1.5)
|
||||
lines.set_stroke(YELLOW)
|
||||
lines.shuffle()
|
||||
|
||||
self.add(word)
|
||||
self.play(
|
||||
ShowPassingFlashWithThinningStrokeWidth(
|
||||
lines,
|
||||
lag_ratio=0.002,
|
||||
run_time=1.5,
|
||||
time_width=0.9,
|
||||
n_segments=5,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class GleickQuote(Scene):
|
||||
def construct(self):
|
||||
quote = TextMobject(
|
||||
"``[Phase space is] one of the most\\\\",
|
||||
"powerful inventions", "of modern science.''\\\\",
|
||||
)
|
||||
quote.power_part = quote.get_part_by_tex("power")
|
||||
book = ImageMobject("ChaosBookCover")
|
||||
book.set_height(5)
|
||||
book.next_to(ORIGIN, LEFT)
|
||||
book.to_edge(DOWN)
|
||||
gleick = ImageMobject("JamesGleick")
|
||||
gleick.set_height(5)
|
||||
gleick.next_to(ORIGIN, RIGHT)
|
||||
gleick.to_edge(DOWN)
|
||||
quote.to_edge(UP)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(book, RIGHT),
|
||||
FadeInFrom(gleick, LEFT),
|
||||
)
|
||||
self.wait()
|
||||
self.play(Write(quote))
|
||||
self.play(Write(
|
||||
quote.power_part.copy().set_color(BLUE),
|
||||
run_time=1
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class WritePhaseFlow(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Phase flow")
|
||||
words.scale(2)
|
||||
words.shift(FRAME_WIDTH * LEFT / 4)
|
||||
words.to_edge(UP)
|
||||
words.add_background_rectangle()
|
||||
self.play(Write(words))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowSineValues(Scene):
|
||||
def construct(self):
|
||||
angle_tracker = ValueTracker(60 * DEGREES)
|
||||
get_angle = angle_tracker.get_value
|
||||
formula = always_redraw(
|
||||
lambda: self.get_sine_formula(get_angle())
|
||||
)
|
||||
self.add(formula)
|
||||
|
||||
self.play(
|
||||
angle_tracker.set_value, 0,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
angle_tracker.set_value, 90 * DEGREES,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def get_sine_formula(self, angle):
|
||||
sin, lp, rp = TexMobject(
|
||||
"\\sin", "(", ") = "
|
||||
)
|
||||
input_part = Integer(
|
||||
angle / DEGREES,
|
||||
unit="^\\circ",
|
||||
)
|
||||
input_part.set_color(YELLOW)
|
||||
output_part = DecimalNumber(
|
||||
np.sin(input_part.get_value() * DEGREES),
|
||||
num_decimal_places=3,
|
||||
)
|
||||
result = VGroup(
|
||||
sin, lp, input_part, rp, output_part
|
||||
)
|
||||
result.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
sin.scale(1.1, about_edge=DOWN)
|
||||
lp.align_to(rp, UP)
|
||||
return result
|
||||
|
||||
|
||||
class SetAsideSeekingSolution(Scene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_edge(UP)
|
||||
q1 = TextMobject("Find an exact solution")
|
||||
q1.set_color(YELLOW)
|
||||
q2 = TexMobject(
|
||||
"\\text{What is }", "\\theta", "(t)",
|
||||
"\\text{'s personality?}",
|
||||
tex_to_color_map={"\\theta": BLUE},
|
||||
arg_separator="",
|
||||
)
|
||||
theta = q2.get_part_by_tex("\\theta")
|
||||
|
||||
for q in q1, q2:
|
||||
q.scale(1.5)
|
||||
q.next_to(ode, DOWN, MED_LARGE_BUFF)
|
||||
eyes = Eyes(theta, height=0.1)
|
||||
|
||||
self.add(ode)
|
||||
self.add(q1)
|
||||
self.wait()
|
||||
self.play(
|
||||
q1.scale, 0.3,
|
||||
q1.to_corner, UR, MED_SMALL_BUFF,
|
||||
)
|
||||
self.play(FadeInFrom(q2, DOWN))
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=lambda t: smooth(1 - t),
|
||||
)
|
||||
self.play(eyes.look_at, q2.get_left())
|
||||
self.play(eyes.look_at, q2.get_right())
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=squish_rate_func(there_and_back)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
eyes.change_mode, "confused",
|
||||
eyes.look_at, ode.get_left(),
|
||||
)
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=squish_rate_func(there_and_back)
|
||||
)
|
||||
|
||||
|
||||
class ThreeBodyTitle(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Three body problem")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
self.add(title)
|
||||
|
||||
|
||||
class ThreeBodySymbols(Scene):
|
||||
def construct(self):
|
||||
self.init_coord_groups()
|
||||
self.introduce_coord_groups()
|
||||
self.count_coords()
|
||||
|
||||
def init_coord_groups(self):
|
||||
kwargs = {
|
||||
"bracket_v_buff": 2 * SMALL_BUFF
|
||||
}
|
||||
positions = VGroup(*[
|
||||
get_vector_symbol(*[
|
||||
"{}_{}".format(s, i)
|
||||
for s in "xyz"
|
||||
], **kwargs)
|
||||
for i in range(1, 4)
|
||||
])
|
||||
velocities = VGroup(*[
|
||||
get_vector_symbol(*[
|
||||
"p^{}_{}".format(s, i)
|
||||
for s in "xyz"
|
||||
], **kwargs)
|
||||
for i in range(1, 4)
|
||||
])
|
||||
groups = VGroup(positions, velocities)
|
||||
colors = [GREEN, RED, BLUE]
|
||||
for group in groups:
|
||||
for matrix in group:
|
||||
matrix.coords = matrix.get_entries()
|
||||
for coord, color in zip(matrix.coords, colors):
|
||||
coord.set_color(color)
|
||||
group.arrange(RIGHT)
|
||||
groups.arrange(DOWN, buff=LARGE_BUFF)
|
||||
groups.to_edge(LEFT)
|
||||
|
||||
self.coord_groups = groups
|
||||
|
||||
def introduce_coord_groups(self):
|
||||
groups = self.coord_groups
|
||||
x_group, p_group = groups
|
||||
x_word = TextMobject("Positions")
|
||||
p_word = TextMobject("Momenta")
|
||||
words = VGroup(x_word, p_word)
|
||||
for word, group in zip(words, groups):
|
||||
word.next_to(group, UP)
|
||||
|
||||
rect_groups = VGroup()
|
||||
for group in groups:
|
||||
rect_group = VGroup(*[
|
||||
SurroundingRectangle(
|
||||
VGroup(*[
|
||||
tm.coords[i]
|
||||
for tm in group
|
||||
]),
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
for i in range(3)
|
||||
])
|
||||
rect_groups.add(rect_group)
|
||||
|
||||
self.play(
|
||||
*[
|
||||
LaggedStartMap(
|
||||
FadeInFrom, group,
|
||||
lambda m: (m, UP),
|
||||
run_time=1,
|
||||
)
|
||||
for group in groups
|
||||
],
|
||||
*map(FadeInFromDown, words),
|
||||
)
|
||||
for rect_group in rect_groups:
|
||||
self.play(
|
||||
ShowCreationThenFadeOut(
|
||||
rect_group,
|
||||
lag_ratio=0.5,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def count_coords(self):
|
||||
coord_copies = VGroup()
|
||||
for group in self.coord_groups:
|
||||
for tex_mob in group:
|
||||
for coord in tex_mob.coords:
|
||||
coord_copy = coord.copy()
|
||||
coord_copy.set_stroke(
|
||||
WHITE, 2, background=True
|
||||
)
|
||||
coord_copies.add(coord_copy)
|
||||
|
||||
count = Integer()
|
||||
count_word = TextMobject("18", "degrees \\\\ of freedom")[1]
|
||||
count_group = VGroup(count, count_word)
|
||||
count_group.arrange(
|
||||
RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
count_group.scale(1.5)
|
||||
count_group.next_to(
|
||||
self.coord_groups, RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
count.add_updater(
|
||||
lambda m: m.set_value(len(coord_copies))
|
||||
)
|
||||
count.add_updater(
|
||||
lambda m: m.next_to(count_word[0][0], LEFT, aligned_edge=DOWN)
|
||||
)
|
||||
|
||||
self.add(count_group)
|
||||
self.play(
|
||||
# ChangeDecimalToValue(count, len(coord_copies)),
|
||||
ShowIncreasingSubsets(coord_copies),
|
||||
run_time=1.5,
|
||||
rate_func=linear,
|
||||
)
|
||||
self.play(FadeOut(coord_copies))
|
||||
|
||||
|
||||
class ThreeBodyEquation(Scene):
|
||||
def construct(self):
|
||||
x1 = "\\vec{\\textbf{x}}_1"
|
||||
x2 = "\\vec{\\textbf{x}}_2"
|
||||
x3 = "\\vec{\\textbf{x}}_3"
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
x1: RED,
|
||||
x2: GREEN,
|
||||
x3: BLUE,
|
||||
}
|
||||
}
|
||||
equations = VGroup(*[
|
||||
TexMobject(
|
||||
"{d^2", t1, "\\over dt^2}", "=",
|
||||
"G", "\\left("
|
||||
"{" + m2, "(", t2, "-", t1, ")"
|
||||
"\\over"
|
||||
"||", t2, "-", t1, "||^3}",
|
||||
"+",
|
||||
"{" + m3, "(", t3, "-", t1, ")"
|
||||
"\\over"
|
||||
"||", t3, "-", t1, "||^3}",
|
||||
"\\right)",
|
||||
**kw
|
||||
)
|
||||
for t1, t2, t3, m1, m2, m3 in [
|
||||
(x1, x2, x3, "m_1", "m_2", "m_3"),
|
||||
(x2, x3, x1, "m_2", "m_3", "m_1"),
|
||||
(x3, x1, x2, "m_3", "m_1", "m_2"),
|
||||
]
|
||||
])
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
|
||||
self.play(LaggedStartMap(
|
||||
FadeInFrom, equations,
|
||||
lambda m: (m, UP),
|
||||
lag_ratio=0.2,
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class JumpToThisPoint(Scene):
|
||||
def construct(self):
|
||||
dot = Dot(color=YELLOW)
|
||||
dot.scale(0.5)
|
||||
|
||||
arrow = Vector(DR, color=WHITE)
|
||||
arrow.next_to(dot, UL, SMALL_BUFF)
|
||||
words = TextMobject(
|
||||
"Jump directly to\\\\",
|
||||
"this point?",
|
||||
)
|
||||
words.add_background_rectangle_to_submobjects()
|
||||
words.next_to(arrow.get_start(), UP, SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
FadeInFromLarge(dot, 20),
|
||||
rate_func=rush_into,
|
||||
)
|
||||
self.play(
|
||||
GrowArrow(arrow),
|
||||
FadeInFromDown(words),
|
||||
)
|
||||
|
||||
|
||||
class ChaosTitle(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Chaos theory")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
line = Line(LEFT, RIGHT)
|
||||
line.set_width(FRAME_WIDTH - 1)
|
||||
line.next_to(title, DOWN)
|
||||
|
||||
self.play(
|
||||
Write(title),
|
||||
ShowCreation(line),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class RevisitQuote(StrogatzQuote, PiCreatureScene):
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
quote.law_part.set_color(YELLOW)
|
||||
quote.language_part.set_color(BLUE)
|
||||
quote.set_stroke(BLACK, 6, background=True)
|
||||
quote.scale(0.8, about_edge=UL)
|
||||
|
||||
new_langauge_part = TextMobject(
|
||||
"\\Large Language of differential equations"
|
||||
)
|
||||
new_langauge_part.to_edge(UP)
|
||||
new_langauge_part.match_style(quote.language_part)
|
||||
|
||||
randy = self.pi_creature
|
||||
|
||||
self.play(
|
||||
FadeInFrom(quote[:-1], DOWN),
|
||||
FadeInFrom(quote[-1:], LEFT),
|
||||
randy.change, "raise_right_hand",
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.change, "angry")
|
||||
self.play(
|
||||
Blink(randy),
|
||||
VFadeOut(randy, run_time=3)
|
||||
)
|
||||
mover = VGroup(quote.language_part)
|
||||
self.add(quote, mover)
|
||||
self.play(
|
||||
ReplacementTransform(
|
||||
mover, new_langauge_part,
|
||||
),
|
||||
*[
|
||||
FadeOut(part)
|
||||
for part in quote
|
||||
if part is not quote.language_part
|
||||
],
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class EndScreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"specific_patrons": [
|
||||
"Juan Benet",
|
||||
"Vassili Philippov",
|
||||
"Burt Humburg",
|
||||
"Carlos Vergara Del Rio",
|
||||
"Matt Russell",
|
||||
"Scott Gray",
|
||||
"soekul",
|
||||
"Tihan Seale",
|
||||
"Ali Yahya",
|
||||
"dave nicponski",
|
||||
"Evan Phillips",
|
||||
"Graham",
|
||||
"Joseph Kelly",
|
||||
"Kaustuv DeBiswas",
|
||||
"LambdaLabs",
|
||||
"Lukas Biewald",
|
||||
"Mike Coleman",
|
||||
"Peter Mcinerney",
|
||||
"Quantopian",
|
||||
"Roy Larson",
|
||||
"Scott Walter, Ph.D.",
|
||||
"Yana Chernobilsky",
|
||||
"Yu Jun",
|
||||
"Jordan Scales",
|
||||
"Lukas -krtek.net- Novy",
|
||||
"John Shaughnessy",
|
||||
"Britt Selvitelle",
|
||||
"David Gow",
|
||||
"J",
|
||||
"Jonathan Wilson",
|
||||
"Joseph John Cox",
|
||||
"Magnus Dahlström",
|
||||
"Randy C. Will",
|
||||
"Ryan Atallah",
|
||||
"Luc Ritchie",
|
||||
"1stViewMaths",
|
||||
"Adrian Robinson",
|
||||
"Alexis Olson",
|
||||
"Andreas Benjamin Brössel",
|
||||
"Andrew Busey",
|
||||
"Ankalagon",
|
||||
"Antonio Juarez",
|
||||
"Arjun Chakroborty",
|
||||
"Art Ianuzzi",
|
||||
"Awoo",
|
||||
"Bernd Sing",
|
||||
"Boris Veselinovich",
|
||||
"Brian Staroselsky",
|
||||
"Chad Hurst",
|
||||
"Charles Southerland",
|
||||
"Chris Connett",
|
||||
"Christian Kaiser",
|
||||
"Clark Gaebel",
|
||||
"Cooper Jones",
|
||||
"Danger Dai",
|
||||
"Dave B",
|
||||
"Dave Kester",
|
||||
"David Clark",
|
||||
"DeathByShrimp",
|
||||
"Delton Ding",
|
||||
"eaglle",
|
||||
"emptymachine",
|
||||
"Eric Younge",
|
||||
"Eryq Ouithaqueue",
|
||||
"Federico Lebron",
|
||||
"Giovanni Filippi",
|
||||
"Hal Hildebrand",
|
||||
"Herman Dieset",
|
||||
"Hitoshi Yamauchi",
|
||||
"Isaac Jeffrey Lee",
|
||||
"j eduardo perez",
|
||||
"Jacob Magnuson",
|
||||
"Jameel Syed",
|
||||
"Jason Hise",
|
||||
"Jeff Linse",
|
||||
"Jeff Straathof",
|
||||
"John Griffith",
|
||||
"John Haley",
|
||||
"John V Wertheim",
|
||||
"Jonathan Eppele",
|
||||
"Kai-Siang Ang",
|
||||
"Kanan Gill",
|
||||
"L0j1k",
|
||||
"Lee Redden",
|
||||
"Linh Tran",
|
||||
"Ludwig Schubert",
|
||||
"Magister Mugit",
|
||||
"Mark B Bahu",
|
||||
"Mark Heising",
|
||||
"Martin Price",
|
||||
"Mathias Jansson",
|
||||
"Matt Langford",
|
||||
"Matt Roveto",
|
||||
"Matthew Cocke",
|
||||
"Michael Faust",
|
||||
"Michael Hardel",
|
||||
"Mirik Gogri",
|
||||
"Mustafa Mahdi",
|
||||
"Márton Vaitkus",
|
||||
"Nero Li",
|
||||
"Nikita Lesnikov",
|
||||
"Omar Zrien",
|
||||
"Owen Campbell-Moore",
|
||||
"Peter Ehrnstrom",
|
||||
"RedAgent14",
|
||||
"rehmi post",
|
||||
"Richard Burgmann",
|
||||
"Richard Comish",
|
||||
"Ripta Pasay",
|
||||
"Rish Kundalia",
|
||||
"Robert Teed",
|
||||
"Roobie",
|
||||
"Ryan Williams",
|
||||
"Samuel D. Judge",
|
||||
"Solara570",
|
||||
"Stevie Metke",
|
||||
"Tal Einav",
|
||||
"Ted Suzman",
|
||||
"Valeriy Skobelev",
|
||||
"Xavier Bernard",
|
||||
"Yavor Ivanov",
|
||||
"Yaw Etse",
|
||||
"YinYangBalance.Asia",
|
||||
"Zach Cardwell",
|
||||
]
|
||||
}
|
||||
@@ -1,898 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
# import scipy
|
||||
|
||||
|
||||
class FourierCirclesScene(Scene):
|
||||
CONFIG = {
|
||||
"n_vectors": 10,
|
||||
"big_radius": 2,
|
||||
"colors": [
|
||||
BLUE_D,
|
||||
BLUE_C,
|
||||
BLUE_E,
|
||||
GREY_BROWN,
|
||||
],
|
||||
"circle_style": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"vector_config": {
|
||||
"buff": 0,
|
||||
"max_tip_length_to_length_ratio": 0.35,
|
||||
"tip_length": 0.15,
|
||||
"max_stroke_width_to_length_ratio": 10,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"circle_config": {
|
||||
"stroke_width": 1,
|
||||
},
|
||||
"base_frequency": 1,
|
||||
"slow_factor": 0.25,
|
||||
"center_point": ORIGIN,
|
||||
"parametric_function_step_size": 0.001,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
self.slow_factor_tracker = ValueTracker(
|
||||
self.slow_factor
|
||||
)
|
||||
self.vector_clock = ValueTracker(0)
|
||||
self.vector_clock.add_updater(
|
||||
lambda m, dt: m.increment_value(
|
||||
self.get_slow_factor() * dt
|
||||
)
|
||||
)
|
||||
self.add(self.vector_clock)
|
||||
|
||||
def get_slow_factor(self):
|
||||
return self.slow_factor_tracker.get_value()
|
||||
|
||||
def get_vector_time(self):
|
||||
return self.vector_clock.get_value()
|
||||
|
||||
#
|
||||
def get_freqs(self):
|
||||
n = self.n_vectors
|
||||
all_freqs = list(range(n // 2, -n // 2, -1))
|
||||
all_freqs.sort(key=abs)
|
||||
return all_freqs
|
||||
|
||||
def get_coefficients(self):
|
||||
return [complex(0) for x in range(self.n_vectors)]
|
||||
|
||||
def get_color_iterator(self):
|
||||
return it.cycle(self.colors)
|
||||
|
||||
def get_rotating_vectors(self, freqs=None, coefficients=None):
|
||||
vectors = VGroup()
|
||||
self.center_tracker = VectorizedPoint(self.center_point)
|
||||
|
||||
if freqs is None:
|
||||
freqs = self.get_freqs()
|
||||
if coefficients is None:
|
||||
coefficients = self.get_coefficients()
|
||||
|
||||
last_vector = None
|
||||
for freq, coefficient in zip(freqs, coefficients):
|
||||
if last_vector:
|
||||
center_func = last_vector.get_end
|
||||
else:
|
||||
center_func = self.center_tracker.get_location
|
||||
vector = self.get_rotating_vector(
|
||||
coefficient=coefficient,
|
||||
freq=freq,
|
||||
center_func=center_func,
|
||||
)
|
||||
vectors.add(vector)
|
||||
last_vector = vector
|
||||
return vectors
|
||||
|
||||
def get_rotating_vector(self, coefficient, freq, center_func):
|
||||
vector = Vector(RIGHT, **self.vector_config)
|
||||
vector.scale(abs(coefficient))
|
||||
if abs(coefficient) == 0:
|
||||
phase = 0
|
||||
else:
|
||||
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)
|
||||
return vector
|
||||
|
||||
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()
|
||||
)
|
||||
return vector
|
||||
|
||||
def get_circles(self, vectors):
|
||||
return VGroup(*[
|
||||
self.get_circle(
|
||||
vector,
|
||||
color=color
|
||||
)
|
||||
for vector, color in zip(
|
||||
vectors,
|
||||
self.get_color_iterator()
|
||||
)
|
||||
])
|
||||
|
||||
def get_circle(self, vector, color=BLUE):
|
||||
circle = Circle(color=color, **self.circle_config)
|
||||
circle.center_func = vector.get_start
|
||||
circle.radius_func = vector.get_length
|
||||
circle.add_updater(self.update_circle)
|
||||
return circle
|
||||
|
||||
def update_circle(self, circle):
|
||||
circle.set_width(2 * circle.radius_func())
|
||||
circle.move_to(circle.center_func())
|
||||
return circle
|
||||
|
||||
def get_vector_sum_path(self, vectors, color=YELLOW):
|
||||
coefs = [v.coefficient for v in vectors]
|
||||
freqs = [v.freq for v in vectors]
|
||||
center = vectors[0].get_start()
|
||||
|
||||
path = ParametricFunction(
|
||||
lambda t: center + reduce(op.add, [
|
||||
complex_to_R3(
|
||||
coef * np.exp(TAU * 1j * freq * t)
|
||||
)
|
||||
for coef, freq in zip(coefs, freqs)
|
||||
]),
|
||||
t_min=0,
|
||||
t_max=1,
|
||||
color=color,
|
||||
step_size=self.parametric_function_step_size,
|
||||
)
|
||||
return path
|
||||
|
||||
# TODO, this should be a general animated mobect
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
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()
|
||||
n_curves = len(path)
|
||||
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
||||
b = alpha - a
|
||||
if b < 0:
|
||||
width = 0
|
||||
else:
|
||||
width = stroke_width * (1 - (b % 1))
|
||||
sp.set_stroke(width=width)
|
||||
path.curr_time += dt
|
||||
return path
|
||||
|
||||
broken_path.set_color(YELLOW)
|
||||
broken_path.add_updater(update_path)
|
||||
return broken_path
|
||||
|
||||
def get_y_component_wave(self,
|
||||
vectors,
|
||||
left_x=1,
|
||||
color=PINK,
|
||||
n_copies=2,
|
||||
right_shift_rate=5):
|
||||
path = self.get_vector_sum_path(vectors)
|
||||
wave = ParametricFunction(
|
||||
lambda t: op.add(
|
||||
right_shift_rate * t * LEFT,
|
||||
path.function(t)[1] * UP
|
||||
),
|
||||
t_min=path.t_min,
|
||||
t_max=path.t_max,
|
||||
color=color,
|
||||
)
|
||||
wave_copies = VGroup(*[
|
||||
wave.copy()
|
||||
for x in range(n_copies)
|
||||
])
|
||||
wave_copies.arrange(RIGHT, buff=0)
|
||||
top_point = wave_copies.get_top()
|
||||
wave.creation = ShowCreation(
|
||||
wave,
|
||||
run_time=(1 / self.get_slow_factor()),
|
||||
rate_func=linear,
|
||||
)
|
||||
cycle_animation(wave.creation)
|
||||
wave.add_updater(lambda m: m.shift(
|
||||
(m.get_left()[0] - left_x) * LEFT
|
||||
))
|
||||
|
||||
def update_wave_copies(wcs):
|
||||
index = int(
|
||||
wave.creation.total_time * self.get_slow_factor()
|
||||
)
|
||||
wcs[:index].match_style(wave)
|
||||
wcs[index:].set_stroke(width=0)
|
||||
wcs.next_to(wave, RIGHT, buff=0)
|
||||
wcs.align_to(top_point, UP)
|
||||
wave_copies.add_updater(update_wave_copies)
|
||||
|
||||
return VGroup(wave, wave_copies)
|
||||
|
||||
def get_wave_y_line(self, vectors, wave):
|
||||
return DashedLine(
|
||||
vectors[-1].get_end(),
|
||||
wave[0].get_end(),
|
||||
stroke_width=1,
|
||||
dash_length=DEFAULT_DASH_LENGTH * 0.5,
|
||||
)
|
||||
|
||||
# Computing Fourier series
|
||||
# i.e. where all the math happens
|
||||
def get_coefficients_of_path(self, path, n_samples=10000, freqs=None):
|
||||
if freqs is None:
|
||||
freqs = self.get_freqs()
|
||||
dt = 1 / n_samples
|
||||
ts = np.arange(0, 1, dt)
|
||||
samples = np.array([
|
||||
path.point_from_proportion(t)
|
||||
for t in ts
|
||||
])
|
||||
samples -= self.center_point
|
||||
complex_samples = samples[:, 0] + 1j * samples[:, 1]
|
||||
|
||||
result = []
|
||||
for freq in freqs:
|
||||
riemann_sum = np.array([
|
||||
np.exp(-TAU * 1j * freq * t) * cs
|
||||
for t, cs in zip(ts, complex_samples)
|
||||
]).sum() * dt
|
||||
result.append(riemann_sum)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground4(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 4,
|
||||
"center_point": 4 * LEFT,
|
||||
"run_time": 30,
|
||||
"big_radius": 1.5,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
circles = self.get_circles()
|
||||
path = self.get_drawn_path(circles)
|
||||
wave = self.get_y_component_wave(circles)
|
||||
h_line = always_redraw(
|
||||
lambda: self.get_wave_y_line(circles, wave)
|
||||
)
|
||||
|
||||
# Why?
|
||||
circles.update(-1 / self.camera.frame_rate)
|
||||
#
|
||||
self.add(circles, path, wave, h_line)
|
||||
self.wait(self.run_time)
|
||||
|
||||
def get_ks(self):
|
||||
return np.arange(1, 2 * self.n_vectors + 1, 2)
|
||||
|
||||
def get_freqs(self):
|
||||
return self.base_frequency * self.get_ks()
|
||||
|
||||
def get_coefficients(self):
|
||||
return self.big_radius / self.get_ks()
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground8(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 8,
|
||||
}
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground12(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 12,
|
||||
}
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground20(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 20,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfPiSymbol(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 51,
|
||||
"center_point": ORIGIN,
|
||||
"slow_factor": 0.1,
|
||||
"n_cycles": 1,
|
||||
"tex": "\\pi",
|
||||
"start_drawn": False,
|
||||
"max_circle_stroke_width": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
for n in range(self.n_cycles):
|
||||
self.run_one_cycle()
|
||||
|
||||
def add_vectors_circles_path(self):
|
||||
path = self.get_path()
|
||||
coefs = self.get_coefficients_of_path(path)
|
||||
vectors = self.get_rotating_vectors(coefficients=coefs)
|
||||
circles = self.get_circles(vectors)
|
||||
self.set_decreasing_stroke_widths(circles)
|
||||
# approx_path = self.get_vector_sum_path(circles)
|
||||
drawn_path = self.get_drawn_path(vectors)
|
||||
if self.start_drawn:
|
||||
self.vector_clock.increment_value(1)
|
||||
|
||||
self.add(path)
|
||||
self.add(vectors)
|
||||
self.add(circles)
|
||||
self.add(drawn_path)
|
||||
|
||||
self.vectors = vectors
|
||||
self.circles = circles
|
||||
self.path = path
|
||||
self.drawn_path = drawn_path
|
||||
|
||||
def run_one_cycle(self):
|
||||
time = 1 / self.slow_factor
|
||||
self.wait(time)
|
||||
|
||||
def set_decreasing_stroke_widths(self, circles):
|
||||
mcsw = self.max_circle_stroke_width
|
||||
for k, circle in zip(it.count(1), circles):
|
||||
circle.set_stroke(width=max(
|
||||
# mcsw / np.sqrt(k),
|
||||
mcsw / k,
|
||||
mcsw,
|
||||
))
|
||||
return circles
|
||||
|
||||
def get_path(self):
|
||||
tex_mob = TexMobject(self.tex)
|
||||
tex_mob.set_height(6)
|
||||
path = tex_mob.family_members_with_points()[0]
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 1)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfName(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"name_color": WHITE,
|
||||
"name_text": "Abc",
|
||||
"time_per_symbol": 5,
|
||||
"slow_factor": 1 / 5,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
name = TextMobject(self.name_text)
|
||||
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)
|
||||
|
||||
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(
|
||||
coefficients=coefs
|
||||
)
|
||||
self.set_decreasing_stroke_widths(new_circles)
|
||||
drawn_path = self.get_drawn_path(new_circles)
|
||||
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
|
||||
self.play(
|
||||
ShowCreation(drawn_path),
|
||||
rate_func=linear,
|
||||
run_time=self.time_per_symbol
|
||||
)
|
||||
circles.suspend_updating()
|
||||
self.play(FadeOut(circles))
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FourierOfPiSymbol5(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 5,
|
||||
"run_time": 10,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfTrebleClef(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 101,
|
||||
"run_time": 10,
|
||||
"start_drawn": True,
|
||||
"file_name": "TrebleClef",
|
||||
"height": 7.5,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject(self.file_name)
|
||||
return shape
|
||||
|
||||
def get_path(self):
|
||||
shape = self.get_shape()
|
||||
path = shape.family_members_with_points()[0]
|
||||
path.set_height(self.height)
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 0)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfIP(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "IP_logo2",
|
||||
"height": 6,
|
||||
"n_vectors": 100,
|
||||
}
|
||||
|
||||
# def construct(self):
|
||||
# path = self.get_path()
|
||||
# self.add(path)
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject(self.file_name)
|
||||
return shape
|
||||
|
||||
def get_path(self):
|
||||
shape = self.get_shape()
|
||||
path = shape.family_members_with_points()[0]
|
||||
path.add_line_to(path.get_start())
|
||||
# path.make_smooth()
|
||||
|
||||
path.set_height(self.height)
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 0)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfEighthNote(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "EighthNote"
|
||||
}
|
||||
|
||||
|
||||
class FourierOfN(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 6,
|
||||
"n_vectors": 1000,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
return TexMobject("N")
|
||||
|
||||
|
||||
class FourierNailAndGear(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 6,
|
||||
"n_vectors": 200,
|
||||
"run_time": 100,
|
||||
"slow_factor": 0.01,
|
||||
"parametric_function_step_size": 0.0001,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject("Nail_And_Gear")[1]
|
||||
return shape
|
||||
|
||||
|
||||
class FourierBatman(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 100,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject("BatmanLogo")[1]
|
||||
return shape
|
||||
|
||||
|
||||
class FourierHeart(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 100,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SuitSymbol("hearts")
|
||||
return shape
|
||||
|
||||
def get_drawn_path(self, *args, **kwargs):
|
||||
kwargs["stroke_width"] = 5
|
||||
path = super().get_drawn_path(*args, **kwargs)
|
||||
path.set_color(PINK)
|
||||
return path
|
||||
|
||||
|
||||
class FourierNDQ(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 1000,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
path = VMobject()
|
||||
shape = TexMobject("NDQ")
|
||||
for sp in shape.family_members_with_points():
|
||||
path.append_points(sp.points)
|
||||
return path
|
||||
|
||||
|
||||
class FourierGoogleG(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"n_vectors": 10,
|
||||
"height": 5,
|
||||
"g_colors": [
|
||||
"#4285F4",
|
||||
"#DB4437",
|
||||
"#F4B400",
|
||||
"#0F9D58",
|
||||
]
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
g = SVGMobject("google_logo")[5]
|
||||
g.center()
|
||||
self.add(g)
|
||||
return g
|
||||
|
||||
def get_drawn_path(self, *args, **kwargs):
|
||||
kwargs["stroke_width"] = 7
|
||||
path = super().get_drawn_path(*args, **kwargs)
|
||||
|
||||
blue, red, yellow, green = self.g_colors
|
||||
|
||||
path[:250].set_color(blue)
|
||||
path[250:333].set_color(green)
|
||||
path[333:370].set_color(yellow)
|
||||
path[370:755].set_color(red)
|
||||
path[755:780].set_color(yellow)
|
||||
path[780:860].set_color(green)
|
||||
path[860:].set_color(blue)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class ExplainCircleAnimations(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"center_point": 2 * DOWN,
|
||||
"n_top_circles": 9,
|
||||
"path_height": 3,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_path()
|
||||
self.add_circles()
|
||||
self.wait(8)
|
||||
self.organize_circles_in_a_row()
|
||||
self.show_frequencies()
|
||||
self.show_examples_for_frequencies()
|
||||
self.show_as_vectors()
|
||||
self.show_vector_sum()
|
||||
self.tweak_starting_vectors()
|
||||
|
||||
def add_path(self):
|
||||
self.path = self.get_path()
|
||||
self.add(self.path)
|
||||
|
||||
def add_circles(self):
|
||||
coefs = self.get_coefficients_of_path(self.path)
|
||||
self.circles = self.get_circles(coefficients=coefs)
|
||||
|
||||
self.add(self.circles)
|
||||
self.drawn_path = self.get_drawn_path(self.circles)
|
||||
self.add(self.drawn_path)
|
||||
|
||||
def organize_circles_in_a_row(self):
|
||||
circles = self.circles
|
||||
top_circles = circles[:self.n_top_circles].copy()
|
||||
|
||||
center_trackers = VGroup()
|
||||
for circle in top_circles:
|
||||
tracker = VectorizedPoint(circle.center_func())
|
||||
circle.center_func = tracker.get_location
|
||||
center_trackers.add(tracker)
|
||||
tracker.freq = circle.freq
|
||||
tracker.circle = circle
|
||||
|
||||
center_trackers.submobjects.sort(
|
||||
key=lambda m: m.freq
|
||||
)
|
||||
center_trackers.generate_target()
|
||||
right_buff = 1.45
|
||||
center_trackers.target.arrange(RIGHT, buff=right_buff)
|
||||
center_trackers.target.to_edge(UP, buff=1.25)
|
||||
|
||||
self.add(top_circles)
|
||||
self.play(
|
||||
MoveToTarget(center_trackers),
|
||||
run_time=2
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
self.top_circles = top_circles
|
||||
self.center_trackers = center_trackers
|
||||
|
||||
def show_frequencies(self):
|
||||
center_trackers = self.center_trackers
|
||||
|
||||
freq_numbers = VGroup()
|
||||
for ct in center_trackers:
|
||||
number = Integer(ct.freq)
|
||||
number.next_to(ct, DOWN, buff=1)
|
||||
freq_numbers.add(number)
|
||||
ct.circle.number = number
|
||||
|
||||
ld, rd = [
|
||||
TexMobject("\\dots")
|
||||
for x in range(2)
|
||||
]
|
||||
ld.next_to(freq_numbers, LEFT, MED_LARGE_BUFF)
|
||||
rd.next_to(freq_numbers, RIGHT, MED_LARGE_BUFF)
|
||||
freq_numbers.add_to_back(ld)
|
||||
freq_numbers.add(rd)
|
||||
|
||||
freq_word = TextMobject("Frequencies")
|
||||
freq_word.scale(1.5)
|
||||
freq_word.set_color(YELLOW)
|
||||
freq_word.next_to(freq_numbers, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFromDown, freq_numbers
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
Write(freq_word),
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround, freq_numbers,
|
||||
)
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
self.freq_numbers = freq_numbers
|
||||
self.freq_word = freq_word
|
||||
|
||||
def show_examples_for_frequencies(self):
|
||||
top_circles = self.top_circles
|
||||
c1, c2, c3 = [
|
||||
list(filter(
|
||||
lambda c: c.freq == k,
|
||||
top_circles
|
||||
))[0]
|
||||
for k in (1, 2, 3)
|
||||
]
|
||||
|
||||
neg_circles = VGroup(*filter(
|
||||
lambda c: c.freq < 0,
|
||||
top_circles
|
||||
))
|
||||
|
||||
for c in [c1, c2, c3, *neg_circles]:
|
||||
c.rect = SurroundingRectangle(c)
|
||||
|
||||
self.play(
|
||||
ShowCreation(c2.rect),
|
||||
WiggleOutThenIn(c2.number),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ReplacementTransform(c2.rect, c1.rect),
|
||||
)
|
||||
self.play(FadeOut(c1.rect))
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(c3.rect),
|
||||
WiggleOutThenIn(c3.number),
|
||||
)
|
||||
self.play(
|
||||
FadeOut(c3.rect),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
ShowCreationThenFadeOut(c.rect)
|
||||
for c in neg_circles
|
||||
])
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeOut(self.freq_word))
|
||||
|
||||
def show_as_vectors(self):
|
||||
top_circles = self.top_circles
|
||||
top_vectors = self.get_rotating_vectors(top_circles)
|
||||
top_vectors.set_color(WHITE)
|
||||
|
||||
original_circles = top_circles.copy()
|
||||
self.play(
|
||||
FadeIn(top_vectors),
|
||||
top_circles.set_opacity, 0,
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
top_circles.match_style, original_circles
|
||||
)
|
||||
self.remove(top_vectors)
|
||||
|
||||
self.top_vectors = top_vectors
|
||||
|
||||
def show_vector_sum(self):
|
||||
trackers = self.center_trackers.copy()
|
||||
trackers.sort(
|
||||
submob_func=lambda t: abs(t.circle.freq - 0.1)
|
||||
)
|
||||
plane = self.plane = NumberPlane(
|
||||
x_min=-3,
|
||||
x_max=3,
|
||||
y_min=-2,
|
||||
y_max=2,
|
||||
axis_config={
|
||||
"stroke_color": LIGHT_GREY,
|
||||
}
|
||||
)
|
||||
plane.set_stroke(width=1)
|
||||
plane.fade(0.5)
|
||||
plane.move_to(self.center_point)
|
||||
|
||||
self.play(
|
||||
FadeOut(self.drawn_path),
|
||||
FadeOut(self.circles),
|
||||
self.slow_factor_tracker.set_value, 0.05,
|
||||
)
|
||||
self.add(plane, self.path)
|
||||
self.play(FadeIn(plane))
|
||||
|
||||
new_circles = VGroup()
|
||||
last_tracker = None
|
||||
for tracker in trackers:
|
||||
if last_tracker:
|
||||
tracker.new_location_func = last_tracker.circle.get_start
|
||||
else:
|
||||
tracker.new_location_func = lambda: self.center_point
|
||||
|
||||
original_circle = tracker.circle
|
||||
tracker.circle = original_circle.copy()
|
||||
tracker.circle.center_func = tracker.get_location
|
||||
new_circles.add(tracker.circle)
|
||||
|
||||
self.add(tracker, tracker.circle)
|
||||
start_point = tracker.get_location()
|
||||
self.play(
|
||||
UpdateFromAlphaFunc(
|
||||
tracker, lambda t, a: t.move_to(
|
||||
interpolate(
|
||||
start_point,
|
||||
tracker.new_location_func(),
|
||||
a,
|
||||
)
|
||||
),
|
||||
run_time=2
|
||||
)
|
||||
)
|
||||
tracker.add_updater(lambda t: t.move_to(
|
||||
t.new_location_func()
|
||||
))
|
||||
self.wait(2)
|
||||
last_tracker = tracker
|
||||
|
||||
self.wait(3)
|
||||
|
||||
self.clear()
|
||||
self.slow_factor_tracker.set_value(0.1)
|
||||
self.add(
|
||||
self.top_circles,
|
||||
self.freq_numbers,
|
||||
self.path,
|
||||
)
|
||||
self.add_circles()
|
||||
for tc in self.top_circles:
|
||||
for c in self.circles:
|
||||
if c.freq == tc.freq:
|
||||
tc.rotate(
|
||||
angle_of_vector(c.get_start() - c.get_center()) -
|
||||
angle_of_vector(tc.get_start() - tc.get_center())
|
||||
)
|
||||
self.wait(10)
|
||||
|
||||
def tweak_starting_vectors(self):
|
||||
top_circles = self.top_circles
|
||||
circles = self.circles
|
||||
path = self.path
|
||||
drawn_path = self.drawn_path
|
||||
|
||||
new_path = self.get_new_path()
|
||||
new_coefs = self.get_coefficients_of_path(new_path)
|
||||
new_circles = self.get_circles(coefficients=new_coefs)
|
||||
|
||||
new_top_circles = VGroup()
|
||||
new_top_vectors = VGroup()
|
||||
for top_circle in top_circles:
|
||||
for circle in new_circles:
|
||||
if circle.freq == top_circle.freq:
|
||||
new_top_circle = circle.copy()
|
||||
new_top_circle.center_func = top_circle.get_center
|
||||
new_top_vector = self.get_rotating_vector(
|
||||
new_top_circle
|
||||
)
|
||||
new_top_circles.add(new_top_circle)
|
||||
new_top_vectors.add(new_top_vector)
|
||||
|
||||
self.play(
|
||||
self.slow_factor_tracker.set_value, 0,
|
||||
FadeOut(drawn_path)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(top_circles, new_top_circles),
|
||||
ReplacementTransform(circles, new_circles),
|
||||
FadeOut(path),
|
||||
run_time=3,
|
||||
)
|
||||
new_drawn_path = self.get_drawn_path(
|
||||
new_circles, stroke_width=4,
|
||||
)
|
||||
self.add(new_drawn_path)
|
||||
self.slow_factor_tracker.set_value(0.1)
|
||||
self.wait(20)
|
||||
|
||||
#
|
||||
def configure_path(self, path):
|
||||
path.set_stroke(WHITE, 1)
|
||||
path.set_fill(BLACK, opacity=1)
|
||||
path.set_height(self.path_height)
|
||||
path.move_to(self.center_point)
|
||||
return path
|
||||
|
||||
def get_path(self):
|
||||
tex = TexMobject("f")
|
||||
path = tex.family_members_with_points()[0]
|
||||
self.configure_path(path)
|
||||
return path
|
||||
# return Square().set_height(3)
|
||||
|
||||
def get_new_path(self):
|
||||
shape = SVGMobject("TrebleClef")
|
||||
path = shape.family_members_with_points()[0]
|
||||
self.configure_path(path)
|
||||
path.scale(1.5, about_edge=DOWN)
|
||||
return path
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,142 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
def construct(self):
|
||||
randy = self.pi_creature
|
||||
randy.set_color(BLUE_C)
|
||||
randy.center()
|
||||
|
||||
point = VectorizedPoint().next_to(randy, UL, LARGE_BUFF)
|
||||
randy.add_updater(lambda r: r.look_at(point))
|
||||
|
||||
self.play(randy.change, "horrified")
|
||||
self.wait()
|
||||
self.play(randy.change, "pondering")
|
||||
self.wait()
|
||||
self.play(
|
||||
randy.change, "confused",
|
||||
point.next_to, randy, UR, LARGE_BUFF,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
point.shift, 2 * DOWN,
|
||||
randy.change, "horrified"
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
class ContrastPDEToODE(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"random_seed": 2,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
student = self.students[2]
|
||||
pde, ode = words = VGroup(*[
|
||||
TextMobject(
|
||||
text + "\\\\",
|
||||
"Differential\\\\",
|
||||
"Equation"
|
||||
)
|
||||
for text in ("Partial", "Ordinary")
|
||||
])
|
||||
pde[0].set_color(YELLOW)
|
||||
ode[0].set_color(BLUE)
|
||||
for word in words:
|
||||
word.arrange(DOWN, aligned_edge=LEFT)
|
||||
|
||||
words.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
words.next_to(student.get_corner(UR), UP, MED_LARGE_BUFF)
|
||||
words.shift(UR)
|
||||
lt = TexMobject("<")
|
||||
lt.scale(1.5)
|
||||
lt.move_to(Line(pde.get_right(), ode.get_left()))
|
||||
|
||||
for pi in self.pi_creatures:
|
||||
pi.add_updater(lambda p: p.look_at(pde))
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(VGroup(words, lt)),
|
||||
student.change, "raise_right_hand",
|
||||
)
|
||||
self.play(
|
||||
self.get_student_changes("pondering", "pondering", "hooray"),
|
||||
self.teacher.change, "happy"
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
Swap(ode, pde),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(
|
||||
"erm", "sassy", "confused"
|
||||
)
|
||||
)
|
||||
self.look_at(words)
|
||||
self.change_student_modes(
|
||||
"thinking", "thinking", "tease",
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class AskAboutWhereEquationComesFrom(TeacherStudentsScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.move_to(self.hold_up_spot, DOWN)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(equation),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.student_says(
|
||||
"Um...why?",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
bubble_kwargs={"direction": RIGHT},
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "confused", "sassy",
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
self.teacher.change, "pondering",
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class AskWhyRewriteIt(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Why?", student_index=1,
|
||||
bubble_kwargs={"height": 2, "width": 2},
|
||||
)
|
||||
self.students[1].bubble = None
|
||||
self.teacher_says(
|
||||
"One step closer\\\\to derivatives"
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "thinking", "thinking",
|
||||
look_at_arg=4 * LEFT + 2 * UP
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class ReferenceKhanVideo(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
khan_logo = ImageMobject("KhanLogo")
|
||||
khan_logo.set_height(1)
|
||||
khan_logo.next_to(self.teacher, UP, buff=2)
|
||||
khan_logo.shift(2 * LEFT)
|
||||
|
||||
self.play(
|
||||
self.teacher.change, "raise_right_hand",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "pondering", "thinking",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(khan_logo))
|
||||
self.look_at(self.screen)
|
||||
self.wait(15)
|
||||
@@ -1,35 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
TIME_COLOR = YELLOW
|
||||
X_COLOR = GREEN
|
||||
|
||||
|
||||
def get_heat_equation():
|
||||
pass
|
||||
|
||||
|
||||
def temperature_to_color(temp, min_temp=-1, max_temp=1):
|
||||
colors = [BLUE, TEAL, GREEN, YELLOW, "#ff0000"]
|
||||
|
||||
alpha = inverse_interpolate(min_temp, max_temp, temp)
|
||||
index, sub_alpha = integer_interpolate(
|
||||
0, len(colors) - 1, alpha
|
||||
)
|
||||
return interpolate_color(
|
||||
colors[index], colors[index + 1], sub_alpha
|
||||
)
|
||||
|
||||
|
||||
def two_d_temp_func(x, y, t):
|
||||
return np.sum([
|
||||
c * np.sin(f * var) * np.exp(-(f**2) * t)
|
||||
for c, f, var in [
|
||||
(0.2, 1, x),
|
||||
(0.3, 3, x),
|
||||
(0.02, 5, x),
|
||||
(0.01, 7, x),
|
||||
(0.5, 2, y),
|
||||
(0.1, 10, y),
|
||||
(0.01, 20, y),
|
||||
]
|
||||
])
|
||||
@@ -1,794 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.staging import TourOfDifferentialEquations
|
||||
|
||||
|
||||
class PartTwoOfTour(TourOfDifferentialEquations):
|
||||
CONFIG = {
|
||||
"zoomed_thumbnail_index": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.show_thumbnails()
|
||||
self.zoom_in_to_one_thumbnail()
|
||||
|
||||
def zoom_in_to_one_thumbnail(self):
|
||||
frame = self.camera_frame
|
||||
thumbnails = self.thumbnails
|
||||
|
||||
ode = TextMobject("Ordinary\\\\", "Differential Equation")
|
||||
pde = TextMobject("Partial\\\\", "Differential Equation")
|
||||
for word, thumbnail, vect in zip([ode, pde], thumbnails, [DOWN, UP]):
|
||||
word.match_width(thumbnail)
|
||||
word.next_to(thumbnail, vect)
|
||||
ode[0].set_color(BLUE)
|
||||
pde[0].set_color(YELLOW)
|
||||
|
||||
self.add(ode)
|
||||
|
||||
frame.save_state()
|
||||
self.play(
|
||||
frame.replace,
|
||||
thumbnails[0],
|
||||
run_time=1,
|
||||
)
|
||||
self.play(
|
||||
Restore(frame, run_time=3),
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(ode, pde),
|
||||
)
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
frame.replace, thumbnails[1],
|
||||
path_arc=(-30 * DEGREES),
|
||||
run_time=3
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class BrownianMotion(Scene):
|
||||
CONFIG = {
|
||||
"wait_time": 60,
|
||||
"L": 3, # Box in [-L, L] x [-L, L]
|
||||
"n_particles": 100,
|
||||
"m1": 1,
|
||||
"m2": 100,
|
||||
"r1": 0.05,
|
||||
"r2": 0.5,
|
||||
"max_v": 5,
|
||||
"random_seed": 2,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.add_particles()
|
||||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
square = Square(side_length=2 * self.L)
|
||||
title = TextMobject("Brownian motion")
|
||||
title.scale(1.5)
|
||||
title.next_to(square, UP)
|
||||
|
||||
self.add(square)
|
||||
self.add(title)
|
||||
|
||||
def add_particles(self):
|
||||
m1 = self.m1
|
||||
m2 = self.m2
|
||||
r1 = self.r1
|
||||
r2 = self.r2
|
||||
L = self.L
|
||||
max_v = self.max_v
|
||||
n_particles = self.n_particles
|
||||
|
||||
lil_particles = VGroup(*[
|
||||
self.get_particle(m1, r1, L, max_v)
|
||||
for k in range(n_particles)
|
||||
])
|
||||
big_particle = self.get_particle(m2, r2, L=r2, max_v=0)
|
||||
big_particle.set_fill(YELLOW, 1)
|
||||
|
||||
for p in lil_particles:
|
||||
if self.are_colliding(p, big_particle):
|
||||
lil_particles.remove(p)
|
||||
all_particles = VGroup(big_particle, *lil_particles)
|
||||
all_particles.add_updater(self.update_particles)
|
||||
|
||||
path = self.get_traced_path(big_particle)
|
||||
|
||||
self.add(all_particles)
|
||||
self.add(path)
|
||||
|
||||
self.particles = all_particles
|
||||
self.big_particle = big_particle
|
||||
self.path = path
|
||||
|
||||
def get_particle(self, m, r, L, max_v):
|
||||
dot = Dot(radius=r)
|
||||
dot.set_fill(WHITE, 0.7)
|
||||
dot.mass = m
|
||||
dot.radius = r
|
||||
dot.center = op.add(
|
||||
np.random.uniform(-L + r, L - r) * RIGHT,
|
||||
np.random.uniform(-L + r, L - r) * UP
|
||||
)
|
||||
dot.move_to(dot.center)
|
||||
dot.velocity = rotate_vector(
|
||||
np.random.uniform(0, max_v) * RIGHT,
|
||||
np.random.uniform(0, TAU),
|
||||
)
|
||||
return dot
|
||||
|
||||
def are_colliding(self, p1, p2):
|
||||
d = get_norm(p1.get_center() - p2.get_center())
|
||||
return (d < p1.radius + p2.radius)
|
||||
|
||||
def get_traced_path(self, particle):
|
||||
path = VMobject()
|
||||
path.set_stroke(BLUE, 3)
|
||||
path.start_new_path(particle.get_center())
|
||||
|
||||
buff = 0.02
|
||||
|
||||
def update_path(path):
|
||||
new_point = particle.get_center()
|
||||
if get_norm(new_point - path.get_last_point()) > buff:
|
||||
path.add_line_to(new_point)
|
||||
|
||||
path.add_updater(update_path)
|
||||
return path
|
||||
|
||||
def update_particles(self, particles, dt):
|
||||
for p1 in particles:
|
||||
p1.center += p1.velocity * dt
|
||||
|
||||
# Check particle collisions
|
||||
buff = 0.01
|
||||
for p2 in particles:
|
||||
if p1 is p2:
|
||||
continue
|
||||
v = p2.center - p1.center
|
||||
dist = get_norm(v)
|
||||
r_sum = p1.radius + p2.radius
|
||||
diff = dist - r_sum
|
||||
if diff < 0:
|
||||
unit_v = v / dist
|
||||
p1.center += (diff - buff) * unit_v / 2
|
||||
p2.center += -(diff - buff) * unit_v / 2
|
||||
u1 = p1.velocity
|
||||
u2 = p2.velocity
|
||||
m1 = p1.mass
|
||||
m2 = p2.mass
|
||||
v1 = (
|
||||
(m2 * (u2 - u1) + m1 * u1 + m2 * u2) /
|
||||
(m1 + m2)
|
||||
)
|
||||
v2 = (
|
||||
(m1 * (u1 - u2) + m1 * u1 + m2 * u2) /
|
||||
(m1 + m2)
|
||||
)
|
||||
p1.velocity = v1
|
||||
p2.velocity = v2
|
||||
|
||||
# Check edge collisions
|
||||
r1 = p1.radius
|
||||
c1 = p1.center
|
||||
for i in [0, 1]:
|
||||
if abs(c1[i]) + r1 > self.L:
|
||||
c1[i] = np.sign(c1[i]) * (self.L - r1)
|
||||
p1.velocity[i] *= -1 * op.mul(
|
||||
np.sign(p1.velocity[i]),
|
||||
np.sign(c1[i])
|
||||
)
|
||||
|
||||
for p in particles:
|
||||
p.move_to(p.center)
|
||||
return particles
|
||||
|
||||
|
||||
class AltBrownianMotion(BrownianMotion):
|
||||
CONFIG = {
|
||||
"wait_time": 20,
|
||||
"n_particles": 100,
|
||||
"m2": 10,
|
||||
}
|
||||
|
||||
|
||||
class BlackScholes(AltBrownianMotion):
|
||||
def construct(self):
|
||||
# For some reason I'm amused by the thought
|
||||
# Of this graph perfectly matching the Brownian
|
||||
# Motion y-coordiante
|
||||
self.add_title()
|
||||
self.add_particles()
|
||||
self.particles.set_opacity(0)
|
||||
self.remove(self.path)
|
||||
self.add_graph()
|
||||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject("Black-Sholes equations")
|
||||
title.scale(1.5)
|
||||
title.next_to(2 * UP, UP)
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial V \\over \\partial t}", "+",
|
||||
"\\frac{1}{2} \\sigma^2 S^2",
|
||||
"{\\partial^2 V \\over \\partial S^2}", "+",
|
||||
"rS", "{\\partial V \\over \\partial S}",
|
||||
"-rV", "=", "0",
|
||||
)
|
||||
equation.scale(0.8)
|
||||
equation.next_to(title, DOWN)
|
||||
|
||||
self.add(title)
|
||||
self.add(equation)
|
||||
self.title = title
|
||||
self.equation = equation
|
||||
|
||||
def add_graph(self):
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=20,
|
||||
y_min=0,
|
||||
y_max=10,
|
||||
number_line_config={
|
||||
"unit_size": 0.5,
|
||||
},
|
||||
)
|
||||
axes.set_height(4)
|
||||
axes.move_to(DOWN)
|
||||
|
||||
def get_graph_point():
|
||||
return axes.c2p(
|
||||
self.get_time(),
|
||||
5 + 2 * self.big_particle.get_center()[1]
|
||||
)
|
||||
|
||||
graph = VMobject()
|
||||
graph.match_style(self.path)
|
||||
graph.start_new_path(get_graph_point())
|
||||
graph.add_updater(
|
||||
lambda g: g.add_line_to(get_graph_point())
|
||||
)
|
||||
|
||||
self.add(axes)
|
||||
self.add(graph)
|
||||
|
||||
|
||||
class ContrastChapters1And2(Scene):
|
||||
def construct(self):
|
||||
c1_frame, c2_frame = frames = VGroup(*[
|
||||
ScreenRectangle(height=3.5)
|
||||
for x in range(2)
|
||||
])
|
||||
frames.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
|
||||
c1_title, c2_title = titles = VGroup(
|
||||
TextMobject("Chapter 1"),
|
||||
TextMobject("Chapter 2"),
|
||||
)
|
||||
titles.scale(1.5)
|
||||
|
||||
ode, pde = des = VGroup(
|
||||
TextMobject(
|
||||
"Ordinary",
|
||||
"Differential Equations\\\\",
|
||||
"ODEs",
|
||||
),
|
||||
TextMobject(
|
||||
"Partial",
|
||||
"Differential Equations\\\\",
|
||||
"PDEs",
|
||||
),
|
||||
)
|
||||
ode[0].set_color(BLUE)
|
||||
pde[0].set_color(YELLOW)
|
||||
for de in des:
|
||||
de[-1][0].match_color(de[0])
|
||||
de[-1].scale(1.5, about_point=de.get_top())
|
||||
|
||||
for title, frame, de in zip(titles, frames, des):
|
||||
title.next_to(frame, UP)
|
||||
de.match_width(frame)
|
||||
de.next_to(frame, DOWN)
|
||||
|
||||
lt = TexMobject("<")
|
||||
lt.move_to(Line(ode.get_right(), pde.get_left()))
|
||||
lt.scale(2, about_edge=UP)
|
||||
|
||||
c1_words = TextMobject(
|
||||
"They're", "really\\\\", "{}",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
c1_words.set_height(0.5 * c1_frame.get_height())
|
||||
c1_words.move_to(c1_frame)
|
||||
|
||||
c2_words = TextMobject(
|
||||
"They're", "really", "\\emph{really}\\\\",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
c2_words.set_color_by_tex("\\emph", YELLOW)
|
||||
c2_words.move_to(c2_frame)
|
||||
edit_shift = MED_LARGE_BUFF * RIGHT
|
||||
c2_edits = VGroup(
|
||||
TextMobject("sometimes").next_to(
|
||||
c2_words[1:3], UP,
|
||||
aligned_edge=LEFT,
|
||||
),
|
||||
Line(
|
||||
c2_words[1].get_left(),
|
||||
c2_words[2].get_right(),
|
||||
stroke_width=8,
|
||||
),
|
||||
TextMobject("not too").next_to(
|
||||
c2_words[3], LEFT,
|
||||
),
|
||||
Line(
|
||||
c2_words[3].get_left(),
|
||||
c2_words[3].get_right(),
|
||||
stroke_width=8,
|
||||
),
|
||||
)
|
||||
c2_edits.set_color(RED)
|
||||
c2_edits[2:].shift(edit_shift)
|
||||
|
||||
self.add(titles)
|
||||
self.add(frames)
|
||||
self.add(des)
|
||||
|
||||
self.wait()
|
||||
self.play(LaggedStartMap(
|
||||
FadeInFromDown, c1_words,
|
||||
lag_ratio=0.1,
|
||||
))
|
||||
self.wait()
|
||||
# self.play(FadeIn(ode))
|
||||
self.play(
|
||||
# TransformFromCopy(ode, pde),
|
||||
TransformFromCopy(c1_words, c2_words),
|
||||
Write(lt)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(c2_edits[:2], run_time=1),
|
||||
)
|
||||
self.play(
|
||||
c2_words[3:5].shift, edit_shift,
|
||||
Write(c2_edits[2:]),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowCubeFormation(ThreeDScene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"shading_factor": 1.0,
|
||||
},
|
||||
"color": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
light_source = self.camera.light_source
|
||||
light_source.move_to(np.array([-6, -3, 6]))
|
||||
|
||||
cube = Cube(
|
||||
side_length=4,
|
||||
fill_color=GREY,
|
||||
stroke_color=WHITE,
|
||||
stroke_width=0.5,
|
||||
)
|
||||
cube.set_fill(opacity=1)
|
||||
if self.color:
|
||||
# cube[0].set_color(BLUE)
|
||||
# cube[1].set_color(RED)
|
||||
# for face in cube[2:]:
|
||||
# face.set_color([BLUE, RED])
|
||||
cube.color_using_background_image("VerticalTempGradient")
|
||||
|
||||
# light_source.next_to(cube, np.array([1, -1, 1]), buff=2)
|
||||
|
||||
cube_3d = cube.copy()
|
||||
cube_2d = cube_3d.copy().stretch(0, 2)
|
||||
cube_1d = cube_2d.copy().stretch(0, 1)
|
||||
cube_0d = cube_1d.copy().stretch(0, 0)
|
||||
|
||||
cube.become(cube_0d)
|
||||
|
||||
self.set_camera_orientation(
|
||||
phi=70 * DEGREES,
|
||||
theta=-145 * DEGREES,
|
||||
)
|
||||
self.begin_ambient_camera_rotation(rate=0.05)
|
||||
|
||||
for target in [cube_1d, cube_2d, cube_3d]:
|
||||
self.play(
|
||||
Transform(cube, target, run_time=1.5)
|
||||
)
|
||||
self.wait(8)
|
||||
|
||||
|
||||
class ShowCubeFormationWithColor(ShowCubeFormation):
|
||||
CONFIG = {
|
||||
"color": True,
|
||||
}
|
||||
|
||||
|
||||
class ShowRect(Scene):
|
||||
CONFIG = {
|
||||
"height": 1,
|
||||
"width": 3,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
rect = Rectangle(
|
||||
height=self.height,
|
||||
width=self.width,
|
||||
)
|
||||
rect.set_color(YELLOW)
|
||||
self.play(ShowCreationThenFadeOut(rect))
|
||||
|
||||
|
||||
class ShowSquare(ShowRect):
|
||||
CONFIG = {
|
||||
"height": 1,
|
||||
"width": 1,
|
||||
}
|
||||
|
||||
|
||||
class ShowHLine(Scene):
|
||||
def construct(self):
|
||||
line = Line(LEFT, RIGHT)
|
||||
line.set_color(BLUE)
|
||||
self.play(ShowCreationThenFadeOut(line))
|
||||
|
||||
|
||||
class ShowCross(Scene):
|
||||
def construct(self):
|
||||
cross = Cross(Square())
|
||||
cross.set_width(3)
|
||||
cross.set_height(1, stretch=True)
|
||||
self.play(ShowCreation(cross))
|
||||
|
||||
|
||||
class TwoBodyEquations(Scene):
|
||||
def construct(self):
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
"x_1": LIGHT_GREY,
|
||||
"y_1": LIGHT_GREY,
|
||||
"x_2": BLUE,
|
||||
"y_2": BLUE,
|
||||
"=": WHITE,
|
||||
}
|
||||
}
|
||||
equations = VGroup(
|
||||
TexMobject(
|
||||
"{d^2 x_1 \\over dt^2}",
|
||||
"=",
|
||||
"{x_2 - x_1 \\over m_1 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 y_1 \\over dt^2}",
|
||||
"=",
|
||||
"{y_2 - y_1 \\over m_1 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 x_2 \\over dt^2}",
|
||||
"=",
|
||||
"{x_1 - x_2 \\over m_2 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 y_2 \\over dt^2}",
|
||||
"=",
|
||||
"{y_1 - y_2 \\over m_2 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
)
|
||||
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
equations.set_height(6)
|
||||
equations.to_edge(LEFT)
|
||||
|
||||
variables = VGroup()
|
||||
lhss = VGroup()
|
||||
rhss = VGroup()
|
||||
for equation in equations:
|
||||
variable = equation[1]
|
||||
lhs = equation[:4]
|
||||
rhs = equation[4:]
|
||||
variables.add(variable)
|
||||
lhss.add(lhs)
|
||||
rhss.add(rhs)
|
||||
lhss_copy = lhss.copy()
|
||||
|
||||
for variable, lhs in zip(variables, lhss):
|
||||
variable.save_state()
|
||||
variable.match_height(lhs)
|
||||
variable.scale(0.7)
|
||||
variable.move_to(lhs, LEFT)
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
FadeInFrom(v, RIGHT)
|
||||
for v in variables
|
||||
]))
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(Restore, variables),
|
||||
FadeIn(
|
||||
lhss_copy,
|
||||
remover=True,
|
||||
lag_ratio=0.1,
|
||||
run_time=2,
|
||||
)
|
||||
)
|
||||
self.add(lhss)
|
||||
self.wait()
|
||||
self.play(LaggedStartMap(
|
||||
FadeIn, rhss
|
||||
))
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
ShowCreationThenFadeAround(lhs[:3])
|
||||
for lhs in lhss
|
||||
])
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
rhss,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class LaplacianIntuition(SpecialThreeDScene):
|
||||
CONFIG = {
|
||||
"three_d_axes_config": {
|
||||
"x_min": -5,
|
||||
"x_max": 5,
|
||||
"y_min": -5,
|
||||
"y_max": 5,
|
||||
},
|
||||
"surface_resolution": 32,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
axes = self.get_axes()
|
||||
axes.scale(0.5, about_point=ORIGIN)
|
||||
self.set_camera_to_default_position()
|
||||
self.begin_ambient_camera_rotation()
|
||||
|
||||
def func(x, y):
|
||||
return np.array([
|
||||
x, y,
|
||||
2.7 + 0.5 * (np.sin(x) + np.cos(y)) -
|
||||
0.025 * (x**2 + y**2)
|
||||
])
|
||||
|
||||
surface_config = {
|
||||
"u_min": -5,
|
||||
"u_max": 5,
|
||||
"v_min": -5,
|
||||
"v_max": 5,
|
||||
"resolution": self.surface_resolution,
|
||||
}
|
||||
# plane = ParametricSurface(
|
||||
# lambda u, v: np.array([u, v, 0]),
|
||||
# **surface_config
|
||||
# )
|
||||
# plane.set_stroke(WHITE, width=0.1)
|
||||
# plane.set_fill(WHITE, opacity=0.1)
|
||||
plane = Square(
|
||||
side_length=10,
|
||||
stroke_width=0,
|
||||
fill_color=WHITE,
|
||||
fill_opacity=0.1,
|
||||
)
|
||||
plane.center()
|
||||
plane.set_shade_in_3d(True)
|
||||
|
||||
surface = ParametricSurface(
|
||||
func, **surface_config
|
||||
)
|
||||
surface.set_stroke(BLUE, width=0.1)
|
||||
surface.set_fill(BLUE, opacity=0.25)
|
||||
|
||||
self.add(axes, plane, surface)
|
||||
|
||||
point = VectorizedPoint(np.array([2, -2, 0]))
|
||||
dot = Dot()
|
||||
dot.set_color(GREEN)
|
||||
dot.add_updater(lambda d: d.move_to(point))
|
||||
line = always_redraw(lambda: DashedLine(
|
||||
point.get_location(),
|
||||
func(*point.get_location()[:2]),
|
||||
background_image_file="VerticalTempGradient",
|
||||
))
|
||||
|
||||
circle = Circle(radius=0.25)
|
||||
circle.set_color(YELLOW)
|
||||
circle.insert_n_curves(20)
|
||||
circle.add_updater(lambda m: m.move_to(point))
|
||||
circle.set_shade_in_3d(True)
|
||||
surface_circle = always_redraw(
|
||||
lambda: circle.copy().apply_function(
|
||||
lambda p: func(*p[:2])
|
||||
).shift(
|
||||
0.02 * IN
|
||||
).color_using_background_image("VerticalTempGradient")
|
||||
)
|
||||
|
||||
self.play(FadeInFromLarge(dot))
|
||||
self.play(ShowCreation(line))
|
||||
self.play(TransformFromCopy(dot, circle))
|
||||
self.play(
|
||||
Transform(
|
||||
circle.copy(),
|
||||
surface_circle.copy().clear_updaters(),
|
||||
remover=True,
|
||||
)
|
||||
)
|
||||
self.add(surface_circle)
|
||||
|
||||
self.wait()
|
||||
for vect in [4 * LEFT, DOWN, 4 * RIGHT, UP]:
|
||||
self.play(
|
||||
point.shift, vect,
|
||||
run_time=3,
|
||||
)
|
||||
|
||||
|
||||
class StrogatzMention(PiCreatureScene):
|
||||
def construct(self):
|
||||
self.show_book()
|
||||
self.show_motives()
|
||||
self.show_pages()
|
||||
|
||||
def show_book(self):
|
||||
morty = self.pi_creature
|
||||
book = ImageMobject("InfinitePowers")
|
||||
book.set_height(5)
|
||||
book.to_edge(LEFT)
|
||||
|
||||
steve = ImageMobject("Strogatz_by_bricks")
|
||||
steve.set_height(5)
|
||||
steve.to_edge(LEFT)
|
||||
|
||||
name = TextMobject("Steven Strogatz")
|
||||
name.match_width(steve)
|
||||
name.next_to(steve, DOWN)
|
||||
|
||||
self.think(
|
||||
"Hmm...many good\\\\lessons here...",
|
||||
run_time=1
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(steve))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(book, DOWN),
|
||||
steve.shift, 4 * RIGHT,
|
||||
RemovePiCreatureBubble(
|
||||
morty, target_mode="thinking"
|
||||
)
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
FadeOut(steve),
|
||||
FadeOut(morty),
|
||||
)
|
||||
|
||||
self.book = book
|
||||
|
||||
def show_motives(self):
|
||||
motives = VGroup(
|
||||
TextMobject("1) Scratch and itch"),
|
||||
TextMobject("2) Make people love math"),
|
||||
)
|
||||
motives.scale(1.5)
|
||||
motives.arrange(
|
||||
DOWN, LARGE_BUFF,
|
||||
aligned_edge=LEFT,
|
||||
)
|
||||
motives.move_to(
|
||||
Line(
|
||||
self.book.get_right(),
|
||||
FRAME_WIDTH * RIGHT / 2
|
||||
)
|
||||
)
|
||||
motives.to_edge(UP)
|
||||
|
||||
for motive in motives:
|
||||
self.play(FadeInFromDown(motive))
|
||||
self.wait(2)
|
||||
self.play(FadeOut(motives))
|
||||
|
||||
def show_pages(self):
|
||||
book = self.book
|
||||
pages = Group(*[
|
||||
ImageMobject("IP_Sample_Page{}".format(i))
|
||||
for i in range(1, 4)
|
||||
])
|
||||
for page in pages:
|
||||
page.match_height(book)
|
||||
page.next_to(book, RIGHT)
|
||||
|
||||
last_page = VectorizedPoint()
|
||||
for page in pages:
|
||||
self.play(
|
||||
FadeOut(last_page),
|
||||
FadeIn(page)
|
||||
)
|
||||
self.wait()
|
||||
last_page = page
|
||||
|
||||
self.play(FadeOut(last_page))
|
||||
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().to_corner(DR)
|
||||
|
||||
|
||||
class Thumbnail(Scene):
|
||||
def construct(self):
|
||||
image = ImageMobject("HeatSurfaceExampleFlipped")
|
||||
image.set_height(6.5)
|
||||
image.to_edge(DOWN, buff=-SMALL_BUFF)
|
||||
self.add(image)
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha", "\\nabla^2 {T}",
|
||||
tex_to_color_map={
|
||||
"{t}": YELLOW,
|
||||
"{T}": RED,
|
||||
}
|
||||
)
|
||||
equation.scale(2)
|
||||
equation.to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
|
||||
Group(equation, image).shift(1.5 * RIGHT)
|
||||
|
||||
question = TextMobject("What is\\\\this?")
|
||||
question.scale(2.5)
|
||||
question.to_edge(LEFT)
|
||||
arrow = Arrow(
|
||||
question.get_top(),
|
||||
equation.get_left(),
|
||||
buff=0.5,
|
||||
path_arc=-90 * DEGREES,
|
||||
)
|
||||
arrow.set_stroke(width=5)
|
||||
|
||||
self.add(question, arrow)
|
||||
|
||||
|
||||
class ShowNewton(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class ShowCupOfWater(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
@@ -1,785 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WriteHeatEquationTemplate(Scene):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{T}": WHITE,
|
||||
"{t}": YELLOW,
|
||||
"{x}": GREEN,
|
||||
"{y}": RED,
|
||||
"{z}": BLUE,
|
||||
"\\partial": WHITE,
|
||||
"2": WHITE,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def get_d1_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}({x}, {t})", "=",
|
||||
"\\alpha \\cdot",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} ({x}, {t})",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d1_equation_without_inputs(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha \\cdot",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d3_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha \\left(",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {y}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {z}^2}",
|
||||
"\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_general_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha", "\\nabla^2 {T}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
|
||||
def get_d3_equation_with_inputs(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}",
|
||||
"({x}, {y}, {z}, {t})", "=",
|
||||
"\\alpha \\left(",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2}",
|
||||
"({x}, {y}, {z}, {t}) + ",
|
||||
"{\\partial^2 {T} \\over \\partial {y}^2}",
|
||||
"({x}, {y}, {z}, {t}) + ",
|
||||
"{\\partial^2 {T} \\over \\partial {z}^2}",
|
||||
"({x}, {y}, {z}, {t})",
|
||||
"\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d1_words(self):
|
||||
return TextMobject("Heat equation\\\\", "(1 dimension)")
|
||||
|
||||
def get_d3_words(self):
|
||||
return TextMobject("Heat equation\\\\", "(3 dimensions)")
|
||||
|
||||
def get_d1_group(self):
|
||||
group = VGroup(
|
||||
self.get_d1_words(),
|
||||
self.get_d1_equation(),
|
||||
)
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
def get_d3_group(self):
|
||||
group = VGroup(
|
||||
self.get_d3_words(),
|
||||
self.get_d3_equation(),
|
||||
)
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
|
||||
class HeatEquationIntroTitle(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
scale_factor = 1.25
|
||||
title = TextMobject("The Heat Equation")
|
||||
title.scale(scale_factor)
|
||||
title.to_edge(UP)
|
||||
|
||||
equation = self.get_general_equation()
|
||||
equation.scale(scale_factor)
|
||||
equation.next_to(title, DOWN, MED_LARGE_BUFF)
|
||||
equation.set_color_by_tex("{T}", RED)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(title, DOWN),
|
||||
FadeInFrom(equation, UP),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class BringTogether(Scene):
|
||||
def construct(self):
|
||||
arrows = VGroup(Vector(2 * RIGHT), Vector(2 * LEFT))
|
||||
arrows.arrange(RIGHT, buff=2)
|
||||
words = TextMobject("Bring together")[0]
|
||||
words.next_to(arrows, DOWN)
|
||||
words.save_state()
|
||||
words.space_out_submobjects(1.2)
|
||||
|
||||
self.play(
|
||||
VFadeIn(words),
|
||||
Restore(words),
|
||||
arrows.arrange, RIGHT, {"buff": SMALL_BUFF},
|
||||
VFadeIn(arrows),
|
||||
)
|
||||
self.play(FadeOut(words), FadeOut(arrows))
|
||||
|
||||
|
||||
class FourierSeriesIntro(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
title_scale_value = 1.5
|
||||
|
||||
title = TextMobject(
|
||||
"Fourier ", "Series",
|
||||
)
|
||||
title.scale(title_scale_value)
|
||||
title.to_edge(UP)
|
||||
title.generate_target()
|
||||
|
||||
details_coming = TextMobject("Details coming...")
|
||||
details_coming.next_to(title.get_corner(DR), DOWN)
|
||||
details_coming.set_color(LIGHT_GREY)
|
||||
|
||||
# physics = TextMobject("Physics")
|
||||
heat = TextMobject("Heat")
|
||||
heat.scale(title_scale_value)
|
||||
physics = self.get_general_equation()
|
||||
physics.set_color_by_tex("{T}", RED)
|
||||
arrow1 = Arrow(LEFT, RIGHT)
|
||||
arrow2 = Arrow(LEFT, RIGHT)
|
||||
group = VGroup(
|
||||
heat, arrow1, physics, arrow2, title.target
|
||||
)
|
||||
group.arrange(RIGHT)
|
||||
# physics.align_to(title.target, UP)
|
||||
group.to_edge(UP)
|
||||
|
||||
rot_square = Square()
|
||||
rot_square.fade(1)
|
||||
rot_square.add_updater(lambda m, dt: m.rotate(dt))
|
||||
|
||||
def update_heat_colors(heat):
|
||||
colors = [YELLOW, RED]
|
||||
vertices = rot_square.get_vertices()
|
||||
letters = heat.family_members_with_points()
|
||||
for letter, vertex in zip(letters, vertices):
|
||||
alpha = (normalize(vertex)[0] + 1) / 2
|
||||
i, sa = integer_interpolate(0, len(colors) - 1, alpha)
|
||||
letter.set_color(interpolate_color(
|
||||
colors[i], colors[i + 1], alpha,
|
||||
))
|
||||
heat.add_updater(update_heat_colors)
|
||||
|
||||
image = ImageMobject("Joseph Fourier")
|
||||
image.set_height(5)
|
||||
image.next_to(title, DOWN, LARGE_BUFF)
|
||||
image.to_edge(LEFT)
|
||||
name = TextMobject("Joseph", "Fourier")
|
||||
name.next_to(image, DOWN)
|
||||
|
||||
bubble = ThoughtBubble(
|
||||
height=2,
|
||||
width=2.5,
|
||||
direction=RIGHT,
|
||||
)
|
||||
bubble.set_fill(opacity=0)
|
||||
bubble.set_stroke(WHITE)
|
||||
bubble.set_stroke(BLACK, 5, background=True)
|
||||
bubble.shift(heat.get_center() - bubble.get_bubble_center())
|
||||
bubble[:-1].shift(LEFT + 0.2 * DOWN)
|
||||
bubble[:-1].rotate(-20 * DEGREES)
|
||||
for mob in bubble[:-1]:
|
||||
mob.rotate(20 * DEGREES)
|
||||
|
||||
# self.play(FadeInFromDown(title))
|
||||
self.add(title)
|
||||
self.play(
|
||||
FadeInFromDown(image),
|
||||
TransformFromCopy(
|
||||
title.get_part_by_tex("Fourier"),
|
||||
name.get_part_by_tex("Fourier"),
|
||||
path_arc=90 * DEGREES,
|
||||
),
|
||||
FadeIn(name.get_part_by_tex("Joseph")),
|
||||
)
|
||||
self.play(Write(details_coming, run_time=1))
|
||||
self.play(LaggedStartMap(FadeOut, details_coming[0], run_time=1))
|
||||
self.wait()
|
||||
self.add(rot_square)
|
||||
self.play(
|
||||
FadeInFrom(physics, RIGHT),
|
||||
GrowArrow(arrow2),
|
||||
FadeInFrom(heat, RIGHT),
|
||||
GrowArrow(arrow1),
|
||||
MoveToTarget(title),
|
||||
)
|
||||
self.play(ShowCreation(bubble))
|
||||
self.wait(10)
|
||||
|
||||
|
||||
class CompareODEToPDE(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class TodaysTargetWrapper(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class TwoGraphTypeTitles(Scene):
|
||||
def construct(self):
|
||||
left_title = TextMobject(
|
||||
"Represent time\\\\with actual time"
|
||||
)
|
||||
left_title.shift(FRAME_WIDTH * LEFT / 4)
|
||||
right_title = TextMobject(
|
||||
"Represent time\\\\with an axis"
|
||||
)
|
||||
right_title.shift(FRAME_WIDTH * RIGHT / 4)
|
||||
|
||||
titles = VGroup(left_title, right_title)
|
||||
for title in titles:
|
||||
title.scale(1.25)
|
||||
title.to_edge(UP)
|
||||
|
||||
self.play(FadeInFromDown(right_title))
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(left_title))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowPartialDerivativeSymbols(Scene):
|
||||
def construct(self):
|
||||
t2c = {
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
d_derivs, del_derivs = VGroup(*[
|
||||
VGroup(*[
|
||||
TexMobject(
|
||||
"{" + sym, "T", "\\over", sym, var + "}",
|
||||
"(", "{x}", ",", "{t}", ")",
|
||||
).set_color_by_tex_to_color_map(t2c)
|
||||
for var in ("{x}", "{t}")
|
||||
])
|
||||
for sym in ("d", "\\partial")
|
||||
])
|
||||
dTdx, dTdt = d_derivs
|
||||
delTdelx, delTdelx = del_derivs
|
||||
dels = VGroup(*it.chain(*[
|
||||
del_deriv.get_parts_by_tex("\\partial")
|
||||
for del_deriv in del_derivs
|
||||
]))
|
||||
|
||||
dTdx.to_edge(UP)
|
||||
self.play(FadeInFrom(dTdx, DOWN))
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(dTdx[3:5]))
|
||||
self.play(ShowCreationThenFadeAround(dTdx[:2]))
|
||||
self.wait()
|
||||
|
||||
dTdt.move_to(dTdx)
|
||||
self.play(
|
||||
dTdx.next_to, dTdt, RIGHT, {"buff": 1.5},
|
||||
dTdx.set_opacity, 0.5,
|
||||
FadeInFromDown(dTdt)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
for m1, m2 in zip(d_derivs, del_derivs):
|
||||
m2.move_to(m1)
|
||||
|
||||
pd_words = TextMobject("Partial derivatives")
|
||||
pd_words.next_to(del_derivs, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
Write(pd_words),
|
||||
dTdx.set_opacity, 1,
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(d_derivs, del_derivs)
|
||||
)
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
dels,
|
||||
surrounding_rectangle_config={
|
||||
"color": BLUE,
|
||||
"buff": 0.5 * SMALL_BUFF,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
num_words = VGroup(*[
|
||||
TextMobject(
|
||||
"Change in $T$\\\\caused by {}",
|
||||
"$\\partial$", "${}$".format(var),
|
||||
arg_separator="",
|
||||
).set_color_by_tex_to_color_map(t2c)
|
||||
for var in ("{x}", "{t}")
|
||||
])
|
||||
num_words.scale(0.8)
|
||||
for word, deriv in zip(num_words, del_derivs):
|
||||
num = deriv[:2]
|
||||
word.move_to(num, UP)
|
||||
word.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
deriv.rect = SurroundingRectangle(
|
||||
num,
|
||||
buff=SMALL_BUFF,
|
||||
stroke_width=2,
|
||||
color=word[-1].get_color(),
|
||||
)
|
||||
deriv.rect.mob = num
|
||||
deriv.rect.add_updater(lambda r: r.move_to(r.mob))
|
||||
|
||||
self.play(
|
||||
Write(num_words[1]),
|
||||
VGroup(del_derivs, pd_words).shift, DOWN,
|
||||
ShowCreation(del_derivs[1].rect),
|
||||
)
|
||||
self.play(
|
||||
Write(num_words[0]),
|
||||
ShowCreation(del_derivs[0].rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WriteHeatEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
title = TextMobject("The Heat Equation")
|
||||
title.to_edge(UP)
|
||||
|
||||
equation = self.get_d1_equation()
|
||||
equation.next_to(title, DOWN)
|
||||
|
||||
eq_i = equation.index_of_part_by_tex("=")
|
||||
dt_part = equation[:eq_i]
|
||||
dx_part = equation[eq_i + 3:]
|
||||
dt_rect = SurroundingRectangle(dt_part)
|
||||
dt_rect.set_stroke(YELLOW, 2)
|
||||
dx_rect = SurroundingRectangle(dx_part)
|
||||
dx_rect.set_stroke(GREEN, 2)
|
||||
|
||||
two_outlines = equation.get_parts_by_tex("2").copy()
|
||||
two_outlines.set_stroke(YELLOW, 2)
|
||||
two_outlines.set_fill(opacity=0)
|
||||
|
||||
to_be_explained = TextMobject(
|
||||
"To be explained shortly..."
|
||||
)
|
||||
to_be_explained.scale(0.7)
|
||||
to_be_explained.next_to(equation, RIGHT, MED_LARGE_BUFF)
|
||||
to_be_explained.fade(1)
|
||||
|
||||
pde = TextMobject("Partial Differential Equation")
|
||||
pde.move_to(title)
|
||||
|
||||
del_outlines = equation.get_parts_by_tex("\\partial").copy()
|
||||
del_outlines.set_stroke(YELLOW, 2)
|
||||
del_outlines.set_fill(opacity=0)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(title, 0.5 * DOWN),
|
||||
FadeInFrom(equation, 0.5 * UP),
|
||||
)
|
||||
self.wait()
|
||||
self.play(ShowCreation(dt_rect))
|
||||
self.wait()
|
||||
self.play(TransformFromCopy(dt_rect, dx_rect))
|
||||
self.play(ShowCreationThenDestruction(two_outlines))
|
||||
self.wait()
|
||||
self.play(Write(to_be_explained, run_time=1))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ShowCreationThenDestruction(
|
||||
del_outlines,
|
||||
lag_ratio=0.1,
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
FadeOutAndShift(title, UP),
|
||||
FadeInFrom(pde, DOWN),
|
||||
FadeOut(dt_rect),
|
||||
FadeOut(dx_rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class Show3DEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d3_equation_with_inputs()
|
||||
equation.set_width(FRAME_WIDTH - 1)
|
||||
inputs = VGroup(*it.chain(*[
|
||||
equation.get_parts_by_tex(s)
|
||||
for s in ["{x}", "{y}", "{z}", "{t}"]
|
||||
]))
|
||||
inputs.sort()
|
||||
equation.to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
self.play(LaggedStartMap(
|
||||
ShowCreationThenFadeAround, inputs,
|
||||
surrounding_rectangle_config={
|
||||
"buff": 0.05,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class Show1DAnd3DEquations(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
d1_group = self.get_d1_group()
|
||||
d3_group = self.get_d3_group()
|
||||
d1_words, d1_equation = d1_group
|
||||
d3_words, d3_equation = d3_group
|
||||
|
||||
groups = VGroup(d1_group, d3_group)
|
||||
for group in groups:
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
groups.arrange(RIGHT, buff=1.5)
|
||||
groups.to_edge(UP)
|
||||
|
||||
d3_rhs = d3_equation[9:-2]
|
||||
d3_brace = Brace(d3_rhs, DOWN)
|
||||
nabla_words = TextMobject("Sometimes written as")
|
||||
nabla_words.match_width(d3_brace)
|
||||
nabla_words.next_to(d3_brace, DOWN)
|
||||
nabla_exp = TexMobject(
|
||||
"\\nabla^2 {T}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
nabla_exp.next_to(nabla_words, DOWN)
|
||||
# nabla_group = VGroup(nabla_words, nabla_exp)
|
||||
|
||||
d1_group.save_state()
|
||||
d1_group.center().to_edge(UP)
|
||||
|
||||
self.play(
|
||||
Write(d1_words),
|
||||
FadeInFrom(d1_equation, UP),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
Restore(d1_group),
|
||||
FadeInFrom(d3_group, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
GrowFromCenter(d3_brace),
|
||||
Write(nabla_words),
|
||||
TransformFromCopy(d3_rhs, nabla_exp),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class D1EquationNoInputs(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation_without_inputs()
|
||||
equation.to_edge(UP)
|
||||
# i1 = equation.index_of_part_by_tex("\\partial")
|
||||
# i2 = equation.index_of_part_by_tex("\\cdot")
|
||||
# equation[i1:i1 + 2].set_color(RED)
|
||||
# equation[i2 + 1:i2 + 6].set_color(RED)
|
||||
equation.set_color_by_tex("{T}", RED)
|
||||
self.add(equation)
|
||||
|
||||
|
||||
class AltHeatRHS(Scene):
|
||||
def construct(self):
|
||||
formula = TexMobject(
|
||||
"{\\alpha \\over 2}", "\\Big(",
|
||||
"T({x} - 1, {t}) + T({x} + 1, {t})"
|
||||
"\\Big)",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
self.add(formula)
|
||||
|
||||
|
||||
class CompareInputsOfGeneralCaseTo1D(WriteHeatEquation):
|
||||
def construct(self):
|
||||
three_d_expr, one_d_expr = [
|
||||
TexMobject(
|
||||
"{T}(" + inputs + ", {t})",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
for inputs in ["{x}, {y}, {z}", "{x}"]
|
||||
]
|
||||
for expr in three_d_expr, one_d_expr:
|
||||
expr.scale(2)
|
||||
expr.to_edge(UP)
|
||||
|
||||
x, y, z = [
|
||||
three_d_expr.get_part_by_tex(letter)
|
||||
for letter in ["x", "y", "z"]
|
||||
]
|
||||
|
||||
self.play(FadeInFromDown(three_d_expr))
|
||||
self.play(LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
VGroup(x, y, z)
|
||||
))
|
||||
self.wait()
|
||||
low = 3
|
||||
high = -3
|
||||
self.play(
|
||||
ReplacementTransform(three_d_expr[:low], one_d_expr[:low]),
|
||||
ReplacementTransform(three_d_expr[high:], one_d_expr[high:]),
|
||||
three_d_expr[low:high].scale, 0,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowLaplacian(WriteHeatEquation):
|
||||
def construct(self):
|
||||
equation = self.get_d3_equation()
|
||||
equation.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
parts = VGroup()
|
||||
plusses = VGroup()
|
||||
for char in "xyz":
|
||||
index = equation.index_of_part_by_tex(
|
||||
"{" + char + "}"
|
||||
)
|
||||
part = equation[index - 6:index + 3]
|
||||
rect = SurroundingRectangle(part)
|
||||
rect.match_color(equation[index])
|
||||
parts.add(part)
|
||||
part.rect = rect
|
||||
if char in "yz":
|
||||
plus = equation[index - 8]
|
||||
part.plus = plus
|
||||
plusses.add(plus)
|
||||
|
||||
lp = equation.get_part_by_tex("(")
|
||||
rp = equation.get_part_by_tex(")")
|
||||
|
||||
for part in parts:
|
||||
part.rp = rp.copy()
|
||||
part.rp.next_to(part, RIGHT, SMALL_BUFF)
|
||||
part.rp.align_to(lp, UP)
|
||||
rp.become(parts[0].rp)
|
||||
|
||||
# Show new second derivatives
|
||||
self.add(*equation)
|
||||
self.remove(*plusses, *parts[1], *parts[2])
|
||||
for part in parts[1:]:
|
||||
self.play(
|
||||
rp.become, part.rp,
|
||||
FadeInFrom(part, LEFT),
|
||||
Write(part.plus),
|
||||
ShowCreation(part.rect),
|
||||
)
|
||||
self.play(
|
||||
FadeOut(part.rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Show laplacian
|
||||
brace = Brace(parts, DOWN)
|
||||
laplacian = TexMobject("\\nabla^2", "T")
|
||||
laplacian.next_to(brace, DOWN)
|
||||
laplacian_name = TextMobject(
|
||||
"``Laplacian''"
|
||||
)
|
||||
laplacian_name.next_to(laplacian, DOWN)
|
||||
|
||||
T_parts = VGroup(*[part[3] for part in parts])
|
||||
non_T_parts = VGroup(*[
|
||||
VGroup(*part[:3], *part[4:])
|
||||
for part in parts
|
||||
])
|
||||
|
||||
self.play(GrowFromCenter(brace))
|
||||
self.play(Write(laplacian_name))
|
||||
self.play(
|
||||
TransformFromCopy(non_T_parts, laplacian[0])
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(T_parts, laplacian[1])
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class AskAboutActuallySolving(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.center()
|
||||
|
||||
q1 = TextMobject("Solve for T?")
|
||||
q1.next_to(equation, UP, LARGE_BUFF)
|
||||
q2 = TextMobject("What does it \\emph{mean} to solve this?")
|
||||
q2.next_to(equation, UP, LARGE_BUFF)
|
||||
formula = TexMobject(
|
||||
"T({x}, {t}) = \\sin\\big(a{x}\\big) e^{-\\alpha \\cdot a^2 {t}}",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
formula.next_to(equation, DOWN, LARGE_BUFF)
|
||||
q3 = TextMobject("Is this it?")
|
||||
arrow = Vector(LEFT, color=WHITE)
|
||||
arrow.next_to(formula, RIGHT)
|
||||
q3.next_to(arrow, RIGHT)
|
||||
|
||||
self.add(equation)
|
||||
self.play(FadeInFromDown(q1))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(q2),
|
||||
q1.shift, 1.5 * UP,
|
||||
)
|
||||
self.play(FadeInFrom(formula, UP))
|
||||
self.play(
|
||||
GrowArrow(arrow),
|
||||
FadeInFrom(q3, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class PDEPatreonEndscreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"specific_patrons": [
|
||||
"Juan Benet",
|
||||
"Vassili Philippov",
|
||||
"Burt Humburg",
|
||||
"Matt Russell",
|
||||
"Scott Gray",
|
||||
"soekul",
|
||||
"Tihan Seale",
|
||||
"Richard Barthel",
|
||||
"Ali Yahya",
|
||||
"dave nicponski",
|
||||
"Evan Phillips",
|
||||
"Graham",
|
||||
"Joseph Kelly",
|
||||
"Kaustuv DeBiswas",
|
||||
"LambdaLabs",
|
||||
"Lukas Biewald",
|
||||
"Mike Coleman",
|
||||
"Peter Mcinerney",
|
||||
"Quantopian",
|
||||
"Roy Larson",
|
||||
"Scott Walter, Ph.D.",
|
||||
"Yana Chernobilsky",
|
||||
"Yu Jun",
|
||||
"Jordan Scales",
|
||||
"D. Sivakumar",
|
||||
"Lukas -krtek.net- Novy",
|
||||
"John Shaughnessy",
|
||||
"Britt Selvitelle",
|
||||
"David Gow",
|
||||
"J",
|
||||
"Jonathan Wilson",
|
||||
"Joseph John Cox",
|
||||
"Magnus Dahlström",
|
||||
"Randy C. Will",
|
||||
"Ryan Atallah",
|
||||
"Luc Ritchie",
|
||||
"1stViewMaths",
|
||||
"Adrian Robinson",
|
||||
"Alexis Olson",
|
||||
"Andreas Benjamin Brössel",
|
||||
"Andrew Busey",
|
||||
"Ankalagon",
|
||||
"Antoine Bruguier",
|
||||
"Antonio Juarez",
|
||||
"Arjun Chakroborty",
|
||||
"Art Ianuzzi",
|
||||
"Awoo",
|
||||
"Bernd Sing",
|
||||
"Boris Veselinovich",
|
||||
"Brian Staroselsky",
|
||||
"Chad Hurst",
|
||||
"Charles Southerland",
|
||||
"Chris Connett",
|
||||
"Christian Kaiser",
|
||||
"Clark Gaebel",
|
||||
"Cooper Jones",
|
||||
"Danger Dai",
|
||||
"Dave B",
|
||||
"Dave Kester",
|
||||
"David B. Hill",
|
||||
"David Clark",
|
||||
"DeathByShrimp",
|
||||
"Delton Ding",
|
||||
"eaglle",
|
||||
"emptymachine",
|
||||
"Eric Younge",
|
||||
"Eryq Ouithaqueue",
|
||||
"Federico Lebron",
|
||||
"Giovanni Filippi",
|
||||
"Hal Hildebrand",
|
||||
"Hitoshi Yamauchi",
|
||||
"Isaac Jeffrey Lee",
|
||||
"j eduardo perez",
|
||||
"Jacob Magnuson",
|
||||
"Jameel Syed",
|
||||
"Jason Hise",
|
||||
"Jeff Linse",
|
||||
"Jeff Straathof",
|
||||
"John Griffith",
|
||||
"John Haley",
|
||||
"John V Wertheim",
|
||||
"Jonathan Eppele",
|
||||
"Kai-Siang Ang",
|
||||
"Kanan Gill",
|
||||
"L0j1k",
|
||||
"Lee Beck",
|
||||
"Lee Redden",
|
||||
"Linh Tran",
|
||||
"Ludwig Schubert",
|
||||
"Magister Mugit",
|
||||
"Mark B Bahu",
|
||||
"Mark Heising",
|
||||
"Martin Price",
|
||||
"Mathias Jansson",
|
||||
"Matt Langford",
|
||||
"Matt Roveto",
|
||||
"Matthew Bouchard",
|
||||
"Matthew Cocke",
|
||||
"Michael Faust",
|
||||
"Michael Hardel",
|
||||
"Mirik Gogri",
|
||||
"Mustafa Mahdi",
|
||||
"Márton Vaitkus",
|
||||
"Nero Li",
|
||||
"Nikita Lesnikov",
|
||||
"Omar Zrien",
|
||||
"Owen Campbell-Moore",
|
||||
"Peter Ehrnstrom",
|
||||
"RedAgent14",
|
||||
"rehmi post",
|
||||
"Richard Burgmann",
|
||||
"Richard Comish",
|
||||
"Ripta Pasay",
|
||||
"Rish Kundalia",
|
||||
"Robert Teed",
|
||||
"Roobie",
|
||||
"Ryan Williams",
|
||||
"Sachit Nagpal",
|
||||
"Solara570",
|
||||
"Stevie Metke",
|
||||
"Tal Einav",
|
||||
"Ted Suzman",
|
||||
"Thomas Tarler",
|
||||
"Tom Fleming",
|
||||
"Valeriy Skobelev",
|
||||
"Xavier Bernard",
|
||||
"Yavor Ivanov",
|
||||
"Yaw Etse",
|
||||
"YinYangBalance.Asia",
|
||||
"Zach Cardwell",
|
||||
],
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
|
||||
|
||||
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_min": 0,
|
||||
"stroke_width": 1,
|
||||
"x_axis_config": {
|
||||
"include_tip": False,
|
||||
},
|
||||
},
|
||||
"freq_amplitude_pairs": [
|
||||
(1, 0.5),
|
||||
(2, 1),
|
||||
(3, 0.5),
|
||||
(4, 0.3),
|
||||
],
|
||||
"v_line_class": DashedLine,
|
||||
"v_line_config": {
|
||||
|
||||
},
|
||||
"step_size": 1,
|
||||
"wait_time": 15,
|
||||
"alpha": 0.25,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_axes()
|
||||
self.set_points()
|
||||
self.show_boundary_point_influenced_by_neighbor()
|
||||
self.add_clock()
|
||||
self.let_evolve()
|
||||
|
||||
def set_points(self):
|
||||
axes = self.axes
|
||||
for mob in axes.family_members_with_points():
|
||||
if isinstance(mob, Line):
|
||||
mob.set_stroke(width=1)
|
||||
|
||||
step_size = self.step_size
|
||||
xs = np.arange(
|
||||
axes.x_min,
|
||||
axes.x_max + step_size,
|
||||
step_size
|
||||
)
|
||||
|
||||
dots = self.dots = self.get_dots(axes, xs)
|
||||
self.v_lines = self.get_v_lines(dots)
|
||||
self.rod_pieces = self.get_rod_pieces(dots)
|
||||
|
||||
# rod_pieces
|
||||
|
||||
self.add(self.dots)
|
||||
self.add(self.v_lines)
|
||||
self.add(self.rod_pieces)
|
||||
|
||||
def show_boundary_point_influenced_by_neighbor(self):
|
||||
dots = self.dots
|
||||
ld = dots[0]
|
||||
ld_in = dots[1]
|
||||
rd = dots[-1]
|
||||
rd_in = dots[-2]
|
||||
v_len = 0.75
|
||||
l_arrow = Vector(v_len * LEFT)
|
||||
l_arrow.move_to(ld.get_left(), RIGHT)
|
||||
r_arrow = Vector(v_len * RIGHT)
|
||||
r_arrow.move_to(rd.get_right(), LEFT)
|
||||
arrows = VGroup(l_arrow, r_arrow)
|
||||
q_marks = VGroup(*[
|
||||
TexMobject("?").scale(1.5).next_to(
|
||||
arrow, arrow.get_vector()
|
||||
)
|
||||
for arrow in arrows
|
||||
])
|
||||
|
||||
arrows.set_color(YELLOW)
|
||||
q_marks.set_color(YELLOW)
|
||||
|
||||
blocking_rects = VGroup(*[
|
||||
BackgroundRectangle(VGroup(
|
||||
*dots[i:-i],
|
||||
*self.rod_pieces[i:-i]
|
||||
))
|
||||
for i in [1, 2]
|
||||
])
|
||||
for rect in blocking_rects:
|
||||
rect.stretch(1.1, dim=1, about_edge=UP)
|
||||
|
||||
self.play(FadeIn(blocking_rects[0]))
|
||||
self.play(
|
||||
LaggedStartMap(ShowCreation, arrows),
|
||||
LaggedStart(*[
|
||||
FadeInFrom(q_mark, -arrow.get_vector())
|
||||
for q_mark, arrow in zip(q_marks, arrows)
|
||||
]),
|
||||
run_time=1.5
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Point to inward neighbor
|
||||
new_arrows = VGroup(*[
|
||||
Arrow(
|
||||
d1.get_center(),
|
||||
VGroup(d1, d2).get_center(),
|
||||
buff=0,
|
||||
).match_style(l_arrow)
|
||||
for d1, d2 in [(ld, ld_in), (rd, rd_in)]
|
||||
])
|
||||
new_arrows.match_style(arrows)
|
||||
|
||||
l_brace = Brace(VGroup(ld, ld_in), DOWN)
|
||||
r_brace = Brace(VGroup(rd, rd_in), DOWN)
|
||||
braces = VGroup(l_brace, r_brace)
|
||||
for brace in braces:
|
||||
brace.align_to(
|
||||
self.axes.x_axis.get_center(), UP
|
||||
)
|
||||
brace.shift(SMALL_BUFF * DOWN)
|
||||
brace.add(brace.get_tex("\\Delta x"))
|
||||
|
||||
self.play(
|
||||
ReplacementTransform(arrows, new_arrows),
|
||||
FadeOut(q_marks),
|
||||
ReplacementTransform(*blocking_rects)
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(braces, UP))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(new_arrows),
|
||||
FadeOut(blocking_rects[1]),
|
||||
FadeOut(braces),
|
||||
)
|
||||
|
||||
def add_clock(self):
|
||||
super().add_clock()
|
||||
self.time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
VGroup(
|
||||
self.clock,
|
||||
self.time_label
|
||||
).shift(2 * LEFT)
|
||||
|
||||
def let_evolve(self):
|
||||
dots = self.dots
|
||||
dots.add_updater(self.update_dots)
|
||||
|
||||
wait_time = self.wait_time
|
||||
self.play(
|
||||
ClockPassesTime(
|
||||
self.clock,
|
||||
run_time=wait_time,
|
||||
hours_passed=wait_time,
|
||||
),
|
||||
)
|
||||
|
||||
#
|
||||
|
||||
def get_dots(self, axes, xs):
|
||||
dots = VGroup(*[
|
||||
Dot(axes.c2p(x, self.temp_func(x, 0)))
|
||||
for x in xs
|
||||
])
|
||||
|
||||
max_width = 0.8 * self.step_size
|
||||
for dot in dots:
|
||||
dot.add_updater(self.update_dot_color)
|
||||
if dot.get_width() > max_width:
|
||||
dot.set_width(max_width)
|
||||
|
||||
return dots
|
||||
|
||||
def get_v_lines(self, dots):
|
||||
return always_redraw(lambda: VGroup(*[
|
||||
self.get_v_line(dot)
|
||||
for dot in dots
|
||||
]))
|
||||
|
||||
def get_v_line(self, dot):
|
||||
x_axis = self.axes.x_axis
|
||||
bottom = dot.get_bottom()
|
||||
x = x_axis.p2n(bottom)
|
||||
proj_point = x_axis.n2p(x)
|
||||
return self.v_line_class(
|
||||
proj_point, bottom,
|
||||
**self.v_line_config,
|
||||
)
|
||||
|
||||
def get_rod_pieces(self, dots):
|
||||
axis = self.axes.x_axis
|
||||
factor = 1 - np.exp(-(0.8 / self.step_size)**2)
|
||||
width = factor * self.step_size
|
||||
|
||||
pieces = VGroup()
|
||||
for dot in dots:
|
||||
piece = Line(ORIGIN, width * RIGHT)
|
||||
piece.set_stroke(width=5)
|
||||
piece.move_to(dot)
|
||||
piece.set_y(axis.get_center()[1])
|
||||
piece.dot = dot
|
||||
piece.add_updater(
|
||||
lambda p: p.match_color(p.dot)
|
||||
)
|
||||
pieces.add(piece)
|
||||
return pieces
|
||||
|
||||
def update_dot_color(self, dot):
|
||||
y = self.axes.y_axis.p2n(dot.get_center())
|
||||
dot.set_color(self.y_to_color(y))
|
||||
|
||||
def update_dots(self, dots, dt):
|
||||
for ds in zip(dots, dots[1:], dots[2:]):
|
||||
points = [d.get_center() for d in ds]
|
||||
x0, x1, x2 = [p[0] for p in points]
|
||||
dx = x1 - x0
|
||||
y0, y1, y2 = [p[1] for p in points]
|
||||
|
||||
self.update_dot(
|
||||
dot=ds[1],
|
||||
dt=dt,
|
||||
mean_diff=0.5 * (y2 - 2 * y1 + y0) / dx
|
||||
)
|
||||
if ds[0] is dots[0]:
|
||||
self.update_dot(
|
||||
dot=ds[0],
|
||||
dt=dt,
|
||||
mean_diff=(y1 - y0) / dx
|
||||
)
|
||||
elif ds[-1] is dots[-1]:
|
||||
self.update_dot(
|
||||
dot=ds[-1],
|
||||
dt=dt,
|
||||
mean_diff=(y1 - y2) / dx
|
||||
)
|
||||
|
||||
def update_dot(self, dot, dt, mean_diff):
|
||||
dot.shift(mean_diff * self.alpha * dt * UP)
|
||||
|
||||
|
||||
class DiscreteEvolutionPoint25(ShowNewRuleAtDiscreteBoundary):
|
||||
CONFIG = {
|
||||
"step_size": 0.25,
|
||||
"alpha": 0.5,
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_axes()
|
||||
self.set_points()
|
||||
self.add_clock()
|
||||
self.let_evolve()
|
||||
|
||||
|
||||
class DiscreteEvolutionPoint1(DiscreteEvolutionPoint25):
|
||||
CONFIG = {
|
||||
"step_size": 0.1,
|
||||
"v_line_config": {
|
||||
"stroke_width": 1,
|
||||
},
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
|
||||
class FlatEdgesForDiscreteEvolution(DiscreteEvolutionPoint1):
|
||||
CONFIG = {
|
||||
"wait_time": 20,
|
||||
"step_size": 0.1,
|
||||
}
|
||||
|
||||
def let_evolve(self):
|
||||
lines = VGroup(*[
|
||||
Line(LEFT, RIGHT)
|
||||
for x in range(2)
|
||||
])
|
||||
lines.set_width(1.5)
|
||||
lines.set_stroke(WHITE, 5, opacity=0.5)
|
||||
lines.add_updater(self.update_lines)
|
||||
|
||||
turn_animation_into_updater(
|
||||
ShowCreation(lines, run_time=2)
|
||||
)
|
||||
self.add(lines)
|
||||
|
||||
super().let_evolve()
|
||||
|
||||
def update_lines(self, lines):
|
||||
dots = self.dots
|
||||
for line, dot in zip(lines, [dots[0], dots[-1]]):
|
||||
line.move_to(dot)
|
||||
|
||||
|
||||
class FlatEdgesForDiscreteEvolutionTinySteps(FlatEdgesForDiscreteEvolution):
|
||||
CONFIG = {
|
||||
"step_size": 0.025,
|
||||
"wait_time": 10,
|
||||
"v_line_class": Line,
|
||||
"v_line_config": {
|
||||
"stroke_opacity": 0.5,
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class IveHeardOfThis(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
point = VectorizedPoint()
|
||||
point.move_to(3 * RIGHT + 2 * UP)
|
||||
self.student_says(
|
||||
"I've heard\\\\", "of this!",
|
||||
student_index=1,
|
||||
target_mode="hooray",
|
||||
bubble_kwargs={
|
||||
"height": 3,
|
||||
"width": 3,
|
||||
"direction": RIGHT,
|
||||
},
|
||||
run_time=1,
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "hooray", "thinking",
|
||||
look_at_arg=point,
|
||||
added_anims=[self.teacher.change, "happy"]
|
||||
)
|
||||
self.wait(3)
|
||||
self.student_says(
|
||||
"But who\\\\", "cares?",
|
||||
student_index=1,
|
||||
target_mode="maybe",
|
||||
bubble_kwargs={
|
||||
"direction": RIGHT,
|
||||
"width": 3,
|
||||
"height": 3,
|
||||
},
|
||||
run_time=1,
|
||||
)
|
||||
self.change_student_modes(
|
||||
"pondering", "maybe", "pondering",
|
||||
look_at_arg=point,
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class InFouriersShoes(PiCreatureScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
randy = self.pi_creature
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
fourier.set_height(4)
|
||||
fourier.next_to(randy, RIGHT, LARGE_BUFF)
|
||||
fourier.align_to(randy, DOWN)
|
||||
|
||||
equation = self.get_d1_equation()
|
||||
equation.next_to(fourier, UP, MED_LARGE_BUFF)
|
||||
|
||||
decades = list(range(1740, 2040, 20))
|
||||
time_line = NumberLine(
|
||||
x_min=decades[0],
|
||||
x_max=decades[-1],
|
||||
tick_frequency=1,
|
||||
tick_size=0.05,
|
||||
longer_tick_multiple=4,
|
||||
unit_size=0.2,
|
||||
numbers_with_elongated_ticks=decades,
|
||||
numbers_to_show=decades,
|
||||
decimal_number_config={
|
||||
"group_with_commas": False,
|
||||
},
|
||||
stroke_width=2,
|
||||
)
|
||||
time_line.add_numbers()
|
||||
time_line.move_to(ORIGIN, RIGHT)
|
||||
time_line.to_edge(UP)
|
||||
triangle = ArrowTip(start_angle=-90 * DEGREES)
|
||||
triangle.set_height(0.25)
|
||||
triangle.move_to(time_line.n2p(2019), DOWN)
|
||||
triangle.set_color(WHITE)
|
||||
|
||||
self.play(FadeInFrom(fourier, 2 * LEFT))
|
||||
self.play(randy.change, "pondering")
|
||||
self.wait()
|
||||
self.play(
|
||||
DrawBorderThenFill(triangle, run_time=1),
|
||||
FadeInFromDown(equation),
|
||||
FadeIn(time_line),
|
||||
)
|
||||
self.play(
|
||||
Animation(triangle),
|
||||
ApplyMethod(
|
||||
time_line.shift,
|
||||
time_line.n2p(2019) - time_line.n2p(1822),
|
||||
run_time=5
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class SineCurveIsUnrealistic(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"But that would\\\\never happen!",
|
||||
student_index=1,
|
||||
bubble_kwargs={
|
||||
"direction": RIGHT,
|
||||
"height": 3,
|
||||
"width": 4,
|
||||
},
|
||||
target_mode="angry"
|
||||
)
|
||||
self.change_student_modes(
|
||||
"guilty", "angry", "hesitant",
|
||||
added_anims=[
|
||||
self.teacher.change, "tease"
|
||||
]
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[1]),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"pondering",
|
||||
look_at_arg=3 * UP,
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class IfOnly(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says(
|
||||
"If only!",
|
||||
target_mode="angry"
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"confused",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class SoWeGotNowhere(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"So we've gotten\\\\nowhere!",
|
||||
target_mode="angry",
|
||||
added_anims=[
|
||||
self.teacher.change, "guilty"
|
||||
]
|
||||
)
|
||||
self.change_all_student_modes("angry")
|
||||
self.wait()
|
||||
text = TexMobject(
|
||||
"&\\text{Actually,}\\\\",
|
||||
"&\\sin\\left({x}\\right)"
|
||||
"e^{-\\alpha {t}}\\\\",
|
||||
"&\\text{isn't far off.}",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
text.scale(0.8)
|
||||
self.teacher_says(
|
||||
text,
|
||||
content_introduction_class=FadeIn,
|
||||
bubble_kwargs={
|
||||
"width": 4,
|
||||
"height": 3.5,
|
||||
}
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"pondering",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait(3)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,919 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class ThreeMainObservations(Scene):
|
||||
def construct(self):
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
name = TextMobject("Joseph Fourier")
|
||||
name.match_width(fourier)
|
||||
name.next_to(fourier, DOWN, SMALL_BUFF)
|
||||
fourier.add(name)
|
||||
fourier.set_height(5)
|
||||
fourier.to_corner(DR)
|
||||
fourier.shift(LEFT)
|
||||
bubble = ThoughtBubble(
|
||||
direction=RIGHT,
|
||||
height=3,
|
||||
width=4,
|
||||
)
|
||||
bubble.move_tip_to(fourier.get_corner(UL) + 0.5 * DR)
|
||||
|
||||
observations = VGroup(
|
||||
TextMobject(
|
||||
"1)",
|
||||
"Sine = Nice",
|
||||
),
|
||||
TextMobject(
|
||||
"2)",
|
||||
"Linearity"
|
||||
),
|
||||
TextMobject(
|
||||
"3)",
|
||||
"Fourier series"
|
||||
),
|
||||
)
|
||||
# heart = SuitSymbol("hearts")
|
||||
# heart.replace(observations[0][2])
|
||||
# observations[0][2].become(heart)
|
||||
# observations[0][1].add(happiness)
|
||||
# observations[2][2].align_to(
|
||||
# observations[2][1], LEFT,
|
||||
# )
|
||||
|
||||
observations.arrange(
|
||||
DOWN,
|
||||
aligned_edge=LEFT,
|
||||
buff=2 * LARGE_BUFF,
|
||||
)
|
||||
observations.set_height(FRAME_HEIGHT - 2)
|
||||
observations.to_corner(UL, buff=LARGE_BUFF)
|
||||
|
||||
self.add(fourier)
|
||||
self.play(ShowCreation(bubble))
|
||||
self.wait()
|
||||
self.play(LaggedStart(*[
|
||||
TransformFromCopy(bubble, observation[0])
|
||||
for observation in observations
|
||||
], lag_ratio=0.2))
|
||||
self.play(
|
||||
FadeOut(fourier),
|
||||
FadeOut(bubble),
|
||||
)
|
||||
self.wait()
|
||||
for obs in observations:
|
||||
self.play(FadeInFrom(obs[1], LEFT))
|
||||
self.wait()
|
||||
|
||||
|
||||
class LastChapterWrapper(Scene):
|
||||
def construct(self):
|
||||
full_rect = FullScreenFadeRectangle(
|
||||
fill_color=DARK_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
rect = ScreenRectangle(height=6)
|
||||
rect.set_stroke(WHITE, 2)
|
||||
rect.set_fill(BLACK, 1)
|
||||
title = TextMobject("Last chapter")
|
||||
title.scale(2)
|
||||
title.to_edge(UP)
|
||||
rect.next_to(title, DOWN)
|
||||
|
||||
self.add(full_rect)
|
||||
self.play(
|
||||
FadeIn(rect),
|
||||
Write(title, run_time=2),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ThreeConstraints(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
self.cross_out_solving()
|
||||
self.show_three_conditions()
|
||||
|
||||
def cross_out_solving(self):
|
||||
equation = self.get_d1_equation()
|
||||
words = TextMobject("Solve this equation")
|
||||
words.to_edge(UP)
|
||||
equation.next_to(words, DOWN)
|
||||
cross = Cross(words)
|
||||
|
||||
self.add(words, equation)
|
||||
self.wait()
|
||||
self.play(ShowCreation(cross))
|
||||
self.wait()
|
||||
|
||||
self.equation = equation
|
||||
self.to_remove = VGroup(words, cross)
|
||||
|
||||
def show_three_conditions(self):
|
||||
equation = self.equation
|
||||
to_remove = self.to_remove
|
||||
|
||||
title = TexMobject(
|
||||
"\\text{Constraints }"
|
||||
"T({x}, {t})"
|
||||
"\\text{ must satisfy:}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
title.to_edge(UP)
|
||||
|
||||
items = VGroup(
|
||||
TextMobject("1)", "The PDE"),
|
||||
TextMobject("2)", "Boundary condition"),
|
||||
TextMobject("3)", "Initial condition"),
|
||||
)
|
||||
items.scale(0.7)
|
||||
items.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
items.set_width(FRAME_WIDTH - 2)
|
||||
items.next_to(title, DOWN, LARGE_BUFF)
|
||||
items[1].set_color(MAROON_B)
|
||||
items[2].set_color(RED)
|
||||
|
||||
bc_paren = TextMobject("(Explained soon)")
|
||||
bc_paren.scale(0.7)
|
||||
bc_paren.next_to(items[1], DOWN)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(title),
|
||||
FadeOutAndShift(to_remove, UP),
|
||||
equation.scale, 0.6,
|
||||
equation.next_to, items[0], DOWN,
|
||||
equation.shift_onto_screen,
|
||||
LaggedStartMap(FadeIn, [
|
||||
items[0],
|
||||
items[1][0],
|
||||
items[2][0],
|
||||
])
|
||||
)
|
||||
self.wait()
|
||||
self.play(Write(items[1][1]))
|
||||
bc_paren.match_y(equation)
|
||||
self.play(FadeInFrom(bc_paren, UP))
|
||||
self.wait(2)
|
||||
self.play(Write(items[2][1]))
|
||||
self.wait(2)
|
||||
|
||||
self.title = title
|
||||
self.items = items
|
||||
self.pde = equation
|
||||
self.bc_paren = bc_paren
|
||||
|
||||
|
||||
class RectAroundEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
eq = self.get_d1_equation()
|
||||
self.play(ShowCreationThenFadeAround(eq))
|
||||
|
||||
|
||||
class BorderRect(Scene):
|
||||
def construct(self):
|
||||
rect = FullScreenFadeRectangle()
|
||||
rect.set_stroke(WHITE, 3)
|
||||
rect.set_fill(opacity=0)
|
||||
self.add(rect)
|
||||
|
||||
|
||||
class SeekIdealized(Scene):
|
||||
def construct(self):
|
||||
phrases = VGroup(*[
|
||||
TextMobject(
|
||||
"Seek", text, "problems",
|
||||
tex_to_color_map={
|
||||
"realistic": GREEN,
|
||||
"{idealized}": YELLOW,
|
||||
"over-idealized": YELLOW,
|
||||
"general": BLUE,
|
||||
}
|
||||
)
|
||||
for text in [
|
||||
"realistic",
|
||||
"{idealized}",
|
||||
"over-idealized",
|
||||
"general",
|
||||
]
|
||||
])
|
||||
phrases.scale(2)
|
||||
words = VGroup()
|
||||
for phrase in phrases:
|
||||
phrase.center()
|
||||
word = phrase[1]
|
||||
words.add(word)
|
||||
phrase.remove(word)
|
||||
arrow = Vector(DOWN)
|
||||
arrow.set_stroke(WHITE, 6)
|
||||
arrow.next_to(words[3], UP)
|
||||
low_arrow = arrow.copy()
|
||||
low_arrow.next_to(words[3], DOWN)
|
||||
|
||||
solutions = TextMobject("solutions")
|
||||
solutions.scale(2)
|
||||
solutions.move_to(phrases[3][1], UL)
|
||||
models = TextMobject("models")
|
||||
models.scale(2)
|
||||
models.next_to(
|
||||
words[0], RIGHT, buff=0.35,
|
||||
aligned_edge=DOWN
|
||||
)
|
||||
|
||||
phrases.center()
|
||||
phrase = phrases[0]
|
||||
|
||||
self.add(phrase)
|
||||
self.add(words[0])
|
||||
self.wait()
|
||||
words[0].save_state()
|
||||
self.play(
|
||||
words[0].to_edge, DOWN,
|
||||
words[0].set_opacity, 0.5,
|
||||
Transform(phrase, phrases[1]),
|
||||
FadeInFrom(words[1], UP)
|
||||
)
|
||||
self.wait()
|
||||
# self.play(
|
||||
# words[1].move_to, words[2], RIGHT,
|
||||
# FadeIn(words[2]),
|
||||
# Transform(phrase, phrases[2])
|
||||
# )
|
||||
# self.wait()
|
||||
self.play(
|
||||
words[1].next_to, arrow, UP,
|
||||
ShowCreation(arrow),
|
||||
MaintainPositionRelativeTo(
|
||||
phrase, words[1]
|
||||
),
|
||||
FadeInFrom(solutions, LEFT),
|
||||
FadeIn(words[3]),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
words[0].generate_target()
|
||||
words[0].target.next_to(low_arrow, DOWN)
|
||||
words[0].target.set_opacity(1)
|
||||
models.shift(
|
||||
words[0].target.get_center() -
|
||||
words[0].saved_state.get_center()
|
||||
)
|
||||
self.play(
|
||||
MoveToTarget(words[0]),
|
||||
ShowCreation(low_arrow),
|
||||
FadeInFrom(models, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class SecondDerivativeOfSine(Scene):
|
||||
def construct(self):
|
||||
equation = TexMobject(
|
||||
"{d^2 \\over d{x}^2}",
|
||||
"\\cos\\left({x}\\right) =",
|
||||
"-\\cos\\left({x}\\right)",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
}
|
||||
)
|
||||
|
||||
self.add(equation)
|
||||
|
||||
|
||||
class EquationAboveSineAnalysis(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.to_edge(UP)
|
||||
equation.shift(2 * LEFT)
|
||||
eq_index = equation.index_of_part_by_tex("=")
|
||||
lhs = equation[:eq_index]
|
||||
eq = equation[eq_index]
|
||||
rhs = equation[eq_index + 1:]
|
||||
t_terms = equation.get_parts_by_tex("{t}")[1:]
|
||||
t_terms.save_state()
|
||||
zeros = VGroup(*[
|
||||
TexMobject("0").replace(t, dim_to_match=1)
|
||||
for t in t_terms
|
||||
])
|
||||
zeros.align_to(t_terms, DOWN)
|
||||
new_rhs = TexMobject(
|
||||
"=", "-\\alpha \\cdot {T}", "({x}, 0)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
# new_rhs.move_to(equation.get_right())
|
||||
# new_rhs.next_to(equation, DOWN, MED_LARGE_BUFF)
|
||||
# new_rhs.align_to(eq, LEFT)
|
||||
new_rhs.next_to(equation, RIGHT)
|
||||
new_rhs.shift(SMALL_BUFF * DOWN)
|
||||
|
||||
self.add(equation)
|
||||
self.play(ShowCreationThenFadeAround(rhs))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOutAndShift(t_terms, UP),
|
||||
FadeInFrom(zeros, DOWN),
|
||||
)
|
||||
t_terms.fade(1)
|
||||
self.wait()
|
||||
self.play(
|
||||
# VGroup(equation, zeros).next_to,
|
||||
# new_rhs, LEFT,
|
||||
FadeIn(new_rhs),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
VGroup(
|
||||
lhs[6:],
|
||||
eq,
|
||||
rhs,
|
||||
new_rhs[0],
|
||||
new_rhs[-3:],
|
||||
zeros,
|
||||
).fade, 0.5,
|
||||
)
|
||||
self.play(ShowCreationThenFadeAround(lhs[:6]))
|
||||
self.play(ShowCreationThenFadeAround(new_rhs[1:-3]))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ExpVideoWrapper(Scene):
|
||||
def construct(self):
|
||||
self.add(FullScreenFadeRectangle(
|
||||
fill_color=DARKER_GREY,
|
||||
fill_opacity=1,
|
||||
))
|
||||
|
||||
screen = ImageMobject("eoc_chapter5_thumbnail")
|
||||
screen.set_height(6)
|
||||
rect = SurroundingRectangle(screen, buff=0)
|
||||
rect.set_stroke(WHITE, 2)
|
||||
screen.add(rect)
|
||||
title = TextMobject("Need a refresher?")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
screen.next_to(title, DOWN)
|
||||
|
||||
screen.center()
|
||||
self.play(
|
||||
# FadeInFrom(title, LEFT),
|
||||
FadeInFrom(screen, DOWN),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowSinExpDerivatives(WriteHeatEquationTemplate):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{0}": WHITE,
|
||||
"\\partial": WHITE,
|
||||
"=": WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pde = self.get_d1_equation_without_inputs()
|
||||
pde.to_edge(UP)
|
||||
pde.generate_target()
|
||||
|
||||
new_rhs = TexMobject(
|
||||
"=- \\alpha \\cdot T",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
new_rhs.next_to(pde, RIGHT)
|
||||
new_rhs.align_to(pde.get_part_by_tex("alpha"), DOWN)
|
||||
|
||||
equation1 = TexMobject(
|
||||
"T({x}, {0}) = \\sin\\left({x}\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
equation2 = TexMobject(
|
||||
"T({x}, {t}) = \\sin\\left({x}\\right)",
|
||||
"e^{-\\alpha{t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
for eq in equation1, equation2:
|
||||
eq.next_to(pde, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
eq2_part1 = equation2[:len(equation1)]
|
||||
eq2_part2 = equation2[len(equation1):]
|
||||
|
||||
# Rectangles
|
||||
exp_rect = SurroundingRectangle(eq2_part2)
|
||||
exp_rect.set_stroke(RED, 3)
|
||||
sin_rect = SurroundingRectangle(
|
||||
eq2_part1[-3:]
|
||||
)
|
||||
sin_rect.set_color(BLUE)
|
||||
|
||||
VGroup(pde.target, new_rhs).center().to_edge(UP)
|
||||
|
||||
# Show proposed solution
|
||||
self.add(pde)
|
||||
self.add(equation1)
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(pde),
|
||||
FadeInFrom(new_rhs, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(equation1, eq2_part1),
|
||||
FadeIn(eq2_part2),
|
||||
)
|
||||
self.play(ShowCreation(exp_rect))
|
||||
self.wait()
|
||||
self.play(FadeOut(exp_rect))
|
||||
|
||||
# Take partial derivatives wrt x
|
||||
q_mark = TexMobject("?")
|
||||
q_mark.next_to(pde.get_part_by_tex("="), UP)
|
||||
q_mark.set_color(RED)
|
||||
|
||||
arrow1 = Vector(3 * DOWN + 1 * RIGHT, color=WHITE)
|
||||
arrow1.scale(1.2 / arrow1.get_length())
|
||||
arrow1.next_to(
|
||||
eq2_part2.get_corner(DL),
|
||||
DOWN, MED_LARGE_BUFF
|
||||
)
|
||||
ddx_label1 = TexMobject(
|
||||
"\\partial \\over \\partial {x}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
ddx_label1.scale(0.7)
|
||||
ddx_label1.next_to(
|
||||
arrow1.point_from_proportion(0.8),
|
||||
UR, SMALL_BUFF
|
||||
)
|
||||
|
||||
pde_ddx = VGroup(
|
||||
*pde.get_parts_by_tex("\\partial")[2:],
|
||||
pde.get_parts_by_tex("\\over")[1],
|
||||
pde.get_part_by_tex("{x}"),
|
||||
)
|
||||
pde_ddx_rect = SurroundingRectangle(pde_ddx)
|
||||
pde_ddx_rect.set_color(GREEN)
|
||||
|
||||
eq2_part2_rect = SurroundingRectangle(eq2_part2)
|
||||
|
||||
dx = TexMobject(
|
||||
"\\cos\\left({x}\\right)", "e^{-\\alpha {t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
ddx = TexMobject(
|
||||
"-\\sin\\left({x}\\right)", "e^{-\\alpha {t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
dx.next_to(arrow1, DOWN)
|
||||
dx.align_to(eq2_part2, RIGHT)
|
||||
x_shift = arrow1.get_end()[0] - arrow1.get_start()[0]
|
||||
x_shift *= 2
|
||||
dx.shift(x_shift * RIGHT)
|
||||
arrow2 = arrow1.copy()
|
||||
arrow2.next_to(dx, DOWN)
|
||||
arrow2.shift(MED_SMALL_BUFF * RIGHT)
|
||||
dx_arrows = VGroup(arrow1, arrow2)
|
||||
|
||||
ddx_label2 = ddx_label1.copy()
|
||||
ddx_label2.shift(
|
||||
arrow2.get_center() - arrow1.get_center()
|
||||
)
|
||||
ddx.next_to(arrow2, DOWN)
|
||||
ddx.align_to(eq2_part2, RIGHT)
|
||||
ddx.shift(2 * x_shift * RIGHT)
|
||||
|
||||
rhs = equation2[-6:]
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(q_mark)
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(pde_ddx_rect)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(
|
||||
GrowArrow(arrow1),
|
||||
GrowArrow(arrow2),
|
||||
),
|
||||
TransformFromCopy(
|
||||
pde_ddx[0], ddx_label1
|
||||
),
|
||||
TransformFromCopy(
|
||||
pde_ddx[0], ddx_label2
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(rhs, dx)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeIn(eq2_part2_rect)
|
||||
)
|
||||
self.play(
|
||||
Transform(
|
||||
eq2_part2_rect,
|
||||
SurroundingRectangle(dx[-3:])
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
FadeOut(eq2_part2_rect)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(dx, ddx)
|
||||
)
|
||||
self.play(
|
||||
FadeIn(
|
||||
SurroundingRectangle(ddx).match_style(
|
||||
pde_ddx_rect
|
||||
)
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Take partial derivative wrt t
|
||||
pde_ddt = pde[:pde.index_of_part_by_tex("=") - 1]
|
||||
pde_ddt_rect = SurroundingRectangle(pde_ddt)
|
||||
|
||||
dt_arrow = Arrow(
|
||||
arrow1.get_start(),
|
||||
arrow2.get_end() + RIGHT,
|
||||
buff=0
|
||||
)
|
||||
dt_arrow.flip(UP)
|
||||
dt_arrow.next_to(dx_arrows, LEFT, MED_LARGE_BUFF)
|
||||
|
||||
dt_label = TexMobject(
|
||||
"\\partial \\over \\partial {t}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
dt_label.scale(1)
|
||||
dt_label.next_to(
|
||||
dt_arrow.get_center(), UL,
|
||||
SMALL_BUFF,
|
||||
)
|
||||
|
||||
rhs_copy = rhs.copy()
|
||||
rhs_copy.next_to(dt_arrow.get_end(), DOWN)
|
||||
rhs_copy.shift(MED_LARGE_BUFF * LEFT)
|
||||
rhs_copy.match_y(ddx)
|
||||
|
||||
minus_alpha_in_exp = rhs_copy[-3][1:].copy()
|
||||
minus_alpha_in_exp.set_color(RED)
|
||||
minus_alpha = TexMobject("-\\alpha")
|
||||
minus_alpha.next_to(rhs_copy, LEFT)
|
||||
minus_alpha.align_to(rhs_copy[0][0], DOWN)
|
||||
dot = TexMobject("\\cdot")
|
||||
dot.move_to(midpoint(
|
||||
minus_alpha.get_right(),
|
||||
rhs_copy.get_left(),
|
||||
))
|
||||
|
||||
self.play(
|
||||
TransformFromCopy(
|
||||
pde_ddx_rect,
|
||||
pde_ddt_rect,
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
GrowArrow(dt_arrow),
|
||||
TransformFromCopy(
|
||||
pde_ddt,
|
||||
dt_label,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
self.play(TransformFromCopy(rhs, rhs_copy))
|
||||
self.play(FadeIn(minus_alpha_in_exp))
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
minus_alpha_in_exp.replace, minus_alpha,
|
||||
path_arc=TAU / 4
|
||||
),
|
||||
FadeIn(dot),
|
||||
)
|
||||
self.play(
|
||||
FadeIn(minus_alpha),
|
||||
FadeOut(minus_alpha_in_exp),
|
||||
)
|
||||
self.wait()
|
||||
rhs_copy.add(minus_alpha, dot)
|
||||
self.play(
|
||||
FadeIn(SurroundingRectangle(rhs_copy))
|
||||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
checkmark = TexMobject("\\checkmark")
|
||||
checkmark.set_color(GREEN)
|
||||
checkmark.move_to(q_mark, DOWN)
|
||||
self.play(
|
||||
FadeInFromDown(checkmark),
|
||||
FadeOutAndShift(q_mark, UP)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class DerivativesOfLinearFunction(WriteHeatEquationTemplate):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{c}": WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
func = TexMobject(
|
||||
"T({x}, {t}) = {c} \\cdot {x}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
dx_T = TexMobject("{c}", **self.tex_mobject_config)
|
||||
ddx_T = TexMobject("0")
|
||||
dt_T = TexMobject("0")
|
||||
|
||||
for mob in func, dx_T, ddx_T, dt_T:
|
||||
mob.scale(1.5)
|
||||
|
||||
func.generate_target()
|
||||
|
||||
arrows = VGroup(*[
|
||||
Vector(1.5 * RIGHT, color=WHITE)
|
||||
for x in range(3)
|
||||
])
|
||||
dx_arrows = arrows[:2]
|
||||
dt_arrow = arrows[2]
|
||||
dt_arrow.rotate(-TAU / 4)
|
||||
dx_group = VGroup(
|
||||
func.target,
|
||||
dx_arrows[0],
|
||||
dx_T,
|
||||
dx_arrows[1],
|
||||
ddx_T,
|
||||
)
|
||||
dx_group.arrange(RIGHT)
|
||||
for arrow, char, vect in zip(arrows, "xxt", [UP, UP, RIGHT]):
|
||||
label = TexMobject(
|
||||
"\\partial \\over \\partial {%s}" % char,
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
label.scale(0.7)
|
||||
label.next_to(arrow.get_center(), vect)
|
||||
arrow.add(label)
|
||||
|
||||
dt_arrow.shift(
|
||||
func.target[-3:].get_bottom() + MED_SMALL_BUFF * DOWN -
|
||||
dt_arrow.get_start(),
|
||||
)
|
||||
dt_T.next_to(dt_arrow.get_end(), DOWN)
|
||||
|
||||
self.play(FadeInFromDown(func))
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(func),
|
||||
LaggedStartMap(Write, dx_arrows),
|
||||
run_time=1,
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(func[-3:], dx_T),
|
||||
path_arc=-TAU / 4,
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(dx_T, ddx_T),
|
||||
path_arc=-TAU / 4,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# dt
|
||||
self.play(Write(dt_arrow))
|
||||
self.play(
|
||||
TransformFromCopy(func[-3:], dt_T)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class FlatAtBoundaryWords(Scene):
|
||||
def construct(self):
|
||||
words = self.get_bc_words()
|
||||
self.play(Write(words))
|
||||
self.wait()
|
||||
|
||||
def get_bc_words(self):
|
||||
return TextMobject(
|
||||
"Flat at boundary\\\\"
|
||||
"for all", "${t}$", "$> 0$",
|
||||
)
|
||||
|
||||
|
||||
class WriteOutBoundaryCondition(FlatAtBoundaryWords, ThreeConstraints, MovingCameraScene):
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
ThreeConstraints.construct(self)
|
||||
self.revert_to_original_skipping_status()
|
||||
|
||||
self.add_ic()
|
||||
self.write_bc_words()
|
||||
self.write_bc_equation()
|
||||
|
||||
def add_ic(self):
|
||||
image = ImageMobject("temp_initial_condition_example")
|
||||
image.set_width(3)
|
||||
border = SurroundingRectangle(image, buff=SMALL_BUFF)
|
||||
border.shift(SMALL_BUFF * UP)
|
||||
border.set_stroke(WHITE, 2)
|
||||
group = Group(image, border)
|
||||
group.next_to(self.items[2], DOWN)
|
||||
self.add(group)
|
||||
|
||||
def write_bc_words(self):
|
||||
bc_paren = self.bc_paren
|
||||
bc_words = self.get_bc_words()
|
||||
bc_words.match_width(self.items[1][1])
|
||||
bc_words.move_to(bc_paren, UP)
|
||||
bc_words.set_color_by_tex("{t}", YELLOW)
|
||||
|
||||
self.play(ShowCreationThenFadeAround(
|
||||
VGroup(self.items[0], self.pde)
|
||||
))
|
||||
self.play(
|
||||
FadeOutAndShift(bc_paren, UP),
|
||||
FadeInFrom(bc_words, DOWN),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.bc_words = bc_words
|
||||
|
||||
def write_bc_equation(self):
|
||||
bc_words = self.bc_words
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial {T} \\over \\partial {x}}(0, {t}) = ",
|
||||
"{\\partial {T} \\over \\partial {x}}(L, {t}) = ",
|
||||
"0",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
equation.next_to(bc_words, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
self.camera_frame.shift, 0.8 * DOWN,
|
||||
)
|
||||
self.play(FadeInFrom(equation, UP))
|
||||
self.wait()
|
||||
|
||||
|
||||
class HeatEquationFrame(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
ddx = equation[-11:]
|
||||
dt = equation[:11]
|
||||
|
||||
full_rect = FullScreenFadeRectangle(
|
||||
fill_color=DARK_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
smaller_rect = ScreenRectangle(
|
||||
height=6,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
smaller_rect.next_to(equation, DOWN)
|
||||
|
||||
self.add(full_rect)
|
||||
self.add(smaller_rect)
|
||||
self.add(equation)
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(
|
||||
ddx,
|
||||
surrounding_rectangle_config={
|
||||
"stroke_color": GREEN,
|
||||
}
|
||||
))
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(dt))
|
||||
self.wait()
|
||||
|
||||
|
||||
class CompareFreqDecays1to2(Scene):
|
||||
CONFIG = {
|
||||
"freqs": [1, 2]
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
background = FullScreenFadeRectangle(
|
||||
fill_color=DARKER_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
|
||||
screens = VGroup(*[
|
||||
ScreenRectangle(
|
||||
height=4,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_width=1,
|
||||
stroke_color=WHITE,
|
||||
)
|
||||
for x in range(2)
|
||||
])
|
||||
screens.arrange(RIGHT)
|
||||
screens.set_width(FRAME_WIDTH - 1)
|
||||
|
||||
formulas = VGroup(*[
|
||||
self.get_formula(freq)
|
||||
for freq in self.freqs
|
||||
])
|
||||
for formula, screen in zip(formulas, screens):
|
||||
formula.next_to(screen, UP)
|
||||
|
||||
self.add(background)
|
||||
self.add(screens)
|
||||
self.add(formulas)
|
||||
self.wait()
|
||||
|
||||
def get_formula(self, freq):
|
||||
f_str = str(freq)
|
||||
return TexMobject(
|
||||
"\\cos\\left(%s \\cdot {x}\\right)" % f_str,
|
||||
"e^{-\\alpha \\cdot %s^2 \\cdot {t}}" % f_str,
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
f_str: MAROON_B,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class CompareFreqDecays1to4(CompareFreqDecays1to2):
|
||||
CONFIG = {
|
||||
"freqs": [1, 4],
|
||||
}
|
||||
|
||||
|
||||
class CompareFreqDecays2to4(CompareFreqDecays1to2):
|
||||
CONFIG = {
|
||||
"freqs": [2, 4],
|
||||
}
|
||||
|
||||
|
||||
class WorryAboutGenerality(TeacherStudentsScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
eq = self.get_d1_equation()
|
||||
diffyq = self.get_diffyq_set()
|
||||
is_in = TexMobject("\\in")
|
||||
is_in.scale(2)
|
||||
|
||||
group = VGroup(eq, is_in, diffyq)
|
||||
group.arrange(RIGHT, buff=MED_LARGE_BUFF)
|
||||
group.to_edge(UP)
|
||||
|
||||
arrow = Vector(DOWN)
|
||||
arrow.set_stroke(WHITE, 5)
|
||||
arrow.next_to(eq, DOWN)
|
||||
themes = TextMobject("Frequent themes")
|
||||
themes.scale(1.5)
|
||||
themes.next_to(arrow, DOWN)
|
||||
|
||||
self.play(
|
||||
self.get_student_changes(
|
||||
"sad", "tired", "pleading"
|
||||
),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
FadeInFromDown(eq)
|
||||
)
|
||||
self.play(Write(group[1:]))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
self.get_student_changes(*3 * ["pondering"]),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(themes, UP),
|
||||
self.get_student_changes(*3 * ["thinking"]),
|
||||
self.teacher.change, "happy"
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
# def get_d1_equation(self):
|
||||
# result = super().get_d1_equation()
|
||||
# lp, rp = parens = TexMobject("(", ")")
|
||||
# parens.match_height(result)
|
||||
# lp.next_to(result, LEFT, SMALL_BUFF)
|
||||
# rp.next_to(result, RIGHT, SMALL_BUFF)
|
||||
# result.add_to_back(lp)
|
||||
# result.add(rp)
|
||||
# return result
|
||||
|
||||
def get_diffyq_set(self):
|
||||
words = TextMobject(
|
||||
"Differential\\\\equations"
|
||||
)
|
||||
words.scale(1.5)
|
||||
words.set_color(BLUE)
|
||||
lb = Brace(words, LEFT)
|
||||
rb = Brace(words, RIGHT)
|
||||
return VGroup(lb, words, rb)
|
||||
@@ -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)
|
||||
@@ -1,345 +0,0 @@
|
||||
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
|
||||
|
||||
|
||||
class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
CONFIG = {
|
||||
"temp_text": "Temp",
|
||||
"alpha": 0.1,
|
||||
"axes_config": {
|
||||
"z_max": 2,
|
||||
"z_min": -2,
|
||||
"z_axis_config": {
|
||||
"tick_frequency": 0.5,
|
||||
"unit_size": 1.5,
|
||||
},
|
||||
},
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16)
|
||||
# "resolution": (4, 4)
|
||||
},
|
||||
"freqs": [2, 5],
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
TemperatureGraphScene.setup(self)
|
||||
WriteHeatEquationTemplate.setup(self)
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_three_graphs()
|
||||
self.show_words()
|
||||
self.add_function_labels()
|
||||
self.change_scalars()
|
||||
|
||||
def init_camera(self):
|
||||
self.camera.set_distance(1000)
|
||||
|
||||
def add_three_graphs(self):
|
||||
axes_group = self.get_axes_group()
|
||||
axes0, axes1, axes2 = axes_group
|
||||
freqs = self.freqs
|
||||
scalar_trackers = Group(
|
||||
ValueTracker(1),
|
||||
ValueTracker(1),
|
||||
)
|
||||
graphs = VGroup(
|
||||
self.get_graph(axes0, [freqs[0]], [scalar_trackers[0]]),
|
||||
self.get_graph(axes1, [freqs[1]], [scalar_trackers[1]]),
|
||||
self.get_graph(axes2, freqs, scalar_trackers),
|
||||
)
|
||||
|
||||
plus = TexMobject("+").scale(2)
|
||||
equals = TexMobject("=").scale(2)
|
||||
plus.move_to(midpoint(
|
||||
axes0.get_right(),
|
||||
axes1.get_left(),
|
||||
))
|
||||
equals.move_to(midpoint(
|
||||
axes1.get_right(),
|
||||
axes2.get_left(),
|
||||
))
|
||||
|
||||
self.add(axes_group)
|
||||
self.add(graphs)
|
||||
self.add(plus)
|
||||
self.add(equals)
|
||||
|
||||
self.axes_group = axes_group
|
||||
self.graphs = graphs
|
||||
self.scalar_trackers = scalar_trackers
|
||||
self.plus = plus
|
||||
self.equals = equals
|
||||
|
||||
def show_words(self):
|
||||
equation = self.get_d1_equation()
|
||||
name = TextMobject("Heat equation")
|
||||
name.next_to(equation, DOWN)
|
||||
name.set_color_by_gradient(RED, YELLOW)
|
||||
group = VGroup(equation, name)
|
||||
group.to_edge(UP)
|
||||
|
||||
shift_val = 0.5 * RIGHT
|
||||
|
||||
arrow = Vector(1.5 * RIGHT)
|
||||
arrow.move_to(group)
|
||||
arrow.shift(shift_val)
|
||||
linear_word = TextMobject("``Linear''")
|
||||
linear_word.scale(2)
|
||||
linear_word.next_to(arrow, RIGHT)
|
||||
|
||||
self.add(group)
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
group.next_to, arrow, LEFT
|
||||
)
|
||||
self.play(FadeInFrom(linear_word, LEFT))
|
||||
self.wait()
|
||||
|
||||
def add_function_labels(self):
|
||||
axes_group = self.axes_group
|
||||
graphs = self.graphs
|
||||
|
||||
solution_labels = VGroup()
|
||||
for axes in axes_group:
|
||||
label = TextMobject("Solution", "$\\checkmark$")
|
||||
label.set_color_by_tex("checkmark", GREEN)
|
||||
label.next_to(axes, DOWN)
|
||||
solution_labels.add(label)
|
||||
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
"T_1": BLUE,
|
||||
"T_2": GREEN,
|
||||
}
|
||||
}
|
||||
T1 = TexMobject("a", "T_1", **kw)
|
||||
T2 = TexMobject("b", "T_2", **kw)
|
||||
T_sum = TexMobject("T_1", "+", "T_2", **kw)
|
||||
T_sum_with_scalars = TexMobject(
|
||||
"a", "T_1", "+", "b", "T_2", **kw
|
||||
)
|
||||
|
||||
T1.next_to(graphs[0], UP)
|
||||
T2.next_to(graphs[1], UP)
|
||||
T_sum.next_to(graphs[2], UP)
|
||||
T_sum.shift(SMALL_BUFF * DOWN)
|
||||
T_sum_with_scalars.move_to(T_sum)
|
||||
|
||||
a_brace = Brace(T1[0], UP, buff=SMALL_BUFF)
|
||||
b_brace = Brace(T2[0], UP, buff=SMALL_BUFF)
|
||||
s1_decimal = DecimalNumber()
|
||||
s1_decimal.match_color(T1[1])
|
||||
s1_decimal.next_to(a_brace, UP, SMALL_BUFF)
|
||||
s1_decimal.add_updater(lambda m: m.set_value(
|
||||
self.scalar_trackers[0].get_value()
|
||||
))
|
||||
s2_decimal = DecimalNumber()
|
||||
s2_decimal.match_color(T2[1])
|
||||
s2_decimal.next_to(b_brace, UP, SMALL_BUFF)
|
||||
s2_decimal.add_updater(lambda m: m.set_value(
|
||||
self.scalar_trackers[1].get_value()
|
||||
))
|
||||
|
||||
self.play(
|
||||
FadeInFrom(T1[1], DOWN),
|
||||
FadeInFrom(solution_labels[0], UP),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(T2[1], DOWN),
|
||||
FadeInFrom(solution_labels[1], UP),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(T1[1], T_sum[0]),
|
||||
TransformFromCopy(T2[1], T_sum[2]),
|
||||
TransformFromCopy(self.plus, T_sum[1]),
|
||||
*[
|
||||
Transform(
|
||||
graph.copy().set_fill(opacity=0),
|
||||
graphs[2].copy().set_fill(opacity=0),
|
||||
remover=True
|
||||
)
|
||||
for graph in graphs[:2]
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(solution_labels[2], UP))
|
||||
self.wait()
|
||||
|
||||
# Show constants
|
||||
self.play(
|
||||
FadeIn(T1[0]),
|
||||
FadeIn(T2[0]),
|
||||
FadeIn(a_brace),
|
||||
FadeIn(b_brace),
|
||||
FadeIn(s1_decimal),
|
||||
FadeIn(s2_decimal),
|
||||
FadeOut(T_sum),
|
||||
FadeIn(T_sum_with_scalars),
|
||||
)
|
||||
|
||||
def change_scalars(self):
|
||||
s1, s2 = self.scalar_trackers
|
||||
|
||||
kw = {
|
||||
"run_time": 2,
|
||||
}
|
||||
for graph in self.graphs:
|
||||
graph.resume_updating()
|
||||
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.wait()
|
||||
|
||||
#
|
||||
def get_axes_group(self):
|
||||
axes_group = VGroup(*[
|
||||
self.get_axes()
|
||||
for x in range(3)
|
||||
])
|
||||
axes_group.arrange(RIGHT, buff=2)
|
||||
axes_group.set_width(FRAME_WIDTH - 1)
|
||||
axes_group.to_edge(DOWN, buff=1)
|
||||
return axes_group
|
||||
|
||||
def get_axes(self):
|
||||
axes = self.get_three_d_axes()
|
||||
# axes.input_plane.set_fill(opacity=0)
|
||||
# axes.input_plane.set_stroke(width=0.5)
|
||||
# axes.add(axes.input_plane)
|
||||
self.orient_three_d_mobject(axes)
|
||||
axes.rotate(-5 * DEGREES, UP)
|
||||
axes.set_width(4)
|
||||
axes.x_axis.label.next_to(
|
||||
axes.x_axis.get_end(), DOWN,
|
||||
buff=2 * SMALL_BUFF
|
||||
)
|
||||
return axes
|
||||
|
||||
def get_graph(self, axes, freqs, scalar_trackers):
|
||||
L = axes.x_max
|
||||
a = self.alpha
|
||||
|
||||
def func(x, t):
|
||||
scalars = [st.get_value() for st in scalar_trackers]
|
||||
return np.sum([
|
||||
s * np.cos(k * x) * np.exp(-a * (k**2) * t)
|
||||
for freq, s in zip(freqs, scalars)
|
||||
for k in [freq * PI / L]
|
||||
])
|
||||
|
||||
def get_surface_graph_group():
|
||||
return VGroup(
|
||||
self.get_surface(axes, func),
|
||||
self.get_time_slice_graph(axes, func, t=0),
|
||||
)
|
||||
|
||||
result = always_redraw(get_surface_graph_group)
|
||||
result.suspend_updating()
|
||||
return result
|
||||
@@ -1,63 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
# Physical constants
|
||||
g = 9.8
|
||||
L = 2
|
||||
mu = 0.1
|
||||
|
||||
THETA_0 = np.pi / 3 # 60 degrees
|
||||
THETA_DOT_0 = 0 # No initial angular velocity
|
||||
|
||||
# Definition of ODE
|
||||
def get_theta_double_dot(theta, theta_dot):
|
||||
return -mu * theta_dot - (g / L) * np.sin(theta)
|
||||
|
||||
|
||||
# Solution to the differential equation
|
||||
def theta(t):
|
||||
# Initialize changing values
|
||||
theta = THETA_0
|
||||
theta_dot = THETA_DOT_0
|
||||
delta_t = 0.01 # Some time step
|
||||
for time in np.arange(0, t, delta_t):
|
||||
# Take many little time steps of size delta_t
|
||||
# until the total time is the function's input
|
||||
theta_double_dot = get_theta_double_dot(
|
||||
theta, theta_dot
|
||||
)
|
||||
theta += theta_dot * delta_t
|
||||
theta_dot += theta_double_dot * delta_t
|
||||
return theta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,283 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WorkOutNumerically(Scene):
|
||||
CONFIG = {
|
||||
"M1_COLOR": TEAL,
|
||||
"M2_COLOR": PINK,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_question()
|
||||
self.add_example()
|
||||
self.compute_rhs()
|
||||
self.compute_lhs()
|
||||
|
||||
def add_question(self):
|
||||
equation = self.original_equation = TexMobject(
|
||||
"\\det(", "M_1", "M_2", ")", "=",
|
||||
"\\det(", "M_1", ")",
|
||||
"\\det(", "M_2", ")",
|
||||
)
|
||||
equation.set_color_by_tex_to_color_map({
|
||||
"M_1": self.M1_COLOR,
|
||||
"M_2": self.M2_COLOR,
|
||||
})
|
||||
challenge = TextMobject("Explain in one sentence")
|
||||
challenge.set_color(YELLOW)
|
||||
group = VGroup(challenge, equation)
|
||||
group.arrange(DOWN)
|
||||
group.to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
self.play(Write(challenge))
|
||||
self.wait()
|
||||
|
||||
def add_example(self):
|
||||
M1 = self.M1 = Matrix([[2, -1], [1, 1]])
|
||||
M1.set_color(self.M1_COLOR)
|
||||
self.M1_copy = M1.copy()
|
||||
M2 = self.M2 = Matrix([[-1, 4], [1, 1]])
|
||||
M2.set_color(self.M2_COLOR)
|
||||
self.M2_copy = M2.copy()
|
||||
eq_parts = TexMobject(
|
||||
"\\det", "\\big(", "\\big)", "=",
|
||||
"\\det", "\\big(", "\\big)",
|
||||
"\\det", "\\big(", "\\big)",
|
||||
)
|
||||
for part in eq_parts.get_parts_by_tex("\\big"):
|
||||
part.scale(2)
|
||||
part.stretch(1.5, 1)
|
||||
i1, i2, i3 = [
|
||||
eq_parts.index_of_part(part) + 1
|
||||
for part in eq_parts.get_parts_by_tex("\\big(")
|
||||
]
|
||||
equation = self.equation_with_numbers = VGroup(*it.chain(
|
||||
eq_parts[:i1], [M1, M2],
|
||||
eq_parts[i1:i2], [self.M1_copy],
|
||||
eq_parts[i2:i3], [self.M2_copy],
|
||||
eq_parts[i3:],
|
||||
))
|
||||
equation.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
eq_parts.get_part_by_tex("=").shift(0.2 * SMALL_BUFF * DOWN)
|
||||
equation.set_width(FRAME_WIDTH - 2 * LARGE_BUFF)
|
||||
equation.next_to(self.original_equation, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(LaggedStartMap(FadeIn, equation))
|
||||
|
||||
def compute_rhs(self):
|
||||
M1, M2 = self.M1_copy, self.M2_copy
|
||||
|
||||
line1 = VGroup(
|
||||
TexMobject(
|
||||
"\\big(", "2", "\\cdot", "2", "-",
|
||||
"(-1)", "\\cdot", "1", "\\big)"
|
||||
),
|
||||
TexMobject(
|
||||
"\\big(", "-1", "\\cdot", "1", "-",
|
||||
"4", "\\cdot", "1", "\\big)"
|
||||
),
|
||||
)
|
||||
line1.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
line1[0].set_color(self.M1_COLOR)
|
||||
line1[1].set_color(self.M2_COLOR)
|
||||
indices = [1, 3, 5, 7]
|
||||
|
||||
line2 = TexMobject("(3)", "(-5)")
|
||||
line2.match_style(line1)
|
||||
line3 = TexMobject("-15")
|
||||
arrows = [TexMobject("\\downarrow") for x in range(2)]
|
||||
lines = VGroup(line1, arrows[0], line2, arrows[1], line3)
|
||||
lines.arrange(DOWN, buff=MED_SMALL_BUFF)
|
||||
lines.next_to(self.equation_with_numbers, DOWN, buff=MED_LARGE_BUFF)
|
||||
lines.to_edge(RIGHT)
|
||||
|
||||
for matrix, det in zip([M1, M2], line1):
|
||||
numbers = VGroup(*[det[i] for i in indices])
|
||||
numbers_iter = iter(numbers)
|
||||
non_numbers = VGroup(*[m for m in det if m not in numbers])
|
||||
matrix_numbers = VGroup(*[
|
||||
matrix.mob_matrix[i][j].copy()
|
||||
for i, j in ((0, 0), (1, 1), (0, 1), (1, 0))
|
||||
])
|
||||
self.play(
|
||||
LaggedStartMap(FadeIn, non_numbers, run_time=1),
|
||||
LaggedStartMap(
|
||||
ReplacementTransform,
|
||||
matrix_numbers,
|
||||
lambda m: (m, next(numbers_iter)),
|
||||
path_arc=TAU / 6
|
||||
),
|
||||
)
|
||||
self.play(LaggedStartMap(FadeIn, lines[1:], run_time=3))
|
||||
|
||||
def compute_lhs(self):
|
||||
matrix = Matrix([[-3, 7], [0, 5]])
|
||||
matrix.set_color(BLUE)
|
||||
matrix.scale(0.8)
|
||||
empty_det_tex = TexMobject("\\det", "\\big(", "\\big)")
|
||||
empty_det_tex[1:].scale(1.5)
|
||||
empty_det_tex[1:].match_height(matrix, stretch=True)
|
||||
det_tex = VGroup(empty_det_tex[:2], matrix, *empty_det_tex[2:])
|
||||
det_tex.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
|
||||
group = VGroup(
|
||||
det_tex,
|
||||
TexMobject("\\downarrow"),
|
||||
TexMobject("(-3)(5) - (7)(0)").scale(0.8),
|
||||
TexMobject("\\downarrow"),
|
||||
TexMobject("-15"),
|
||||
)
|
||||
group.arrange(DOWN, buff=2 * SMALL_BUFF)
|
||||
# group.set_height(0.4*FRAME_HEIGHT)
|
||||
group.next_to(self.equation_with_numbers, DOWN)
|
||||
group.shift(FRAME_WIDTH * LEFT / 4)
|
||||
|
||||
self.play(FadeIn(empty_det_tex))
|
||||
self.play(*[
|
||||
ReplacementTransform(M.copy(), matrix)
|
||||
for M in (self.M1, self.M2)
|
||||
])
|
||||
self.play(LaggedStartMap(FadeIn, group[1:]))
|
||||
self.wait()
|
||||
|
||||
|
||||
class LetsGoInOneSentence(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says(
|
||||
"Here we go, \\\\", "one sentence!"
|
||||
)
|
||||
self.change_all_student_modes("hooray")
|
||||
self.teacher_says(
|
||||
"Or three...", "",
|
||||
target_mode="guilty"
|
||||
)
|
||||
self.change_all_student_modes("sassy")
|
||||
self.wait(4)
|
||||
|
||||
|
||||
class SuccessiveLinearTransformations(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"matrix_2": [[3, -1], [0, 1]],
|
||||
"matrix_1": [[2, 3], [-1. / 3, 2]],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.create_product_and_inverse()
|
||||
self.scale_area_successively()
|
||||
self.apply_transformations_successively()
|
||||
self.scale_area_successively(
|
||||
"\\det(M_2)", "\\det(M_1)", "\\det(M_1 M_2)",
|
||||
reset=False
|
||||
)
|
||||
# self.show_det_as_scaling_factor()
|
||||
|
||||
def create_product_and_inverse(self):
|
||||
self.matrix_product = np.dot(self.matrix_1, self.matrix_2)
|
||||
self.matrix_product_inverse = np.linalg.inv(self.matrix_product)
|
||||
|
||||
def scale_area_successively(self, tex2="3", tex1="5", tex_prod="15", reset=True):
|
||||
self.add_unit_square()
|
||||
t1 = "$%s \\, \\cdot $" % tex1
|
||||
t2 = "$%s \\, \\cdot $" % tex2
|
||||
t3 = "Area"
|
||||
areas = VGroup(
|
||||
TextMobject("", "", t3),
|
||||
TextMobject("", t2, t3),
|
||||
TextMobject(t1, t2, t3),
|
||||
)
|
||||
areas.scale(0.8)
|
||||
areas.move_to(self.square)
|
||||
area = areas[0]
|
||||
self.add_moving_mobject(area, areas[1])
|
||||
|
||||
self.play(
|
||||
FadeIn(self.square),
|
||||
Write(area),
|
||||
Animation(self.basis_vectors)
|
||||
)
|
||||
self.apply_matrix(self.matrix_2)
|
||||
self.wait()
|
||||
self.add_moving_mobject(area, areas[2])
|
||||
self.apply_matrix(self.matrix_1)
|
||||
self.wait()
|
||||
|
||||
product = VGroup(area[:2])
|
||||
brace = Brace(product, DOWN, buff=SMALL_BUFF)
|
||||
brace_tex = brace.get_tex(tex_prod, buff=SMALL_BUFF)
|
||||
brace_tex.scale(0.8, about_edge=UP)
|
||||
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(brace_tex)
|
||||
)
|
||||
self.wait()
|
||||
if reset:
|
||||
self.play(
|
||||
FadeOut(VGroup(self.square, area, brace, brace_tex)),
|
||||
Animation(self.plane),
|
||||
Animation(self.basis_vectors)
|
||||
)
|
||||
self.transformable_mobjects.remove(self.square)
|
||||
self.moving_mobjects = []
|
||||
self.reset_plane()
|
||||
self.wait()
|
||||
|
||||
def apply_transformations_successively(self):
|
||||
M1, M2, all_space = expression = TexMobject(
|
||||
"M_1", "M_2", "\\text{(All 2d space)}"
|
||||
)
|
||||
expression.set_color_by_tex_to_color_map({
|
||||
"M_1": TEAL,
|
||||
"M_2": PINK,
|
||||
})
|
||||
expression.shift(FRAME_WIDTH * LEFT / 4)
|
||||
expression.to_edge(UP)
|
||||
for part in expression:
|
||||
part.add_background_rectangle()
|
||||
part.background_rectangle.stretch(1.05, 0)
|
||||
M1.save_state()
|
||||
M1.move_to(ORIGIN)
|
||||
M1.fade(1)
|
||||
|
||||
# Apply one after the other
|
||||
self.play(
|
||||
FocusOn(M2, run_time=1),
|
||||
FadeIn(VGroup(M2, all_space))
|
||||
)
|
||||
self.add_foreground_mobjects(M2, all_space)
|
||||
self.apply_matrix(self.matrix_2)
|
||||
self.wait()
|
||||
self.play(M1.restore)
|
||||
self.add_foreground_mobjects(M1)
|
||||
self.apply_matrix(self.matrix_1)
|
||||
self.wait()
|
||||
|
||||
# Show full composition
|
||||
rp, lp = parens = TexMobject("()")
|
||||
matrices = VGroup(M1, M2)
|
||||
matrices.generate_target()
|
||||
parens.match_height(matrices)
|
||||
lp.move_to(matrices, RIGHT)
|
||||
matrices.target.next_to(lp, LEFT, SMALL_BUFF)
|
||||
rp.next_to(matrices.target, LEFT, SMALL_BUFF)
|
||||
|
||||
self.reset_plane()
|
||||
self.play(
|
||||
MoveToTarget(matrices),
|
||||
*list(map(GrowFromCenter, parens))
|
||||
)
|
||||
self.apply_matrix(self.matrix_product)
|
||||
self.wait()
|
||||
self.reset_plane()
|
||||
|
||||
def show_det_as_scaling_factor(self):
|
||||
pass
|
||||
|
||||
###
|
||||
|
||||
def reset_plane(self):
|
||||
plane_and_bases = VGroup(self.plane, self.basis_vectors)
|
||||
self.play(FadeOut(plane_and_bases))
|
||||
self.apply_matrix(self.matrix_product_inverse, run_time=0)
|
||||
self.play(FadeIn(plane_and_bases))
|
||||
@@ -1,222 +0,0 @@
|
||||
from fractions import Fraction
|
||||
|
||||
from manimlib.imports import *
|
||||
from functools import reduce
|
||||
|
||||
|
||||
class FractionMobject(VGroup):
|
||||
CONFIG = {
|
||||
"max_height": 1,
|
||||
}
|
||||
|
||||
def __init__(self, fraction, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
numerator = self.numerator = Integer(fraction.numerator)
|
||||
self.add(numerator)
|
||||
if fraction.denominator != 1:
|
||||
denominator = Integer(fraction.denominator)
|
||||
line = TexMobject("/")
|
||||
numerator.next_to(line, LEFT, SMALL_BUFF)
|
||||
denominator.next_to(line, RIGHT, SMALL_BUFF)
|
||||
self.add(numerator, line, denominator)
|
||||
self.set_height(min(self.max_height, self.get_height()))
|
||||
self.value = fraction
|
||||
|
||||
def add_plus_if_needed(self):
|
||||
if self.value > 0:
|
||||
plus = TexMobject("+")
|
||||
plus.next_to(self, LEFT, SMALL_BUFF)
|
||||
plus.match_color(self)
|
||||
self.add_to_back(plus)
|
||||
|
||||
|
||||
class ShowRowReduction(Scene):
|
||||
CONFIG = {
|
||||
"matrices": [
|
||||
[
|
||||
[2, -1, -1],
|
||||
[0, 3, -4],
|
||||
[-3, 2, 1],
|
||||
],
|
||||
[
|
||||
[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 1],
|
||||
],
|
||||
# [[1], [2], [3]],
|
||||
],
|
||||
"h_spacing": 2,
|
||||
"extra_h_spacing": 0.5,
|
||||
"v_spacing": 1,
|
||||
"include_separation_lines": True,
|
||||
"changing_row_color": YELLOW,
|
||||
"reference_row_color": BLUE,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.initialize_terms()
|
||||
|
||||
self.apply_row_rescaling(0, Fraction(1, 2))
|
||||
self.add_row_multiple_to_row(2, 0, 3)
|
||||
self.apply_row_rescaling(1, Fraction(1, 3))
|
||||
self.add_row_multiple_to_row(2, 1, Fraction(-1, 2))
|
||||
self.apply_row_rescaling(2, Fraction(6))
|
||||
self.add_row_multiple_to_row(0, 1, Fraction(1, 2))
|
||||
self.add_row_multiple_to_row(0, 2, Fraction(7, 6))
|
||||
self.add_row_multiple_to_row(1, 2, Fraction(4, 3))
|
||||
self.wait()
|
||||
|
||||
def initialize_terms(self):
|
||||
full_matrix = reduce(
|
||||
lambda m, v: np.append(m, v, axis=1),
|
||||
self.matrices
|
||||
)
|
||||
mobject_matrix = np.vectorize(FractionMobject)(full_matrix)
|
||||
rows = self.rows = VGroup(*it.starmap(VGroup, mobject_matrix))
|
||||
for i, row in enumerate(rows):
|
||||
for j, term in enumerate(row):
|
||||
term.move_to(
|
||||
i * self.v_spacing * DOWN +
|
||||
j * self.h_spacing * RIGHT
|
||||
)
|
||||
|
||||
# Visually seaprate distinct parts
|
||||
separation_lines = self.separation_lines = VGroup()
|
||||
lengths = [len(m[0]) for m in self.matrices]
|
||||
for partial_sum in np.cumsum(lengths)[:-1]:
|
||||
VGroup(*mobject_matrix[:, partial_sum:].flatten()).shift(
|
||||
self.extra_h_spacing * RIGHT
|
||||
)
|
||||
c1 = VGroup(*mobject_matrix[:, partial_sum - 1])
|
||||
c2 = VGroup(*mobject_matrix[:, partial_sum])
|
||||
line = DashedLine(c1.get_top(), c1.get_bottom())
|
||||
line.move_to(VGroup(c1, c2))
|
||||
separation_lines.add(line)
|
||||
|
||||
if self.include_separation_lines:
|
||||
group = VGroup(rows, separation_lines)
|
||||
else:
|
||||
group = rows
|
||||
group.center().to_edge(DOWN, buff=2)
|
||||
self.add(group)
|
||||
|
||||
def add_variables(self):
|
||||
# If it is meant to represent a system of equations
|
||||
pass
|
||||
|
||||
def apply_row_rescaling(self, row_index, scale_factor):
|
||||
row = self.rows[row_index]
|
||||
new_row = VGroup()
|
||||
for element in row:
|
||||
target = FractionMobject(element.value * scale_factor)
|
||||
target.move_to(element)
|
||||
new_row.add(target)
|
||||
new_row.set_color(self.changing_row_color)
|
||||
|
||||
label = VGroup(
|
||||
TexMobject("r_%d" % (row_index + 1)),
|
||||
TexMobject("\\rightarrow"),
|
||||
TexMobject("("),
|
||||
FractionMobject(scale_factor),
|
||||
TexMobject(")"),
|
||||
TexMobject("r_%d" % (row_index + 1)),
|
||||
)
|
||||
label.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
label.to_edge(UP)
|
||||
VGroup(label[0], label[-1]).set_color(self.changing_row_color)
|
||||
|
||||
scalar_mob = FractionMobject(scale_factor)
|
||||
scalar_mob.add_to_back(
|
||||
TexMobject("\\times").next_to(scalar_mob, LEFT, SMALL_BUFF)
|
||||
)
|
||||
scalar_mob.scale(0.5)
|
||||
scalar_mob.next_to(row[0], DR, SMALL_BUFF)
|
||||
|
||||
# Do do, fancier illustrations here
|
||||
self.play(
|
||||
FadeIn(label),
|
||||
row.set_color, self.changing_row_color,
|
||||
)
|
||||
self.play(FadeIn(scalar_mob))
|
||||
for elem, new_elem in zip(row, new_row):
|
||||
self.play(scalar_mob.next_to, elem, DR, SMALL_BUFF)
|
||||
self.play(ReplacementTransform(elem, new_elem, path_arc=30 * DEGREES))
|
||||
self.play(FadeOut(scalar_mob))
|
||||
self.play(new_row.set_color, WHITE)
|
||||
self.play(FadeOut(label))
|
||||
self.rows.submobjects[row_index] = new_row
|
||||
|
||||
def add_row_multiple_to_row(self, row1_index, row2_index, scale_factor):
|
||||
row1 = self.rows[row1_index]
|
||||
row2 = self.rows[row2_index]
|
||||
new_row1 = VGroup()
|
||||
scaled_row2 = VGroup()
|
||||
for elem1, elem2 in zip(row1, row2):
|
||||
target = FractionMobject(elem1.value + scale_factor * elem2.value)
|
||||
target.move_to(elem1)
|
||||
new_row1.add(target)
|
||||
|
||||
scaled_term = FractionMobject(scale_factor * elem2.value)
|
||||
scaled_term.move_to(elem2)
|
||||
scaled_row2.add(scaled_term)
|
||||
new_row1.set_color(self.changing_row_color)
|
||||
scaled_row2.set_color(self.reference_row_color)
|
||||
|
||||
for elem1, elem2 in zip(row1, scaled_row2):
|
||||
elem2.add_plus_if_needed()
|
||||
elem2.scale(0.5)
|
||||
elem2.next_to(elem1, UL, buff=SMALL_BUFF)
|
||||
|
||||
label = VGroup(
|
||||
TexMobject("r_%d" % (row1_index + 1)),
|
||||
TexMobject("\\rightarrow"),
|
||||
TexMobject("r_%d" % (row1_index + 1)),
|
||||
TexMobject("+"),
|
||||
TexMobject("("),
|
||||
FractionMobject(scale_factor),
|
||||
TexMobject(")"),
|
||||
TexMobject("r_%d" % (row2_index + 1)),
|
||||
)
|
||||
label.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
label.to_edge(UP)
|
||||
VGroup(label[0], label[2]).set_color(self.changing_row_color)
|
||||
label[-1].set_color(self.reference_row_color)
|
||||
|
||||
self.play(
|
||||
FadeIn(label),
|
||||
row1.set_color, self.changing_row_color,
|
||||
row2.set_color, self.reference_row_color,
|
||||
)
|
||||
row1.target.next_to(self.rows, UP, buff=2)
|
||||
row1.target.align_to(row1, LEFT)
|
||||
|
||||
row2.target.next_to(row1.target, DOWN, buff=MED_LARGE_BUFF)
|
||||
lp, rp = row2_parens = TexMobject("()")
|
||||
row2_parens.set_height(row2.get_height() + 2 * SMALL_BUFF)
|
||||
lp.next_to(row2, LEFT, SMALL_BUFF)
|
||||
rp.next_to(row2, RIGHT, SMALL_BUFF)
|
||||
scalar = FractionMobject(scale_factor)
|
||||
scalar.next_to(lp, LEFT, SMALL_BUFF)
|
||||
scalar.add_plus_if_needed()
|
||||
|
||||
self.play(
|
||||
FadeIn(row2_parens),
|
||||
Write(scalar),
|
||||
)
|
||||
self.play(ReplacementTransform(row2.copy(), scaled_row2))
|
||||
self.wait()
|
||||
for elem, new_elem, s_elem in zip(row1, new_row1, scaled_row2):
|
||||
self.play(
|
||||
FadeOut(elem),
|
||||
FadeIn(new_elem),
|
||||
Transform(s_elem, new_elem.copy().fade(1), remover=True)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(label),
|
||||
FadeOut(row2_parens),
|
||||
FadeOut(scalar),
|
||||
new_row1.set_color, WHITE,
|
||||
row2.set_color, WHITE,
|
||||
)
|
||||
self.rows.submobjects[row1_index] = new_row1
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
class Birthday(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
sidelength = 6.0
|
||||
corner = np.array([-sidelength/2,-sidelength/2,0])
|
||||
nb_days_left = 365.0
|
||||
toggle = False
|
||||
|
||||
def probability():
|
||||
width = rect.get_width()
|
||||
height = rect.get_height()
|
||||
return width * height / sidelength**2
|
||||
|
||||
rect = Square().scale(sidelength/2)
|
||||
|
||||
while probability() > 0.5:
|
||||
|
||||
self.add(rect.copy())
|
||||
nb_days_left -= 1
|
||||
|
||||
if toggle:
|
||||
dim = 0
|
||||
else:
|
||||
dim = 1
|
||||
|
||||
rect.stretch_about_point(nb_days_left / 365, dim, corner)
|
||||
|
||||
toggle = not toggle
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_series()
|
||||
self.show_examples()
|
||||
|
||||
def show_series(self):
|
||||
series = VideoSeries(num_videos = 11)
|
||||
series.to_edge(UP)
|
||||
this_video = series[0]
|
||||
this_video.set_color(YELLOW)
|
||||
this_video.save_state()
|
||||
this_video.set_fill(opacity = 0)
|
||||
this_video.center()
|
||||
this_video.set_height(FRAME_HEIGHT)
|
||||
self.this_video = this_video
|
||||
|
||||
|
||||
words = TextMobject(
|
||||
"Welcome to \\\\",
|
||||
"Essence of Probability"
|
||||
)
|
||||
words.set_color_by_tex("Essence of Probability", YELLOW)
|
||||
|
||||
self.teacher.change_mode("happy")
|
||||
self.play(
|
||||
FadeIn(
|
||||
series,
|
||||
lag_ratio = 0.5,
|
||||
run_time = 2
|
||||
),
|
||||
Blink(self.get_teacher())
|
||||
)
|
||||
self.teacher_says(words, target_mode = "hooray")
|
||||
self.change_student_modes(
|
||||
*["hooray"]*3,
|
||||
look_at_arg = series[1].get_left(),
|
||||
added_anims = [
|
||||
ApplyMethod(this_video.restore, run_time = 3),
|
||||
]
|
||||
)
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
video.shift, 0.5*video.get_height()*DOWN,
|
||||
run_time = 3,
|
||||
rate_func = squish_rate_func(
|
||||
there_and_back, alpha, alpha+0.3
|
||||
)
|
||||
)
|
||||
for video, alpha in zip(series, np.linspace(0, 0.7, len(series)))
|
||||
]+[
|
||||
Animation(self.teacher.bubble),
|
||||
Animation(self.teacher.bubble.content),
|
||||
])
|
||||
|
||||
self.play(
|
||||
FadeOut(self.teacher.bubble),
|
||||
FadeOut(self.teacher.bubble.content),
|
||||
self.get_teacher().change_mode, "raise_right_hand",
|
||||
*[
|
||||
ApplyMethod(pi.change_mode, "pondering")
|
||||
for pi in self.get_students()
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.series = series
|
||||
|
||||
|
||||
def show_examples(self):
|
||||
|
||||
self.wait(10)
|
||||
# put examples here in video editor
|
||||
@@ -1,82 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_series()
|
||||
self.show_examples()
|
||||
|
||||
def show_series(self):
|
||||
series = VideoSeries(num_videos = 11)
|
||||
series.to_edge(UP)
|
||||
this_video = series[0]
|
||||
this_video.set_color(YELLOW)
|
||||
this_video.save_state()
|
||||
this_video.set_fill(opacity = 0)
|
||||
this_video.center()
|
||||
this_video.set_height(FRAME_HEIGHT)
|
||||
self.this_video = this_video
|
||||
|
||||
|
||||
words = TextMobject(
|
||||
"Welcome to \\\\",
|
||||
"Essence of Probability"
|
||||
)
|
||||
words.set_color_by_tex("Essence of Probability", YELLOW)
|
||||
|
||||
self.teacher.change_mode("happy")
|
||||
self.play(
|
||||
FadeIn(
|
||||
series,
|
||||
lag_ratio = 0.5,
|
||||
run_time = 2
|
||||
),
|
||||
Blink(self.get_teacher())
|
||||
)
|
||||
self.teacher_says(words, target_mode = "hooray")
|
||||
self.change_student_modes(
|
||||
*["hooray"]*3,
|
||||
look_at_arg = series[1].get_left(),
|
||||
added_anims = [
|
||||
ApplyMethod(this_video.restore, run_time = 3),
|
||||
]
|
||||
)
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
video.shift, 0.5*video.get_height()*DOWN,
|
||||
run_time = 3,
|
||||
rate_func = squish_rate_func(
|
||||
there_and_back, alpha, alpha+0.3
|
||||
)
|
||||
)
|
||||
for video, alpha in zip(series, np.linspace(0, 0.7, len(series)))
|
||||
]+[
|
||||
Animation(self.teacher.bubble),
|
||||
Animation(self.teacher.bubble.content),
|
||||
])
|
||||
|
||||
self.play(
|
||||
FadeOut(self.teacher.bubble),
|
||||
FadeOut(self.teacher.bubble.content),
|
||||
self.get_teacher().change_mode, "raise_right_hand",
|
||||
*[
|
||||
ApplyMethod(pi.change_mode, "pondering")
|
||||
for pi in self.get_students()
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.series = series
|
||||
|
||||
|
||||
def show_examples(self):
|
||||
|
||||
self.wait(10)
|
||||
# put examples here in video editor
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class ShuffleThroughAllSequences(Scene):
|
||||
CONFIG = {
|
||||
"nb_coins" : 20,
|
||||
"run_time" : 5,
|
||||
"fps" : int(1.0/PRODUCTION_QUALITY_FRAME_DURATION),
|
||||
"coin_size" : 0.5,
|
||||
"coin_spacing" : 0.65
|
||||
}
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
nb_frames = self.run_time * self.fps
|
||||
nb_relevant_coins = int(np.log2(nb_frames)) + 1
|
||||
print("relevant coins:", nb_relevant_coins)
|
||||
nb_idle_coins = self.nb_coins - nb_relevant_coins
|
||||
|
||||
idle_heads = CoinSequence(nb_idle_coins * ["H"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
idle_tails = CoinSequence(nb_idle_coins * ["T"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
idle_tails.fade(0.5)
|
||||
|
||||
idle_part = VGroup(idle_heads, idle_tails)
|
||||
left_idle_part = CoinSequence(6 * ["H"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
|
||||
#self.add(idle_part, left_idle_part)
|
||||
self.add(left_idle_part)
|
||||
last_coin_seq = VGroup()
|
||||
|
||||
for i in range(2**nb_relevant_coins):
|
||||
binary_seq = binary(i)
|
||||
# pad to the left with 0s
|
||||
nb_leading_zeroes = nb_relevant_coins - len(binary_seq)
|
||||
for j in range(nb_leading_zeroes):
|
||||
binary_seq.insert(0, 0)
|
||||
seq2 = ["H" if x == 0 else "T" for x in binary_seq]
|
||||
coin_seq = CoinSequence(seq2,
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
coin_seq.next_to(idle_part, LEFT, buff = self.coin_spacing - self.coin_size)
|
||||
left_idle_part.next_to(coin_seq, LEFT, buff = self.coin_spacing - self.coin_size)
|
||||
all_coins = VGroup(left_idle_part, coin_seq) #, idle_part)
|
||||
all_coins.center()
|
||||
self.remove(last_coin_seq)
|
||||
self.add(coin_seq)
|
||||
#self.wait(1.0/self.fps)
|
||||
self.update_frame()
|
||||
self.add_frames(self.get_frame())
|
||||
last_coin_seq = coin_seq
|
||||
print(float(i)/2**nb_relevant_coins)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class IllustrateAreaModelBayes(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
color_A = YELLOW
|
||||
color_not_A = YELLOW_E
|
||||
color_B = MAROON
|
||||
color_not_B = MAROON_E
|
||||
opacity_B = 0.7
|
||||
|
||||
|
||||
# show independent events
|
||||
|
||||
sample_space_width = sample_space_height = 3
|
||||
p_of_A = 0.7
|
||||
p_of_not_A = 1 - p_of_A
|
||||
p_of_B = 0.8
|
||||
p_of_not_B = 1 - p_of_B
|
||||
|
||||
|
||||
rect_A = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = 1 * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_A,
|
||||
fill_opacity = 1.0
|
||||
).move_to(3 * RIGHT + 1.5 * UP)
|
||||
|
||||
rect_not_A = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = 1 * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_A,
|
||||
fill_opacity = 1.0
|
||||
).next_to(rect_A, RIGHT, buff = 0)
|
||||
|
||||
brace_A = Brace(rect_A, DOWN)
|
||||
label_A = TexMobject("P(A)").next_to(brace_A, DOWN).scale(0.7)
|
||||
brace_not_A = Brace(rect_not_A, DOWN)
|
||||
label_not_A = TexMobject("P(\\text{not }A)").next_to(brace_not_A, DOWN).scale(0.7)
|
||||
|
||||
# self.play(
|
||||
# LaggedStartMap(FadeIn, VGroup(rect_A, rect_not_A))
|
||||
# )
|
||||
# self.play(
|
||||
# ShowCreation(brace_A),
|
||||
# Write(label_A),
|
||||
# )
|
||||
|
||||
|
||||
|
||||
rect_B = Rectangle(
|
||||
width = 1 * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
)
|
||||
rect_not_B = Rectangle(
|
||||
width = 1 * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_B, UP, buff = 0)
|
||||
|
||||
VGroup(rect_B, rect_not_B).move_to(VGroup(rect_A, rect_not_A))
|
||||
|
||||
brace_B = Brace(rect_B, LEFT)
|
||||
label_B = TexMobject("P(B)").next_to(brace_B, LEFT).scale(0.7)
|
||||
brace_not_B = Brace(rect_not_B, LEFT)
|
||||
label_not_B = TexMobject("P(\\text{not }B)").next_to(brace_not_B, LEFT).scale(0.7)
|
||||
|
||||
# self.play(
|
||||
# LaggedStartMap(FadeIn, VGroup(rect_B, rect_not_B))
|
||||
# )
|
||||
# self.play(
|
||||
# ShowCreation(brace_B),
|
||||
# Write(label_B),
|
||||
# )
|
||||
|
||||
rect_A_and_B = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 3,
|
||||
fill_opacity = 0.0
|
||||
).align_to(rect_A, DOWN).align_to(rect_A,LEFT)
|
||||
label_A_and_B = TexMobject("P(A\\text{ and }B)").scale(0.7)
|
||||
label_A_and_B.move_to(rect_A_and_B)
|
||||
|
||||
# self.play(
|
||||
# ShowCreation(rect_A_and_B)
|
||||
# )
|
||||
|
||||
indep_formula = TexMobject("P(A\\text{ and }B)", "=", "P(A)", "\cdot", "P(B)")
|
||||
indep_formula = indep_formula.scale(0.7)
|
||||
label_p_of_b = indep_formula.get_part_by_tex("P(B)")
|
||||
|
||||
label_A_and_B_copy = label_A_and_B.copy()
|
||||
label_A_copy = label_A.copy()
|
||||
label_B_copy = label_B.copy()
|
||||
# self.add(label_A_and_B_copy, label_A_copy, label_B_copy)
|
||||
|
||||
# self.play(Transform(label_A_and_B_copy, indep_formula[0]))
|
||||
# self.play(FadeIn(indep_formula[1]))
|
||||
# self.play(Transform(label_A_copy, indep_formula[2]))
|
||||
# self.play(FadeIn(indep_formula[3]))
|
||||
# self.play(Transform(label_B_copy, indep_formula[4]))
|
||||
|
||||
#self.wait()
|
||||
|
||||
label_A_and_B_copy = indep_formula[0]
|
||||
label_A_copy = indep_formula[2]
|
||||
label_B_copy = indep_formula[4]
|
||||
|
||||
# show conditional prob
|
||||
|
||||
rect_A_and_B.set_fill(color = RED, opacity = 0.5)
|
||||
rect_A_and_not_B = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B, UP, buff = 0)
|
||||
|
||||
rect_not_A_and_B = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B, RIGHT, buff = 0)
|
||||
|
||||
rect_not_A_and_not_B = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_not_A_and_B, UP, buff = 0)
|
||||
|
||||
|
||||
indep_formula.next_to(rect_not_A, LEFT, buff = 5)
|
||||
#indep_formula.shift(UP)
|
||||
|
||||
self.play(Write(indep_formula))
|
||||
|
||||
self.play(
|
||||
FadeIn(VGroup(
|
||||
rect_A, rect_not_A, brace_A, label_A, brace_B, label_B,
|
||||
rect_A_and_not_B, rect_not_A_and_B, rect_not_A_and_not_B,
|
||||
rect_A_and_B,
|
||||
label_A_and_B,
|
||||
))
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
p_of_B_knowing_A = 0.6
|
||||
rect_A_and_B.target = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_B_knowing_A * sample_space_height,
|
||||
stroke_width = 3,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
).align_to(rect_A_and_B, DOWN).align_to(rect_A_and_B, LEFT)
|
||||
|
||||
rect_A_and_not_B.target = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = (1 - p_of_B_knowing_A) * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B.target, UP, buff = 0)
|
||||
|
||||
brace_B.target = Brace(rect_A_and_B.target, LEFT)
|
||||
label_B.target = TexMobject("P(B\mid A)").scale(0.7).next_to(brace_B.target, LEFT)
|
||||
|
||||
|
||||
self.play(
|
||||
MoveToTarget(rect_A_and_B),
|
||||
MoveToTarget(rect_A_and_not_B),
|
||||
MoveToTarget(brace_B),
|
||||
MoveToTarget(label_B),
|
||||
label_A_and_B.move_to,rect_A_and_B.target
|
||||
)
|
||||
label_B_knowing_A = label_B
|
||||
|
||||
#self.play(FadeOut(label_B_copy))
|
||||
self.remove(indep_formula.get_part_by_tex("P(B)"))
|
||||
indep_formula.remove(indep_formula.get_part_by_tex("P(B)"))
|
||||
label_B_knowing_A_copy = label_B_knowing_A.copy()
|
||||
self.add(label_B_knowing_A_copy)
|
||||
|
||||
self.play(
|
||||
label_B_knowing_A_copy.next_to, indep_formula.get_part_by_tex("\cdot"), RIGHT,
|
||||
)
|
||||
|
||||
# solve formula for P(B|A)
|
||||
|
||||
rearranged_formula = TexMobject("P(B\mid A)", "=", "{P(A\\text{ and }B) \over P(A)}")
|
||||
rearranged_formula.move_to(indep_formula)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
self.play(
|
||||
# in some places get_part_by_tex does not find the correct part
|
||||
# so I picked out fitting indices
|
||||
label_B_knowing_A_copy.move_to, rearranged_formula.get_part_by_tex("P(B\mid A)"),
|
||||
label_A_copy.move_to, rearranged_formula[-1][10],
|
||||
label_A_and_B_copy.move_to, rearranged_formula[-1][3],
|
||||
indep_formula.get_part_by_tex("=").move_to, rearranged_formula.get_part_by_tex("="),
|
||||
Transform(indep_formula.get_part_by_tex("\cdot"), rearranged_formula[2][8]),
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(rearranged_formula, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from old_projects.eoc.chapter8 import *
|
||||
|
||||
import scipy.special
|
||||
|
||||
class IllustrateAreaModelErf(GraphScene):
|
||||
CONFIG = {
|
||||
"x_min" : -3.0,
|
||||
"x_max" : 3.0,
|
||||
"y_min" : 0,
|
||||
"y_max" : 1.0,
|
||||
"num_rects": 400,
|
||||
"y_axis_label" : "",
|
||||
"x_axis_label" : "",
|
||||
"variable_point_label" : "a",
|
||||
"graph_origin": 2.5 * DOWN + 4 * RIGHT,
|
||||
"x_axis_width": 5,
|
||||
"y_axis_height": 5
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
# integral bounds
|
||||
x_min_1 = -0.0001
|
||||
x_max_1 = 0.0001
|
||||
|
||||
x_min_2 = self.x_min
|
||||
x_max_2 = self.x_max
|
||||
|
||||
self.setup_axes()
|
||||
self.remove(self.x_axis, self.y_axis)
|
||||
graph = self.get_graph(lambda x: np.exp(-x**2) * 2.0 / TAU ** 0.5)
|
||||
area = self.area = self.get_area(graph, x_min_1, x_max_1)
|
||||
|
||||
|
||||
pdf_formula = TexMobject("p(x) = {1\over \sigma\sqrt{2\pi}}e^{-{1\over 2}({x\over\sigma})^2}")
|
||||
pdf_formula.set_color(graph.color)
|
||||
|
||||
cdf_formula = TexMobject("P(|X| < ", "a", ") = \int", "_{-a}", "^a", "p(x) dx")
|
||||
cdf_formula.set_color_by_tex("a", YELLOW)
|
||||
cdf_formula.next_to(graph, LEFT, buff = 2)
|
||||
pdf_formula.next_to(cdf_formula, UP)
|
||||
|
||||
formulas = VGroup(pdf_formula, cdf_formula)
|
||||
self.play(Write(pdf_formula))
|
||||
self.play(Write(cdf_formula))
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
self.play(ShowCreation(self.x_axis))
|
||||
self.play(ShowCreation(graph))
|
||||
self.play(FadeIn(area))
|
||||
|
||||
self.v_graph = graph
|
||||
self.add_T_label(
|
||||
x_min_1,
|
||||
label = "-a",
|
||||
side = LEFT,
|
||||
color = YELLOW,
|
||||
animated = False
|
||||
)
|
||||
self.add_T_label(
|
||||
x_max_1,
|
||||
label = "a",
|
||||
side = RIGHT,
|
||||
color = YELLOW,
|
||||
animated = False
|
||||
)
|
||||
# don't show the labels just yet
|
||||
self.remove(
|
||||
self.left_T_label_group[0],
|
||||
self.right_T_label_group[0],
|
||||
)
|
||||
|
||||
def integral_update_func(t):
|
||||
return scipy.special.erf(
|
||||
self.point_to_coords(self.right_v_line.get_center())[0]
|
||||
)
|
||||
|
||||
def integral_update_func_percent(t):
|
||||
return 100 * integral_update_func(t)
|
||||
|
||||
equals_sign = TexMobject("=").next_to(cdf_formula, buff = MED_LARGE_BUFF)
|
||||
|
||||
cdf_value = DecimalNumber(0, color = graph.color, num_decimal_places = 3)
|
||||
cdf_value.next_to(equals_sign)
|
||||
self.play(
|
||||
FadeIn(equals_sign),
|
||||
FadeIn(cdf_value)
|
||||
)
|
||||
self.add_foreground_mobject(cdf_value)
|
||||
|
||||
cdf_percentage = DecimalNumber(0, unit = "\\%")
|
||||
cdf_percentage.move_to(self.coords_to_point(0,0.2))
|
||||
self.add_foreground_mobject(cdf_percentage)
|
||||
|
||||
cdf_value.add_updater(
|
||||
lambda m: m.set_value(integral_update_func())
|
||||
)
|
||||
|
||||
anim = self.get_animation_integral_bounds_change(
|
||||
graph, x_min_2, x_max_2,
|
||||
run_time = 3)
|
||||
|
||||
|
||||
self.play(
|
||||
anim
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(formulas, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class IllustrateAreaModelExpectation(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
formula = TexMobject("E[X] = \sum_{i=1}^N p_i x_i").move_to(3 * LEFT + UP)
|
||||
self.play(Write(formula))
|
||||
|
||||
|
||||
x_scale = 5.0
|
||||
y_scale = 1.0
|
||||
|
||||
probabilities = np.array([1./8, 3./8, 3./8, 1./8])
|
||||
prob_strings = ["{1\over 8}","{3\over 8}","{3\over 8}","{1\over 8}"]
|
||||
cumulative_probabilities = np.cumsum(probabilities)
|
||||
cumulative_probabilities = np.insert(cumulative_probabilities, 0, 0)
|
||||
y_values = np.array([0, 1, 2, 3])
|
||||
|
||||
hist = Histogram(probabilities, y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none"
|
||||
)
|
||||
|
||||
flat_hist = Histogram(probabilities, 0 * y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none"
|
||||
)
|
||||
|
||||
self.play(FadeIn(flat_hist))
|
||||
self.play(
|
||||
ReplacementTransform(flat_hist, hist)
|
||||
)
|
||||
|
||||
braces = VGroup()
|
||||
p_labels = VGroup()
|
||||
# add x labels (braces)
|
||||
for (p,string,bar) in zip(probabilities, prob_strings,hist.bars):
|
||||
brace = Brace(bar, DOWN, buff = 0.1)
|
||||
p_label = TexMobject(string).next_to(brace, DOWN, buff = SMALL_BUFF).scale(0.7)
|
||||
group = VGroup(brace, p_label)
|
||||
braces.add(brace)
|
||||
p_labels.add(p_label)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(FadeIn,braces),
|
||||
LaggedStartMap(FadeIn, p_labels)
|
||||
)
|
||||
|
||||
|
||||
|
||||
y_average = np.mean(y_values)
|
||||
averaged_y_values = y_average * np.ones(np.shape(y_values))
|
||||
|
||||
averaged_hist = flat_hist = Histogram(probabilities, averaged_y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none",
|
||||
y_labels = "none"
|
||||
).fade(0.2)
|
||||
|
||||
ghost_hist = hist.copy().fade(0.8)
|
||||
self.bring_to_back(ghost_hist)
|
||||
|
||||
self.play(Transform(hist, averaged_hist, run_time = 3))
|
||||
self.wait()
|
||||
|
||||
average_brace = Brace(averaged_hist, RIGHT, buff = 0.1)
|
||||
average_label = TexMobject(str(y_average)).scale(0.7)
|
||||
average_label.next_to(average_brace, RIGHT, SMALL_BUFF)
|
||||
average_group = VGroup(average_brace, average_label)
|
||||
|
||||
one_brace = Brace(averaged_hist, DOWN, buff = 0.1)
|
||||
one_p_label = TexMobject(str(1)).next_to(one_brace, DOWN, buff = SMALL_BUFF).scale(0.7)
|
||||
one_group = VGroup(one_brace, one_p_label)
|
||||
|
||||
self.play(
|
||||
FadeIn(average_group),
|
||||
Transform(braces, one_brace),
|
||||
Transform(p_labels, one_p_label),
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(formula, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,164 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.chapter1.brick_row_scene import BrickRowScene
|
||||
|
||||
class EntireBrickWall(BrickRowScene, MovingCameraScene):
|
||||
|
||||
def setup(self):
|
||||
super(BrickRowScene, self).setup()
|
||||
super(PiCreatureScene, self).setup()
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.remove(self.get_primary_pi_creature())
|
||||
|
||||
row_height = 0.3
|
||||
nb_rows = 20
|
||||
start_point = 3 * UP + 1 * LEFT
|
||||
|
||||
rows = VMobject()
|
||||
rows.add(BrickRow(0, height = row_height))
|
||||
rows.move_to(start_point)
|
||||
self.add(rows)
|
||||
|
||||
zero_counter = Integer(0).next_to(start_point + 0.5 * rows[0].width * RIGHT)
|
||||
nb_flips_text = TextMobject("\# of flips")
|
||||
nb_flips_text.next_to(zero_counter, RIGHT, buff = LARGE_BUFF)
|
||||
self.add(zero_counter, nb_flips_text)
|
||||
flip_counters = VGroup(zero_counter)
|
||||
|
||||
for i in range(1, nb_rows + 1):
|
||||
rows.add(rows[-1].copy())
|
||||
self.bring_to_back(rows[-1])
|
||||
anims = [
|
||||
rows[-1].shift, row_height * DOWN,
|
||||
Animation(rows[-2])
|
||||
]
|
||||
|
||||
if i % 5 == 0:
|
||||
counter = Integer(i)
|
||||
counter.next_to(rows[-1].get_right() + row_height * DOWN, RIGHT)
|
||||
flip_counters.add(counter)
|
||||
anims.append(FadeIn(counter))
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
self.play(SplitRectsInBrickWall(rows[-1]))
|
||||
rows.submobjects[-1] = self.merge_rects_by_subdiv(rows[-1])
|
||||
rows.submobjects[-1] = self.merge_rects_by_coloring(rows[-1])
|
||||
|
||||
|
||||
# draw indices under the last row for the number of tails
|
||||
tails_counters = VGroup()
|
||||
for (i, rect) in enumerate(rows[-1].rects):
|
||||
if i < 6 or i > 14:
|
||||
continue
|
||||
if i == 6:
|
||||
counter = TexMobject("\dots", color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF)
|
||||
elif i == 14:
|
||||
counter = TexMobject("\dots", color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF)
|
||||
counter.shift(0.2 * RIGHT)
|
||||
else:
|
||||
counter = Integer(i, color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN)
|
||||
tails_counters.add(counter)
|
||||
|
||||
nb_tails_text = TextMobject("\# of tails", color = COLOR_TAILS)
|
||||
nb_tails_text.next_to(tails_counters[-1], RIGHT, buff = LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(FadeIn, tails_counters),
|
||||
FadeIn(nb_tails_text)
|
||||
)
|
||||
|
||||
# remove any hidden brick rows
|
||||
self.clear()
|
||||
self.add(nb_flips_text)
|
||||
|
||||
mobs_to_shift = VGroup(
|
||||
rows, flip_counters, tails_counters, nb_tails_text,
|
||||
)
|
||||
self.play(mobs_to_shift.shift, 3 * UP)
|
||||
|
||||
last_row_rect = SurroundingRectangle(rows[-1], buff = 0)
|
||||
last_row_rect.set_stroke(color = YELLOW, width = 6)
|
||||
|
||||
rows.save_state()
|
||||
self.play(
|
||||
rows.fade, 0.9,
|
||||
ShowCreation(last_row_rect)
|
||||
)
|
||||
|
||||
def highlighted_brick(row = 20, nb_tails = 10):
|
||||
brick_copy = rows[row].rects[nb_tails].copy()
|
||||
brick_copy.set_fill(color = YELLOW, opacity = 0.8)
|
||||
prob_percentage = float(choose(row, nb_tails)) / 2**row * 100
|
||||
brick_label = DecimalNumber(prob_percentage,
|
||||
unit = "\%", num_decimal_places = 1, color = BLACK)
|
||||
brick_label.move_to(brick_copy)
|
||||
brick_label.set_height(0.8 * brick_copy.get_height())
|
||||
return VGroup(brick_copy, brick_label)
|
||||
|
||||
highlighted_bricks = [
|
||||
highlighted_brick(row = 20, nb_tails = i)
|
||||
for i in range(20)
|
||||
]
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeIn(highlighted_bricks[10])
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(highlighted_bricks[10]),
|
||||
FadeIn(highlighted_bricks[9]),
|
||||
FadeIn(highlighted_bricks[11]),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(highlighted_bricks[9]),
|
||||
FadeOut(highlighted_bricks[11]),
|
||||
FadeIn(highlighted_bricks[8]),
|
||||
FadeIn(highlighted_bricks[12]),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(highlighted_bricks[8]),
|
||||
FadeOut(highlighted_bricks[12]),
|
||||
FadeOut(last_row_rect),
|
||||
rows.restore,
|
||||
)
|
||||
self.wait()
|
||||
new_frame = self.camera_frame.copy()
|
||||
new_frame.scale(0.0001).move_to(rows.get_corner(DR))
|
||||
|
||||
self.play(
|
||||
Transform(self.camera_frame, new_frame,
|
||||
run_time = 9,
|
||||
rate_func = exponential_decay
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class Chapter1OpeningQuote(OpeningQuote):
|
||||
CONFIG = {
|
||||
"fade_in_kwargs": {
|
||||
"lag_ratio": 0.5,
|
||||
"rate_func": linear,
|
||||
"run_time": 10,
|
||||
},
|
||||
"text_size" : "\\normalsize",
|
||||
"use_quotation_marks": False,
|
||||
"quote" : [
|
||||
"To see a world in a grain of sand\\\\",
|
||||
"And a heaven in a wild flower,\\\\",
|
||||
"Hold infinity in the palm of your hand\\\\",
|
||||
"\phantom{r}And eternity in an hour.\\\\"
|
||||
],
|
||||
"quote_arg_separator" : " ",
|
||||
"highlighted_quote_terms" : {},
|
||||
"author" : "William Blake: \\\\ \emph{Auguries of Innocence}",
|
||||
}
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.wait(5)
|
||||
|
||||
self.change_student_modes(
|
||||
"confused", "frustrated", "dejected",
|
||||
look_at_arg = UP + 2 * RIGHT
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
self.get_teacher().change_mode,"raise_right_hand"
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.wait(30)
|
||||
# put examples here in video editor
|
||||
|
||||
|
||||
# # # # # # # # # # # # # # # # # #
|
||||
# show examples of the area model #
|
||||
# # # # # # # # # # # # # # # # # #
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class JustFlipping(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E, flip_height = 1).shift(2 * DOWN)
|
||||
self.add(randy)
|
||||
|
||||
self.wait(2)
|
||||
|
||||
for i in range(10):
|
||||
self.wait()
|
||||
self.play(FlipCoin(randy))
|
||||
|
||||
|
||||
|
||||
class JustFlippingWithResults(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E, flip_height = 1).shift(2 * DOWN)
|
||||
self.add(randy)
|
||||
|
||||
self.wait(2)
|
||||
|
||||
for i in range(10):
|
||||
self.wait()
|
||||
self.play(FlipCoin(randy))
|
||||
result = random.choice(["H", "T"])
|
||||
if result == "H":
|
||||
coin = UprightHeads().scale(3)
|
||||
else:
|
||||
coin = UprightTails().scale(3)
|
||||
coin.move_to(2 * UP + 2.5 * LEFT + i * 0.6 * RIGHT)
|
||||
self.play(FadeIn(coin))
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class MillionFlips(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("1{,}000{,}000 flips")
|
||||
title.to_edge(UP)
|
||||
self.add(title)
|
||||
|
||||
small_wait_time = 1.0 / 15 # Um...
|
||||
|
||||
n_flips_label = TextMobject("\\# Flips: ")
|
||||
n_heads_label = TextMobject("\\# Heads: ")
|
||||
n_flips_count = Integer(0)
|
||||
n_heads_count = Integer(0)
|
||||
n_heads_label.to_edge(RIGHT, buff=2 * LARGE_BUFF)
|
||||
n_flips_label.next_to(n_heads_label, DOWN, aligned_edge=LEFT)
|
||||
n_flips_count.next_to(n_flips_label[-1], RIGHT)
|
||||
n_heads_count.next_to(n_heads_label[-1], RIGHT)
|
||||
VGroup(n_flips_count, n_heads_count).shift(0.5 * SMALL_BUFF * UP)
|
||||
self.add(n_flips_label, n_heads_label, n_flips_count, n_heads_count)
|
||||
|
||||
coins = VGroup(*[
|
||||
FlatHeads() if random.random() < 0.5 else FlatTails()
|
||||
for x in range(100)
|
||||
])
|
||||
self.organize_group(coins)
|
||||
|
||||
proportions = np.random.normal(0.5, 0.5 * 0.1, 100)
|
||||
hundred_boxes = VGroup(*[
|
||||
Square(
|
||||
stroke_width=1,
|
||||
stroke_color=WHITE,
|
||||
fill_opacity=1,
|
||||
fill_color=interpolate_color(COLOR_HEADS, COLOR_TAILS, prop)
|
||||
)
|
||||
for prop in proportions
|
||||
])
|
||||
self.organize_group(hundred_boxes)
|
||||
|
||||
ten_k_proportions = np.random.normal(0.5, 0.5 * 0.01, 100)
|
||||
ten_k_boxes = VGroup(*[
|
||||
Square(
|
||||
stroke_width=1,
|
||||
stroke_color=WHITE,
|
||||
fill_opacity=1,
|
||||
fill_color=interpolate_color(COLOR_HEADS, COLOR_TAILS, prop)
|
||||
)
|
||||
for prop in ten_k_proportions
|
||||
])
|
||||
self.organize_group(ten_k_boxes)
|
||||
|
||||
# Animations
|
||||
for coin in coins:
|
||||
self.add(coin)
|
||||
self.increment(n_flips_count)
|
||||
if isinstance(coin, FlatHeads):
|
||||
self.increment(n_heads_count)
|
||||
self.wait(small_wait_time)
|
||||
|
||||
self.play(
|
||||
FadeIn(hundred_boxes[0]),
|
||||
coins.set_stroke, {"width": 0},
|
||||
coins.replace, hundred_boxes[0]
|
||||
)
|
||||
hundred_boxes[0].add(coins)
|
||||
for box, prop in list(zip(hundred_boxes, proportions))[1:]:
|
||||
self.add(box)
|
||||
self.increment(n_flips_count, 100)
|
||||
self.increment(n_heads_count, int(np.round(prop * 100)))
|
||||
self.wait(small_wait_time)
|
||||
|
||||
self.play(
|
||||
FadeIn(ten_k_boxes[0]),
|
||||
hundred_boxes.set_stroke, {"width": 0},
|
||||
hundred_boxes.replace, ten_k_boxes[0]
|
||||
)
|
||||
ten_k_boxes[0].add(hundred_boxes)
|
||||
for box, prop in list(zip(ten_k_boxes, ten_k_proportions))[1:]:
|
||||
self.add(box)
|
||||
self.increment(n_flips_count, 10000)
|
||||
self.increment(n_heads_count, int(np.round(prop * 10000)))
|
||||
self.wait(small_wait_time)
|
||||
self.wait()
|
||||
|
||||
def organize_group(self, group):
|
||||
group.arrange_in_grid(10)
|
||||
group.set_height(5)
|
||||
group.shift(DOWN + 2 * LEFT)
|
||||
|
||||
def increment(self, integer_mob, value=1):
|
||||
new_int = Integer(integer_mob.number + value)
|
||||
new_int.move_to(integer_mob, DL)
|
||||
integer_mob.number += value
|
||||
integer_mob.submobjects = new_int.submobjects
|
||||
|
||||
|
||||
class PropHeadsWithinThousandth(Scene):
|
||||
def construct(self):
|
||||
prob = TexMobject(
|
||||
"P(499{,}000 \\le", "\\# \\text{H}", "\\le 501{,}000)",
|
||||
"\\approx", "0.9545",
|
||||
)
|
||||
prob[1].set_color(RED)
|
||||
prob[-1].set_color(YELLOW)
|
||||
self.add(prob)
|
||||
|
||||
|
||||
class PropHeadsWithinHundredth(Scene):
|
||||
def construct(self):
|
||||
prob = TexMobject(
|
||||
"P(490{,}000 \\le", "\\# \\text{H}", "\\le 510{,}000)",
|
||||
"\\approx", "0.99999999\\dots",
|
||||
)
|
||||
prob[1].set_color(RED)
|
||||
prob[-1].set_color(YELLOW)
|
||||
self.add(prob)
|
||||
@@ -1,299 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class GenericMorphBrickRowIntoHistogram(Scene):
|
||||
|
||||
CONFIG = {
|
||||
"level" : 3,
|
||||
"bar_width" : 2.0,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"show_tallies" : False,
|
||||
"show_nb_flips" : True
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.row = BrickRow(self.level, height = self.bar_width, width = 10)
|
||||
self.bars = OutlineableBars(*[self.row.rects[i] for i in range(self.level + 1)])
|
||||
self.bar_anchors = [self.bar_anchor_height * UP + self.row.height * (i - 0.5 * self.level) * RIGHT for i in range(self.level + 1)]
|
||||
|
||||
self.add(self.row)
|
||||
|
||||
if self.show_tallies:
|
||||
|
||||
tallies = VMobject()
|
||||
|
||||
for (i,brick) in enumerate(self.row.rects):
|
||||
tally = TallyStack(self.level - i, i)
|
||||
tally.move_to(brick)
|
||||
self.add(tally)
|
||||
tallies.add(tally)
|
||||
brick.set_stroke(width = 3)
|
||||
|
||||
if self.show_nb_flips:
|
||||
nb_flips_text = TextMobject("\# of flips: " + str(self.level))
|
||||
nb_flips_text.to_corner(UR)
|
||||
self.add(nb_flips_text)
|
||||
|
||||
self.remove(self.row.subdivs, self.row.border)
|
||||
|
||||
for rect in self.row.rects:
|
||||
rect.set_stroke(color = WHITE, width = 3)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
self.row.rects.space_out_submobjects, {"factor" : 1.3},
|
||||
FadeOut(tallies)
|
||||
)
|
||||
self.wait()
|
||||
anims = []
|
||||
for brick in self.row.rects:
|
||||
anims.append(brick.rotate)
|
||||
anims.append(TAU/4)
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
self.wait()
|
||||
|
||||
anims = []
|
||||
for (i,brick) in enumerate(self.row.rects):
|
||||
anims.append(brick.next_to)
|
||||
anims.append(self.bar_anchors[i])
|
||||
anims.append({"direction" : UP, "buff" : 0})
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
self.bars.create_outline()
|
||||
anims = [
|
||||
ApplyMethod(rect.set_stroke, {"width" : 0})
|
||||
for rect in self.bars
|
||||
]
|
||||
anims.append(FadeIn(self.bars.outline))
|
||||
self.play(*anims)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram):
|
||||
|
||||
CONFIG = {
|
||||
"level" : 3,
|
||||
"prob_denominator" : 8,
|
||||
"bar_width" : 2.0,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"show_tallies" : True,
|
||||
"show_nb_flips" : False
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
|
||||
|
||||
super(MorphBrickRowIntoHistogram3,self).construct()
|
||||
|
||||
|
||||
# draw x-axis
|
||||
|
||||
x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0)
|
||||
x_axis.next_to(self.bars, DOWN, buff = 0)
|
||||
#x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)])
|
||||
x_labels = VMobject()
|
||||
|
||||
for (i, bar) in enumerate(self.bars):
|
||||
label = Integer(i)
|
||||
label.next_to(self.bar_anchors[i], DOWN)
|
||||
x_labels.add(label)
|
||||
|
||||
nb_tails_label = TextMobject("\# of tails")
|
||||
nb_tails_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF)
|
||||
|
||||
|
||||
|
||||
# draw y-guides
|
||||
|
||||
y_guides = VMobject()
|
||||
for i in range(0,self.prob_denominator + 1):
|
||||
y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY)
|
||||
y_guide.move_to(self.bar_anchor_height * UP + i * float(self.row.width) / self.prob_denominator * UP)
|
||||
y_guide_label = TexMobject("{" + str(i) + "\over " + str(self.prob_denominator) + "}", color = GRAY)
|
||||
y_guide_label.scale(0.7)
|
||||
y_guide_label.next_to(y_guide, LEFT)
|
||||
if i != 0:
|
||||
y_guide.add(y_guide_label)
|
||||
y_guides.add(y_guide)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeIn(y_guides),
|
||||
Animation(self.bars.outline),
|
||||
Animation(self.bars)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeIn(x_axis),
|
||||
FadeIn(x_labels),
|
||||
FadeIn(nb_tails_label)
|
||||
)
|
||||
|
||||
self.add_foreground_mobject(nb_tails_label)
|
||||
area_color = YELLOW
|
||||
|
||||
total_area_text = TextMobject("total area =", color = area_color)
|
||||
area_decimal = DecimalNumber(0, color = area_color, num_decimal_places = 3)
|
||||
area_decimal.next_to(total_area_text, RIGHT)
|
||||
|
||||
total_area_group = VGroup(total_area_text, area_decimal)
|
||||
total_area_group.move_to(2.7 * UP)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeIn(total_area_text),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
cumulative_areas = [0.125, 0.5, 0.875, 1]
|
||||
covering_rects = self.bars.copy()
|
||||
for (i,rect) in enumerate(covering_rects):
|
||||
rect.set_fill(color = area_color, opacity = 0.5)
|
||||
self.play(
|
||||
FadeIn(rect, rate_func = linear),
|
||||
ChangeDecimalToValue(area_decimal, cumulative_areas[i],
|
||||
rate_func = linear)
|
||||
)
|
||||
self.wait(0.2)
|
||||
|
||||
self.wait()
|
||||
|
||||
total_area_rect = SurroundingRectangle(
|
||||
total_area_group,
|
||||
buff = MED_SMALL_BUFF,
|
||||
stroke_color = area_color
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(covering_rects),
|
||||
ShowCreation(total_area_rect)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram):
|
||||
CONFIG = {
|
||||
"level" : 20,
|
||||
"prob_ticks" : 0.05,
|
||||
"bar_width" : 0.5,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"x_ticks": 5
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
super(MorphBrickRowIntoHistogram20, self).construct()
|
||||
|
||||
x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0)
|
||||
x_axis.next_to(self.bars, DOWN, buff = 0)
|
||||
#x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)])
|
||||
x_labels = VMobject()
|
||||
for (i, bar) in enumerate(self.bars):
|
||||
if i % self.x_ticks != 0:
|
||||
continue
|
||||
label = Integer(i)
|
||||
label.next_to(self.bar_anchors[i], DOWN)
|
||||
x_labels.add(label)
|
||||
|
||||
nb_tails_label = TextMobject("\# of tails")
|
||||
nb_tails_label.move_to(5 * RIGHT + 2.5 * DOWN)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeIn(x_axis),
|
||||
FadeIn(x_labels),
|
||||
FadeIn(nb_tails_label)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# draw y-guides
|
||||
|
||||
max_prob = float(choose(self.level, self.level/2)) / 2 ** self.level
|
||||
|
||||
y_guides = VMobject()
|
||||
y_guide_heights = []
|
||||
prob_grid = np.arange(self.prob_ticks, 1.3 * max_prob, self.prob_ticks)
|
||||
for i in prob_grid:
|
||||
y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY)
|
||||
y_guide_height = self.bar_anchor_height + i * float(self.row.width)
|
||||
y_guide_heights.append(y_guide_height)
|
||||
y_guide.move_to(y_guide_height * UP)
|
||||
y_guide_label = DecimalNumber(i, num_decimal_places = 2, color = GRAY)
|
||||
y_guide_label.scale(0.7)
|
||||
y_guide_label.next_to(y_guide, LEFT)
|
||||
y_guide.add(y_guide_label)
|
||||
y_guides.add(y_guide)
|
||||
|
||||
self.bring_to_back(y_guides)
|
||||
self.play(FadeIn(y_guides), Animation(self.bars))
|
||||
self.wait()
|
||||
|
||||
histogram_width = self.bars.get_width()
|
||||
histogram_height = self.bars.get_height()
|
||||
|
||||
# scale to fit screen
|
||||
self.scale_x = 10.0/((len(self.bars) - 1) * self.bar_width)
|
||||
self.scale_y = 6.0/histogram_height
|
||||
|
||||
|
||||
anims = []
|
||||
for (bar, x_label) in zip(self.bars, x_labels):
|
||||
v = (self.scale_x - 1) * x_label.get_center()[0] * RIGHT
|
||||
anims.append(x_label.shift)
|
||||
anims.append(v)
|
||||
|
||||
|
||||
anims.append(self.bars.stretch_about_point)
|
||||
anims.append(self.scale_x)
|
||||
anims.append(0)
|
||||
anims.append(ORIGIN)
|
||||
anims.append(self.bars.outline.stretch_about_point)
|
||||
anims.append(self.scale_x)
|
||||
anims.append(0)
|
||||
anims.append(ORIGIN)
|
||||
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
anims = []
|
||||
for (guide, i, h) in zip(y_guides, prob_grid, y_guide_heights):
|
||||
new_y_guide_height = self.bar_anchor_height + i * self.scale_y * float(self.row.width)
|
||||
v = (new_y_guide_height - h) * UP
|
||||
anims.append(guide.shift)
|
||||
anims.append(v)
|
||||
|
||||
anims.append(self.bars.stretch_about_point)
|
||||
anims.append(self.scale_y)
|
||||
anims.append(1)
|
||||
anims.append(self.bars.get_bottom())
|
||||
anims.append(self.bars.outline.stretch_about_point)
|
||||
anims.append(self.scale_y)
|
||||
anims.append(1)
|
||||
anims.append(self.bars.get_bottom())
|
||||
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
class MorphBrickRowIntoHistogram100(MorphBrickRowIntoHistogram20):
|
||||
CONFIG = {
|
||||
"level" : 100,
|
||||
"x_ticks": 20,
|
||||
"prob_ticks": 0.02
|
||||
}
|
||||
|
||||
class MorphBrickRowIntoHistogram500(MorphBrickRowIntoHistogram20):
|
||||
CONFIG = {
|
||||
"level" : 500,
|
||||
"x_ticks": 100,
|
||||
"prob_ticks": 0.01
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class ProbabilityDistributions(PiCreatureScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": False,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
lag_ratio = 0.2
|
||||
run_time = 3
|
||||
|
||||
|
||||
# WEATHER FORECAST
|
||||
|
||||
|
||||
unit_rect = Rectangle(
|
||||
height = 3, width = 3
|
||||
).shift(DOWN)
|
||||
|
||||
p_rain = 0.23
|
||||
p_sun = 1 - p_rain
|
||||
opacity = 0.7
|
||||
|
||||
rain_rect = unit_rect.copy().stretch(p_rain, 0)
|
||||
rain_rect.align_to(unit_rect, LEFT)
|
||||
rain_rect.set_fill(color = BLUE, opacity = opacity)
|
||||
rain_rect.set_stroke(width = 0)
|
||||
|
||||
sun_rect = unit_rect.copy().stretch(p_sun, 0)
|
||||
sun_rect.next_to(rain_rect, RIGHT, buff = 0)
|
||||
sun_rect.set_fill(color = YELLOW, opacity = opacity)
|
||||
sun_rect.set_stroke(width = 0)
|
||||
|
||||
self.add(unit_rect, rain_rect, sun_rect)
|
||||
|
||||
rain = SVGMobject(file_name = "rain").scale(0.25)
|
||||
sun = SVGMobject(file_name = "sun").scale(0.35)
|
||||
|
||||
rain.flip().move_to(rain_rect)
|
||||
sun.move_to(sun_rect)
|
||||
|
||||
self.add(rain, sun)
|
||||
|
||||
|
||||
text_scale = 0.7
|
||||
|
||||
brace_rain = Brace(rain_rect, UP)
|
||||
p_rain_label = TextMobject("$P($rain$)=$").scale(text_scale)
|
||||
p_rain_decimal = DecimalNumber(p_rain).scale(text_scale)
|
||||
p_rain_decimal.next_to(p_rain_label)
|
||||
p_rain_whole_label = VGroup(p_rain_label, p_rain_decimal)
|
||||
p_rain_whole_label.next_to(brace_rain, UP)
|
||||
|
||||
brace_sun = Brace(sun_rect, DOWN)
|
||||
p_sun_label = TextMobject("$P($sunshine$)=$").scale(text_scale)
|
||||
p_sun_decimal = DecimalNumber(p_sun).scale(text_scale)
|
||||
p_sun_decimal.next_to(p_sun_label)
|
||||
p_sun_whole_label = VGroup(p_sun_label, p_sun_decimal)
|
||||
p_sun_whole_label.next_to(brace_sun, DOWN)
|
||||
|
||||
self.add(brace_rain, p_rain_whole_label, brace_sun, p_sun_whole_label)
|
||||
|
||||
self.wait(6)
|
||||
|
||||
|
||||
|
||||
# new_p_rain = 0.68
|
||||
# new_p_sun = 1 - new_p_rain
|
||||
|
||||
# new_rain_rect = unit_rect.copy().stretch(new_p_rain, 0)
|
||||
# new_rain_rect.align_to(unit_rect, LEFT)
|
||||
# new_rain_rect.set_fill(color = BLUE, opacity = opacity)
|
||||
# new_rain_rect.set_stroke(width = 0)
|
||||
|
||||
# new_sun_rect = unit_rect.copy().stretch(new_p_sun, 0)
|
||||
# new_sun_rect.next_to(new_rain_rect, RIGHT, buff = 0)
|
||||
# new_sun_rect.set_fill(color = YELLOW, opacity = opacity)
|
||||
# new_sun_rect.set_stroke(width = 0)
|
||||
|
||||
# new_rain = SVGMobject(file_name = "rain").scale(0.35)
|
||||
# new_sun = SVGMobject(file_name = "sun").scale(0.35)
|
||||
|
||||
# new_rain.flip().move_to(new_rain_rect)
|
||||
# new_sun.move_to(new_sun_rect)
|
||||
|
||||
# new_brace_rain = Brace(new_rain_rect, UP)
|
||||
# new_p_rain_label = TextMobject("$P($rain$)=$").scale(text_scale)
|
||||
# new_p_rain_decimal = DecimalNumber(new_p_rain).scale(text_scale)
|
||||
# new_p_rain_decimal.next_to(new_p_rain_label)
|
||||
# new_p_rain_whole_label = VGroup(new_p_rain_label, new_p_rain_decimal)
|
||||
# new_p_rain_whole_label.next_to(new_brace_rain, UP)
|
||||
|
||||
|
||||
# new_brace_sun = Brace(new_sun_rect, DOWN)
|
||||
# new_p_sun_label = TextMobject("$P($sunshine$)=$").scale(text_scale)
|
||||
# new_p_sun_decimal = DecimalNumber(new_p_sun).scale(text_scale)
|
||||
# new_p_sun_decimal.next_to(new_p_sun_label)
|
||||
# new_p_sun_whole_label = VGroup(new_p_sun_label, new_p_sun_decimal)
|
||||
# new_p_sun_whole_label.next_to(new_brace_sun, DOWN)
|
||||
|
||||
# def rain_update_func(alpha):
|
||||
# return alpha * new_p_rain + (1 - alpha) * p_rain
|
||||
|
||||
# def sun_update_func(alpha):
|
||||
# return 1 - rain_update_func(alpha)
|
||||
|
||||
# update_p_rain = ChangingDecimal(
|
||||
# p_rain_decimal, rain_update_func,
|
||||
# tracked_mobject = p_rain_label,
|
||||
# run_time = run_time
|
||||
# )
|
||||
# update_p_sun = ChangingDecimal(
|
||||
# p_sun_decimal, sun_update_func,
|
||||
# tracked_mobject = p_sun_label,
|
||||
# run_time = run_time
|
||||
# )
|
||||
|
||||
# self.play(
|
||||
# Transform(rain_rect, new_rain_rect, run_time = run_time),
|
||||
# Transform(sun_rect, new_sun_rect, run_time = run_time),
|
||||
# Transform(rain, new_rain, run_time = run_time),
|
||||
# Transform(sun, new_sun, run_time = run_time),
|
||||
# Transform(brace_rain, new_brace_rain, run_time = run_time),
|
||||
# Transform(brace_sun, new_brace_sun, run_time = run_time),
|
||||
# Transform(p_rain_label, new_p_rain_label, run_time = run_time),
|
||||
# Transform(p_sun_label, new_p_sun_label, run_time = run_time),
|
||||
# update_p_rain,
|
||||
# update_p_sun
|
||||
# )
|
||||
|
||||
|
||||
|
||||
# move the forecast into a corner
|
||||
|
||||
forecast = VGroup(
|
||||
rain_rect, sun_rect, rain, sun, brace_rain, brace_sun,
|
||||
p_rain_whole_label, p_sun_whole_label, unit_rect
|
||||
)
|
||||
|
||||
forecast.target = forecast.copy().scale(0.5)
|
||||
forecast.target.to_corner(UL)
|
||||
|
||||
self.play(MoveToTarget(forecast))
|
||||
|
||||
self.play(
|
||||
FadeOut(brace_rain),
|
||||
FadeOut(brace_sun),
|
||||
FadeOut(p_rain_whole_label),
|
||||
FadeOut(p_sun_whole_label),
|
||||
)
|
||||
|
||||
self.wait(3)
|
||||
|
||||
|
||||
# DOUBLE DICE THROW
|
||||
|
||||
cell_size = 0.5
|
||||
dice_table = TwoDiceTable(cell_size = cell_size, label_scale = 0.7)
|
||||
dice_table.shift(0.8 * DOWN)
|
||||
dice_unit_rect = SurroundingRectangle(
|
||||
dice_table.cells, buff = 0,
|
||||
stroke_color=WHITE
|
||||
)
|
||||
|
||||
dice_table_grouped_cells = VGroup()
|
||||
|
||||
for i in range(6):
|
||||
dice_table_grouped_cells.add(VGroup(*[
|
||||
VGroup(
|
||||
dice_table.cells[6 * i - 5 * k],
|
||||
dice_table.labels[6 * i - 5 * k],
|
||||
)
|
||||
for k in range(i + 1)
|
||||
]))
|
||||
|
||||
for i in range(5):
|
||||
dice_table_grouped_cells.add(VGroup(*[
|
||||
VGroup(
|
||||
dice_table.cells[31 + i - 5 * k],
|
||||
dice_table.labels[31 + i - 5 * k],
|
||||
)
|
||||
for k in range(5 - i)
|
||||
]))
|
||||
|
||||
# self.play(
|
||||
# FadeIn(dice_unit_rect),
|
||||
# FadeIn(dice_table.rows)
|
||||
# )
|
||||
|
||||
# for (cell, label) in zip(dice_table.cells, dice_table.labels):
|
||||
# cell.add(label)
|
||||
|
||||
# self.play(
|
||||
# LaggedStartMap(FadeIn, dice_table_grouped_cells,
|
||||
# lag_ratio = lag_ratio, run_time = run_time)
|
||||
# )
|
||||
self.play(
|
||||
FadeIn(dice_table_grouped_cells),
|
||||
FadeIn(dice_unit_rect),
|
||||
FadeIn(dice_table.rows)
|
||||
)
|
||||
|
||||
self.wait(3)
|
||||
|
||||
|
||||
self.play(
|
||||
dice_table_grouped_cells.space_out_submobjects, {"factor" : 1.5},
|
||||
rate_func=there_and_back_with_pause,
|
||||
run_time=run_time
|
||||
)
|
||||
|
||||
dice_table.add(dice_unit_rect)
|
||||
dice_table_target = dice_table.deepcopy()
|
||||
dice_table_target.scale(0.5)
|
||||
dice_table_target.to_corner(UR, buff=LARGE_BUFF)
|
||||
dice_table_target.shift(0.4 * UP)
|
||||
|
||||
self.play(Transform(dice_table, dice_table_target))
|
||||
|
||||
self.play(
|
||||
FadeOut(dice_table.rows),
|
||||
FadeOut(dice_unit_rect),
|
||||
)
|
||||
|
||||
self.wait(3)
|
||||
|
||||
# TITLE
|
||||
|
||||
text = TextMobject("Probability distributions")
|
||||
text.to_edge(UP)
|
||||
text_rect = SurroundingRectangle(text, buff=MED_SMALL_BUFF)
|
||||
text_rect.match_color(text)
|
||||
|
||||
self.play(
|
||||
FadeIn(text),
|
||||
ShowCreation(text_rect)
|
||||
)
|
||||
|
||||
self.wait(3)
|
||||
|
||||
|
||||
# COIN FLIP
|
||||
|
||||
|
||||
brick_row = BrickRow(3, height = 2, width = 10)
|
||||
coin_flip_rect = VGroup(brick_row)
|
||||
|
||||
tallies = VGroup()
|
||||
for (i, brick) in enumerate(brick_row.rects):
|
||||
tally = TallyStack(3 - i, i)
|
||||
tally.move_to(brick)
|
||||
tallies.add(tally)
|
||||
coin_flip_rect.add(tallies)
|
||||
|
||||
coin_flip_rect.scale(0.65).shift(RIGHT)
|
||||
self.play(FadeIn(coin_flip_rect))
|
||||
|
||||
counts = [1, 3, 3, 1]
|
||||
braces = VGroup()
|
||||
labels = VGroup()
|
||||
for (rect, count) in zip(brick_row.rects, counts):
|
||||
label = TexMobject("{" + str(count) + "\\over 8}").scale(0.5)
|
||||
brace = Brace(rect, DOWN)
|
||||
label.next_to(brace, DOWN)
|
||||
braces.add(brace)
|
||||
labels.add(label)
|
||||
|
||||
self.play(
|
||||
FadeIn(braces),
|
||||
FadeIn(labels)
|
||||
)
|
||||
|
||||
coin_flip_rect.add(braces, labels)
|
||||
|
||||
|
||||
self.wait(6)
|
||||
|
||||
outcomes = brick_row.get_outcome_rects_for_level(3, with_labels = True,
|
||||
inset = True)
|
||||
outcomes.scale(0.65)
|
||||
outcomes.move_to(brick_row.get_center())
|
||||
outcome_braces = VGroup(*[
|
||||
Brace(outcome, DOWN) for outcome in outcomes
|
||||
])
|
||||
outcome_labels = VGroup(*[
|
||||
TexMobject("{1\over 8}").scale(0.5).next_to(brace, DOWN)
|
||||
for brace in outcome_braces
|
||||
])
|
||||
|
||||
self.play(
|
||||
FadeOut(tallies),
|
||||
FadeIn(outcomes),
|
||||
FadeOut(braces),
|
||||
FadeOut(labels),
|
||||
FadeIn(outcome_braces),
|
||||
FadeIn(outcome_labels)
|
||||
)
|
||||
|
||||
|
||||
self.wait(10)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.independence import *
|
||||
|
||||
from for_3b1b_videos.pi_class import PiCreatureClass
|
||||
|
||||
class QuizResult(PiCreatureScene):
|
||||
CONFIG = {
|
||||
"pi_creatures_start_on_screen" : False,
|
||||
"random_seed" : 0
|
||||
}
|
||||
def construct(self):
|
||||
|
||||
|
||||
def get_example_quiz():
|
||||
quiz = get_quiz(
|
||||
"Define ``Brachistochrone'' ",
|
||||
"Define ``Tautochrone'' ",
|
||||
"Define ``Cycloid'' ",
|
||||
)
|
||||
rect = SurroundingRectangle(quiz, buff = 0)
|
||||
rect.set_fill(color = BLACK, opacity = 1)
|
||||
rect.set_stroke(width = 0)
|
||||
quiz.add_to_back(rect)
|
||||
return quiz
|
||||
|
||||
|
||||
highlight_color = WHITE
|
||||
|
||||
nb_students_x = 5
|
||||
nb_students_y = 3
|
||||
spacing_students_x = 2.0
|
||||
spacing_students_y = 2.2
|
||||
|
||||
all_students = PiCreatureClass(
|
||||
width = nb_students_x, height = nb_students_y)# VGroup()
|
||||
student_points = []
|
||||
grades = []
|
||||
grades_count = []
|
||||
hist_y_values = np.zeros(4)
|
||||
for i in range(nb_students_x):
|
||||
for j in range(nb_students_y):
|
||||
x = i * spacing_students_x
|
||||
y = j * spacing_students_y
|
||||
#pi = PiCreature().scale(0.3)
|
||||
#pi.move_to([x,y,0])
|
||||
#all_students.add(pi)
|
||||
all_students[i*nb_students_y + j].move_to([x,y,0])
|
||||
q1 = np.random.choice([True, False])
|
||||
q2 = np.random.choice([True, False])
|
||||
q3 = np.random.choice([True, False])
|
||||
student_points.append([q1, q2, q3])
|
||||
grade = q1*1+q2*1+q3*1
|
||||
grades.append(grade)
|
||||
hist_y_values[grade] += 1
|
||||
# How many times has this grade already occured?
|
||||
grade_count = grades.count(grade)
|
||||
grades_count.append(grade_count)
|
||||
|
||||
|
||||
all_students.move_to(ORIGIN)
|
||||
self.pi_creatures = all_students
|
||||
self.play(FadeIn(all_students))
|
||||
|
||||
all_quizzes = VGroup()
|
||||
|
||||
quiz = get_example_quiz().scale(0.2)
|
||||
for pi in all_students:
|
||||
quiz_copy = quiz.copy()
|
||||
quiz_copy.next_to(pi, UP)
|
||||
all_quizzes.add(quiz_copy)
|
||||
|
||||
master_quiz = get_example_quiz()
|
||||
self.play(Write(master_quiz), run_time = 2)
|
||||
self.wait()
|
||||
self.play(ReplacementTransform(
|
||||
VGroup(master_quiz), all_quizzes,
|
||||
run_time=2,
|
||||
lag_ratio=0.5
|
||||
))
|
||||
self.wait(2)
|
||||
|
||||
grades_mob = VGroup()
|
||||
for (pi, quiz, grade) in zip(all_students, all_quizzes, grades):
|
||||
grade_mob = TexMobject(str(grade) + "/3")
|
||||
grade_mob.move_to(quiz)
|
||||
grades_mob.add(grade_mob)
|
||||
|
||||
self.remove(master_quiz)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(all_quizzes),
|
||||
FadeIn(grades_mob)
|
||||
)
|
||||
|
||||
# self.play(
|
||||
# all_students[2:].fade, 0.8,
|
||||
# grades_mob[2:].fade, 0.8
|
||||
# )
|
||||
|
||||
students_points_mob = VGroup()
|
||||
for (pi, quiz, points) in zip(all_students, all_quizzes, student_points):
|
||||
slot = get_slot_group(points, include_qs = False)
|
||||
slot.scale(0.5).move_to(quiz)
|
||||
students_points_mob.add(slot)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
#all_students.fade, 0,
|
||||
FadeOut(grades_mob),
|
||||
FadeIn(students_points_mob)
|
||||
)
|
||||
|
||||
all_students.save_state()
|
||||
students_points_mob.save_state()
|
||||
self.wait()
|
||||
randy = all_students[0]
|
||||
morty = all_students[nb_students_y]
|
||||
all_other_students = VGroup(*all_students)
|
||||
all_other_students.remove(randy, morty)
|
||||
randy_points = students_points_mob[0]
|
||||
morty_points = students_points_mob[nb_students_y]
|
||||
all_other_points = VGroup(*students_points_mob)
|
||||
all_other_points.remove(randy_points, morty_points)
|
||||
self.play(
|
||||
all_other_students.fade, 0.8,
|
||||
all_other_points.fade, 0.8,
|
||||
)
|
||||
self.wait()
|
||||
scale = 1.5
|
||||
self.play(randy_points.scale,scale)
|
||||
self.play(randy_points.scale,1.0/scale, morty_points.scale,scale)
|
||||
self.play(morty_points.scale,1.0/scale)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
all_students.restore,
|
||||
students_points_mob.restore,
|
||||
)
|
||||
|
||||
self.wait()
|
||||
anims = []
|
||||
for points in students_points_mob:
|
||||
anims.append(points.scale)
|
||||
anims.append(scale)
|
||||
self.play(*anims)
|
||||
|
||||
self.wait()
|
||||
anims = []
|
||||
for points in students_points_mob:
|
||||
anims.append(points.scale)
|
||||
anims.append(1.0/scale)
|
||||
self.play(*anims)
|
||||
|
||||
anims = []
|
||||
anchor_point = 3 * DOWN + 1 * LEFT
|
||||
for (pi, grade, grades_count) in zip(all_students, grades, grades_count):
|
||||
anims.append(pi.move_to)
|
||||
anims.append(anchor_point + grade * RIGHT + grades_count * UP)
|
||||
anims.append(FadeOut(students_points_mob))
|
||||
|
||||
self.wait()
|
||||
self.play(*anims)
|
||||
|
||||
grade_labels = VGroup()
|
||||
for i in range(4):
|
||||
grade_label = Integer(i, color = highlight_color)
|
||||
grade_label.move_to(i * RIGHT)
|
||||
grade_labels.add(grade_label)
|
||||
grade_labels.next_to(all_students, DOWN)
|
||||
out_of_label = TextMobject("out of 3", color = highlight_color)
|
||||
out_of_label.next_to(grade_labels, RIGHT, buff = MED_LARGE_BUFF)
|
||||
grade_labels.add(out_of_label)
|
||||
self.wait()
|
||||
self.play(Write(grade_labels))
|
||||
|
||||
grade_hist = Histogram(
|
||||
np.ones(4),
|
||||
hist_y_values,
|
||||
mode = "widths",
|
||||
x_labels = "none",
|
||||
y_label_position = "center",
|
||||
bar_stroke_width = 0,
|
||||
outline_stroke_width = 5
|
||||
)
|
||||
grade_hist.move_to(all_students)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeIn(grade_hist),
|
||||
FadeOut(all_students)
|
||||
)
|
||||
|
||||
|
||||
nb_students_label = TextMobject("\# of students", color = highlight_color)
|
||||
nb_students_label.move_to(5 * RIGHT + 1 * UP)
|
||||
arrows = VGroup(*[
|
||||
Arrow(nb_students_label.get_left(), grade_hist.bars[i].get_center(),
|
||||
color = highlight_color)
|
||||
for i in range(4)
|
||||
])
|
||||
self.wait()
|
||||
self.play(Write(nb_students_label), LaggedStartMap(GrowArrow,arrows))
|
||||
|
||||
percentage_label = TextMobject("\% of students", color = highlight_color)
|
||||
percentage_label.move_to(nb_students_label)
|
||||
percentages = hist_y_values / (nb_students_x * nb_students_y) * 100
|
||||
anims = []
|
||||
for (label, percentage) in zip(grade_hist.y_labels_group, percentages):
|
||||
new_label = DecimalNumber(percentage,
|
||||
num_decimal_places = 1,
|
||||
unit = "\%",
|
||||
color = highlight_color
|
||||
)
|
||||
new_label.scale(0.7)
|
||||
new_label.move_to(label)
|
||||
anims.append(Transform(label, new_label))
|
||||
anims.append(ReplacementTransform(nb_students_label, percentage_label))
|
||||
self.wait()
|
||||
self.play(*anims)
|
||||
|
||||
self.remove(all_quizzes)
|
||||
# put small copy of class in corner
|
||||
for (i,pi) in enumerate(all_students):
|
||||
x = i % 5
|
||||
y = i / 5
|
||||
pi.move_to(x * RIGHT + y * UP)
|
||||
all_students.scale(0.8)
|
||||
all_students.to_corner(DOWN + LEFT)
|
||||
self.wait()
|
||||
self.play(FadeIn(all_students))
|
||||
|
||||
prob_label = TextMobject("probability", color = highlight_color)
|
||||
prob_label.move_to(percentage_label)
|
||||
self.wait()
|
||||
self.play(
|
||||
all_students[8].set_color, MAROON_E,
|
||||
#all_students[:8].fade, 0.6,
|
||||
#all_students[9:].fade, 0.6,
|
||||
ReplacementTransform(percentage_label, prob_label)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(prob_label),
|
||||
FadeOut(arrows)
|
||||
)
|
||||
|
||||
flash_hist = FlashThroughHistogram(
|
||||
grade_hist,
|
||||
direction = "vertical",
|
||||
mode = "random",
|
||||
cell_opacity = 0.5,
|
||||
run_time = 5,
|
||||
rate_func = linear
|
||||
)
|
||||
|
||||
flash_class = FlashThroughClass(
|
||||
all_students,
|
||||
mode = "random",
|
||||
highlight_color = MAROON_E,
|
||||
run_time = 5,
|
||||
rate_func = linear
|
||||
)
|
||||
|
||||
self.wait()
|
||||
for i in range(3):
|
||||
self.play(flash_hist, flash_class)
|
||||
self.remove(flash_hist.prototype_cell)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class ProbabilityRect(VMobject):
|
||||
CONFIG = {
|
||||
"unit_width" : 2,
|
||||
"unit_height" : 2,
|
||||
"alignment" : LEFT,
|
||||
"color": YELLOW,
|
||||
"opacity": 1.0,
|
||||
"num_decimal_places": 2,
|
||||
"use_percent" : False
|
||||
}
|
||||
|
||||
def __init__(self, p0, **kwargs):
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
self.unit_rect = Rectangle(
|
||||
width = self.unit_width,
|
||||
height = self.unit_height,
|
||||
stroke_color = self.color
|
||||
)
|
||||
self.p = p0
|
||||
self.prob_rect = self.create_prob_rect(p0)
|
||||
self.prob_label = self.create_prob_label(p0)
|
||||
|
||||
self.add(self.unit_rect, self.prob_rect, self.prob_label)
|
||||
|
||||
|
||||
def create_prob_rect(self, p):
|
||||
|
||||
prob_width, prob_height = self.unit_width, self.unit_height
|
||||
|
||||
if self.alignment in [LEFT, RIGHT]:
|
||||
prob_width *= p
|
||||
elif self.alignment in [UP, DOWN]:
|
||||
prob_height *= p
|
||||
else:
|
||||
raise Exception("Aligment must be LEFT, RIGHT, UP or DOWN")
|
||||
|
||||
prob_rect = Rectangle(
|
||||
width = prob_width,
|
||||
height = prob_height,
|
||||
fill_color = self.color,
|
||||
fill_opacity = self.opacity,
|
||||
stroke_color = self.color
|
||||
)
|
||||
|
||||
prob_rect.align_to(self.unit_rect, direction = self.alignment)
|
||||
return prob_rect
|
||||
|
||||
|
||||
def create_prob_label(self, p):
|
||||
|
||||
if self.use_percent:
|
||||
prob_label = DecimalNumber(
|
||||
p * 100,
|
||||
color = BLACK,
|
||||
num_decimal_places = self.num_decimal_places,
|
||||
unit = "\%"
|
||||
)
|
||||
else:
|
||||
prob_label = DecimalNumber(
|
||||
p,
|
||||
color = BLACK,
|
||||
num_decimal_places = self.num_decimal_places,
|
||||
)
|
||||
|
||||
prob_label.move_to(self.prob_rect)
|
||||
|
||||
return prob_label
|
||||
|
||||
|
||||
class ChangeProbability(Animation):
|
||||
|
||||
def __init__(self, prob_mob, p1, **kwargs):
|
||||
|
||||
if not isinstance(prob_mob, ProbabilityRect):
|
||||
raise Exception("ChangeProportion's mobject must be a ProbabilityRect")
|
||||
|
||||
self.p1 = p1
|
||||
self.p0 = prob_mob.p
|
||||
Animation.__init__(self, prob_mob, **kwargs)
|
||||
|
||||
|
||||
def interpolate_mobject(self, alpha):
|
||||
|
||||
p = (1 - alpha) * self.p0 + alpha * self.p1
|
||||
self.mobject.remove(self.mobject.prob_rect, self.mobject.prob_label)
|
||||
self.mobject.prob_rect = self.mobject.create_prob_rect(p)
|
||||
self.mobject.prob_label = self.mobject.create_prob_label(p)
|
||||
self.mobject.add(self.mobject.prob_rect, self.mobject.prob_label)
|
||||
|
||||
|
||||
def clean_up_from_scene(self, scene=None):
|
||||
self.mobject.p = self.p1
|
||||
super(ChangeProbability, self).clean_up_from_scene(scene = scene)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ShowProbAsProportion(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
p0 = 0.3
|
||||
p1 = 1
|
||||
p2 = 0.18
|
||||
p3 = 0.64
|
||||
|
||||
prob_mob = ProbabilityRect(p0,
|
||||
unit_width = 4,
|
||||
unit_height = 2,
|
||||
use_percent = False,
|
||||
num_decimal_places = 2
|
||||
)
|
||||
|
||||
self.add(prob_mob)
|
||||
self.wait()
|
||||
self.play(
|
||||
ChangeProbability(prob_mob, p1,
|
||||
run_time = 3)
|
||||
)
|
||||
self.wait(0.5)
|
||||
self.play(
|
||||
ChangeProbability(prob_mob, p2,
|
||||
run_time = 3)
|
||||
)
|
||||
self.wait(0.5)
|
||||
self.play(
|
||||
ChangeProbability(prob_mob, p3,
|
||||
run_time = 3)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class ShowUncertaintyDarts(Scene):
|
||||
|
||||
|
||||
def throw_darts(self, n, run_time = 1):
|
||||
|
||||
points = np.random.normal(
|
||||
loc = self.dartboard.get_center(),
|
||||
scale = 0.6 * np.ones(3),
|
||||
size = (n,3)
|
||||
)
|
||||
points[:,2] = 0
|
||||
dots = VGroup()
|
||||
for point in points:
|
||||
dot = Dot(point, radius = 0.04, fill_opacity = 0.7)
|
||||
dots.add(dot)
|
||||
self.add(dot)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(FadeIn, dots, lag_ratio = 0.01, run_time = run_time)
|
||||
)
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.dartboard = ImageMobject("dartboard").scale(2)
|
||||
dartboard_circle = Circle(
|
||||
radius = self.dartboard.get_width() / 2,
|
||||
fill_color = BLACK,
|
||||
fill_opacity = 0.5,
|
||||
stroke_color = WHITE,
|
||||
stroke_width = 5
|
||||
)
|
||||
self.dartboard.add(dartboard_circle)
|
||||
|
||||
self.add(self.dartboard)
|
||||
|
||||
self.throw_darts(5,5)
|
||||
self.throw_darts(20,5)
|
||||
self.throw_darts(100,5)
|
||||
self.throw_darts(1000,5)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class ShowUncertaintyDice(Scene):
|
||||
|
||||
def throw_a_die(self, run_time = 0.3):
|
||||
|
||||
eye = np.random.randint(1,7)
|
||||
face = self.row_of_dice.submobjects[eye - 1]
|
||||
|
||||
self.play(
|
||||
ApplyMethod(face.submobjects[0].set_fill, {"opacity": 1},
|
||||
rate_func = there_and_back,
|
||||
run_time = run_time,
|
||||
),
|
||||
)
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.row_of_dice = RowOfDice(direction = DOWN).scale(0.5)
|
||||
self.add(self.row_of_dice)
|
||||
|
||||
for i in range(5):
|
||||
self.throw_a_die()
|
||||
self.wait(1)
|
||||
|
||||
for i in range(10):
|
||||
self.throw_a_die()
|
||||
self.wait(0.3)
|
||||
|
||||
for i in range(100):
|
||||
self.throw_a_die(0.05)
|
||||
self.wait(0.0)
|
||||
|
||||
|
||||
|
||||
class IdealizedDieHistogram(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.probs = 1.0/6 * np.ones(6)
|
||||
x_scale = 1.3
|
||||
|
||||
y_labels = ["${1\over 6}$"] * 6
|
||||
|
||||
hist = Histogram(np.ones(6), self.probs,
|
||||
mode = "widths",
|
||||
x_labels = "none",
|
||||
y_labels = y_labels,
|
||||
y_label_position = "center",
|
||||
y_scale = 20,
|
||||
x_scale = x_scale,
|
||||
)
|
||||
hist.rotate(-TAU/4)
|
||||
|
||||
for label in hist.y_labels_group:
|
||||
label.rotate(TAU/4)
|
||||
hist.remove(hist.y_labels_group)
|
||||
|
||||
|
||||
self.play(FadeIn(hist))
|
||||
self.play(LaggedStartMap(FadeIn, hist.y_labels_group))
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
|
||||
class RandyIsSickOrNot(Scene):
|
||||
|
||||
|
||||
def construct(self):
|
||||
title = TextMobject("1 in 200")
|
||||
title.to_edge(UP)
|
||||
|
||||
|
||||
randy = SicklyPiCreature()
|
||||
randy.set_height(3)
|
||||
randy.move_to(2*LEFT)
|
||||
randy.change_mode("plain")
|
||||
randy.set_color(BLUE)
|
||||
randy.save_state()
|
||||
|
||||
self.add(randy)
|
||||
|
||||
p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%").scale(1.7)
|
||||
p_sick.set_color_by_tex("sick", SICKLY_GREEN)
|
||||
p_sick.next_to(randy, UP, buff = LARGE_BUFF)
|
||||
self.add(p_sick)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.wait(2)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_sick)
|
||||
)
|
||||
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
|
||||
self.play(randy.get_better)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.wait(0.5)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_sick)
|
||||
)
|
||||
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.get_better)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
|
||||
class OneIn200HasDisease(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("1 in 200")
|
||||
title.to_edge(UP)
|
||||
creature = PiCreature()
|
||||
|
||||
all_creatures = VGroup(*[
|
||||
VGroup(*[
|
||||
creature.copy()
|
||||
for y in range(20)
|
||||
]).arrange(DOWN, SMALL_BUFF)
|
||||
for x in range(10)
|
||||
]).arrange(RIGHT, SMALL_BUFF)
|
||||
all_creatures.set_height(FRAME_HEIGHT * 0.8)
|
||||
all_creatures.next_to(title, DOWN)
|
||||
randy = all_creatures[0][0]
|
||||
all_creatures[0].remove(randy)
|
||||
randy.change_mode("sick")
|
||||
randy.set_color(SICKLY_GREEN)
|
||||
randy.save_state()
|
||||
randy.set_height(3)
|
||||
randy.center()
|
||||
randy.change_mode("plain")
|
||||
randy.set_color(BLUE)
|
||||
|
||||
self.add(randy)
|
||||
|
||||
#p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%")
|
||||
#p_sick.set_color_by_tex("sick", SICKLY_GREEN)
|
||||
#p_sick.next_to(randy, RIGHT+UP)
|
||||
#self.add(p_sick)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
randy.change_mode, "sick",
|
||||
randy.set_color, SICKLY_GREEN
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.restore)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(title),
|
||||
LaggedStartMap(FadeIn, all_creatures, run_time = 3)
|
||||
)
|
||||
self.wait()
|
||||
@@ -1,29 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class StackingCoins(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
h = t = 0
|
||||
heads_stack = HeadsStack(size = h)
|
||||
heads_stack.next_to(0.5*LEFT + 3*DOWN, UP)
|
||||
tails_stack = TailsStack(size = t)
|
||||
tails_stack.next_to(0.5*RIGHT + 3*DOWN, UP)
|
||||
self.add(heads_stack, tails_stack)
|
||||
|
||||
for i in range(120):
|
||||
flip = np.random.choice(["H", "T"])
|
||||
if flip == "H":
|
||||
h += 1
|
||||
new_heads_stack = HeadsStack(size = h)
|
||||
new_heads_stack.next_to(0.5*LEFT + 3*DOWN, UP)
|
||||
self.play(Transform(heads_stack, new_heads_stack,
|
||||
run_time = 0.2))
|
||||
elif flip == "T":
|
||||
t += 1
|
||||
new_tails_stack = TailsStack(size = t)
|
||||
new_tails_stack.next_to(0.5*RIGHT + 3*DOWN, UP)
|
||||
self.play(Transform(tails_stack, new_tails_stack,
|
||||
run_time = 0.2))
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class RandyThinksAboutCoin(PiCreatureScene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = self.get_primary_pi_creature()
|
||||
randy.center()
|
||||
self.add(randy)
|
||||
self.wait()
|
||||
h_or_t = BinaryOption(UprightHeads().scale(3), UprightTails().scale(3),
|
||||
text_scale = 1.5)
|
||||
self.think(h_or_t, direction = LEFT)
|
||||
|
||||
v = 0.3
|
||||
self.play(
|
||||
h_or_t[0].shift,v*UP,
|
||||
h_or_t[2].shift,v*DOWN,
|
||||
)
|
||||
self.play(
|
||||
h_or_t[0].shift,2*v*DOWN,
|
||||
h_or_t[2].shift,2*v*UP,
|
||||
)
|
||||
self.play(
|
||||
h_or_t[0].shift,v*UP,
|
||||
h_or_t[2].shift,v*DOWN,
|
||||
)
|
||||
|
||||
self.wait()
|
||||
@@ -1,132 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.combinations import *
|
||||
from active_projects.eop.independence import *
|
||||
|
||||
import itertools as it
|
||||
|
||||
class RandyFlipsAndStacks(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E)
|
||||
randy.scale(0.5).to_edge(LEFT + DOWN)
|
||||
|
||||
heads = tails = 0
|
||||
tally = TallyStack(heads, tails, anchor = ORIGIN)
|
||||
|
||||
nb_flips = 10
|
||||
|
||||
flips = np.random.randint(2, size = nb_flips)
|
||||
|
||||
for i in range(nb_flips):
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
self.wait(0.5)
|
||||
|
||||
flip = flips[i]
|
||||
if flip == 0:
|
||||
heads += 1
|
||||
elif flip == 1:
|
||||
tails += 1
|
||||
else:
|
||||
raise Exception("That side does not exist on this coin")
|
||||
|
||||
new_tally = TallyStack(heads, tails, anchor = ORIGIN)
|
||||
|
||||
if tally.nb_heads == 0 and new_tally.nb_heads == 1:
|
||||
self.play(FadeIn(new_tally.heads_stack))
|
||||
elif tally.nb_tails == 0 and new_tally.nb_tails == 1:
|
||||
self.play(FadeIn(new_tally.tails_stack))
|
||||
else:
|
||||
self.play(Transform(tally, new_tally))
|
||||
|
||||
tally = new_tally
|
||||
|
||||
|
||||
|
||||
class TwoDiceTableScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
table = TwoDiceTable(cell_size = 1)
|
||||
|
||||
table.center()
|
||||
self.add(table)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class VisualCovariance(Scene):
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
size = 4
|
||||
square = Square(side_length = size)
|
||||
n_points = 30
|
||||
cloud = VGroup(*[
|
||||
Dot((x + 0.8*y) * RIGHT + y * UP).set_fill(WHITE, 1)
|
||||
for x, y in zip(
|
||||
np.random.normal(0, 1, n_points),
|
||||
np.random.normal(0, 1, n_points)
|
||||
)
|
||||
])
|
||||
self.add_foreground_mobject(cloud)
|
||||
|
||||
x_axis = Vector(8*RIGHT, color = WHITE).move_to(2.5*DOWN)
|
||||
y_axis = Vector(5*UP, color = WHITE).move_to(4*LEFT)
|
||||
|
||||
self.add(x_axis, y_axis)
|
||||
|
||||
|
||||
random_pairs = [ (p1, p2) for (p1, p2) in
|
||||
it.combinations(cloud, 2)
|
||||
]
|
||||
np.random.shuffle(random_pairs)
|
||||
|
||||
|
||||
|
||||
for (p1, p2) in random_pairs:
|
||||
c1, c2 = p1.get_center(), p2.get_center()
|
||||
x1, y1, x2, y2 = c1[0], c1[1], c2[0], c2[1]
|
||||
if x1 >= x2:
|
||||
continue
|
||||
if y2 > y1:
|
||||
# make a red rect
|
||||
color = RED
|
||||
opacity = 0.1
|
||||
|
||||
elif y2 < y1:
|
||||
# make a blue rect
|
||||
color = BLUE
|
||||
opacity = 0.2
|
||||
|
||||
rect = Rectangle(width = x2 - x1, height = abs(y2 - y1))
|
||||
rect.set_fill(color = color, opacity = opacity)
|
||||
rect.set_stroke(width = 0)
|
||||
rect.move_to((c1+c2)/2)
|
||||
|
||||
self.play(FadeIn(rect), run_time = 0.05)
|
||||
|
||||
|
||||
|
||||
|
||||
class BinaryChoices(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
example1 = BinaryOption(UprightHeads(), UprightTails())
|
||||
example2 = BinaryOption(Male(), Female())
|
||||
example3 = BinaryOption(Checkmark(), Xmark())
|
||||
|
||||
example2.next_to(example1, DOWN, buff = MED_LARGE_BUFF)
|
||||
example3.next_to(example2, DOWN, buff = MED_LARGE_BUFF)
|
||||
|
||||
all = VGroup(example1, example2, example3)
|
||||
all = all.scale(2)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(FadeIn, all)
|
||||
)
|
||||
@@ -1,43 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WhatDoesItReallyMean(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
student_q = TextMobject(
|
||||
"What does", "``probability''\\\\",
|
||||
"\\emph{actually}", "mean?"
|
||||
)
|
||||
student_q.set_color_by_tex("probability", YELLOW)
|
||||
self.student_says(student_q, target_mode="sassy")
|
||||
self.wait()
|
||||
self.play(
|
||||
self.students[1].change_mode, "confused"
|
||||
)
|
||||
self.wait(2)
|
||||
student_bubble = self.students[1].bubble
|
||||
self.students[1].bubble = None
|
||||
student_bubble.add(student_bubble.content)
|
||||
self.play(
|
||||
student_bubble.scale, 0.5,
|
||||
student_bubble.to_corner, UL,
|
||||
)
|
||||
self.teacher_says(
|
||||
"Don't worry -- philosophy\\\\ can come later!",
|
||||
added_anims=[self.get_student_changes(*3 * ["happy"])],
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(RemovePiCreatureBubble(self.teacher))
|
||||
self.play(*[
|
||||
ApplyMethod(pi.look_at, ORIGIN) for pi in self.get_pi_creatures()
|
||||
])
|
||||
self.change_all_student_modes("pondering", look_at_arg=UP)
|
||||
self.wait(3)
|
||||
self.change_student_modes("confused", look_at_arg=UP)
|
||||
self.wait(3)
|
||||
@@ -1,103 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
def print_permutation(index_list):
|
||||
|
||||
|
||||
n = max(max(index_list), len(index_list))
|
||||
for i in range(0,n):
|
||||
if index_list[i] > n - i:
|
||||
raise Exception("Impossible indices!")
|
||||
|
||||
#print "given index list:", index_list
|
||||
perm_list = n * ["_"]
|
||||
alphabet = ["A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "L",
|
||||
"M", "N", "O", "P", "Q", "R",
|
||||
"S", "T", "U", "V", "W", "X",
|
||||
"Y", "Z"]
|
||||
free_indices = list(range(n))
|
||||
free_indices_p1 = list(range(1,n + 1))
|
||||
#print perm_list
|
||||
for i in range(n):
|
||||
findex = index_list[i] - 1
|
||||
#print "place next letter at", findex + 1, "th free place"
|
||||
tindex = free_indices[findex]
|
||||
#print "so at position", tindex + 1
|
||||
perm_list[tindex] = alphabet[i]
|
||||
free_indices.remove(tindex)
|
||||
free_indices_p1.remove(tindex + 1)
|
||||
#print "remaining free places:", free_indices_p1
|
||||
#print perm_list
|
||||
|
||||
return "".join(perm_list)
|
||||
|
||||
|
||||
class PermutationGrid(Scene):
|
||||
|
||||
def text_box(self, str):
|
||||
box = TextMobject(str).scale(0.3)
|
||||
box.add(SurroundingRectangle(box, stroke_color = DARK_GREY))
|
||||
return box
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
|
||||
N = 5
|
||||
|
||||
index_list = []
|
||||
perm5_box = VGroup()
|
||||
for i in range(1, N + 1):
|
||||
index_list.append(i)
|
||||
perm4_box = VGroup()
|
||||
for j in range(1, N):
|
||||
index_list.append(j)
|
||||
perm3_box = VGroup()
|
||||
for k in range(1, N - 1):
|
||||
index_list.append(k)
|
||||
perm2_box = VGroup()
|
||||
for l in range(1, N - 2):
|
||||
index_list.append(l)
|
||||
index_list.append(1)
|
||||
perm_box = self.text_box(print_permutation(index_list))
|
||||
if l > 1:
|
||||
perm_box.next_to(perm2_box[-1], DOWN, buff = 0)
|
||||
perm2_box.add(perm_box)
|
||||
index_list.pop()
|
||||
index_list.pop()
|
||||
if k > 1:
|
||||
perm2_box.next_to(perm3_box[-1], RIGHT, buff = 0.08)
|
||||
perm3_box.add(perm2_box)
|
||||
index_list.pop()
|
||||
perm3_box.add(SurroundingRectangle(perm3_box, buff = 0.12, stroke_color = LIGHT_GRAY))
|
||||
if j > 1:
|
||||
perm3_box.next_to(perm4_box[-1], DOWN, buff = 0)
|
||||
perm4_box.add(perm3_box)
|
||||
index_list.pop()
|
||||
if i > 1:
|
||||
perm4_box.next_to(perm5_box[-1], RIGHT, buff = 0.16)
|
||||
perm5_box.add(perm4_box)
|
||||
index_list.pop()
|
||||
|
||||
perm5_box.move_to(ORIGIN)
|
||||
self.add(perm5_box)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,347 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
from once_useful_constructs.combinatorics import *
|
||||
|
||||
nb_levels = 5
|
||||
|
||||
dev_x_step = 2
|
||||
dev_y_step = 5
|
||||
|
||||
GRADE_COLOR_1 = RED
|
||||
GRADE_COLOR_2 = BLUE
|
||||
|
||||
|
||||
|
||||
def graded_square(n,k):
|
||||
return Square(
|
||||
side_length = 1,
|
||||
fill_color = graded_color(n,k),
|
||||
fill_opacity = 1,
|
||||
stroke_width = 1
|
||||
)
|
||||
|
||||
def graded_binomial(n,k):
|
||||
return Integer(
|
||||
choose(n,k),
|
||||
color = graded_color(n,k)
|
||||
)
|
||||
|
||||
def split_square(n,k):
|
||||
width = 1
|
||||
height = 1
|
||||
|
||||
proportion = float(choose(n,k)) / 2**n
|
||||
|
||||
lower_height = proportion * height
|
||||
upper_height = (1 - proportion) * height
|
||||
lower_rect = Rectangle(
|
||||
width = width,
|
||||
height = lower_height,
|
||||
fill_color = RED,
|
||||
fill_opacity = 1.0,
|
||||
stroke_color = WHITE,
|
||||
stroke_width = 3
|
||||
)
|
||||
upper_rect = Rectangle(
|
||||
width = width,
|
||||
height = upper_height,
|
||||
fill_color = BLUE,
|
||||
fill_opacity = 1.0,
|
||||
stroke_color = WHITE,
|
||||
stroke_width = 3
|
||||
)
|
||||
upper_rect.next_to(lower_rect,UP,buff = 0)
|
||||
square = VGroup(lower_rect, upper_rect).move_to(ORIGIN)
|
||||
return square
|
||||
|
||||
|
||||
class BuildNewPascalRow(Transform):
|
||||
|
||||
def __init__(self,mobject, duplicate_row = None, **kwargs):
|
||||
if mobject.__class__ != GeneralizedPascalsTriangle and mobject.__class__ != PascalsTriangle:
|
||||
raise("Transform BuildNewPascalRow only works on members of (Generalized)PascalsTriangle!")
|
||||
|
||||
n = mobject.nrows - 1
|
||||
lowest_row_copy1 = mobject.get_lowest_row()
|
||||
lowest_row_copy2 = duplicate_row
|
||||
|
||||
start_mob = VGroup(lowest_row_copy1, lowest_row_copy2)
|
||||
|
||||
new_pt = mobject.copy()
|
||||
new_pt.nrows += 1
|
||||
new_pt.generate_points()
|
||||
# align with original (copy got centered on screen)
|
||||
c1 = new_pt.coords_to_mobs[0][0].get_center()
|
||||
c2 = mobject.coords_to_mobs[0][0].get_center()
|
||||
print(c1, c2)
|
||||
v = c2 - c1
|
||||
new_pt.shift(v)
|
||||
|
||||
new_row_left_copy = VGroup(*[
|
||||
new_pt.coords_to_mobs[n+1][k]
|
||||
for k in range(0,n+1)
|
||||
])
|
||||
|
||||
new_row_right_copy = VGroup(*[
|
||||
new_pt.coords_to_mobs[n+1][k]
|
||||
for k in range(1,n+2)
|
||||
]).copy()
|
||||
|
||||
target_mob = VGroup(new_row_left_copy, new_row_right_copy)
|
||||
|
||||
Transform.__init__(self, start_mob, target_mob, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SimplePascal(Scene):
|
||||
|
||||
def build_new_pascal_row(self,old_pt):
|
||||
|
||||
lowest_row_copy = old_pt.get_lowest_row().copy()
|
||||
self.add(lowest_row_copy)
|
||||
|
||||
n = old_pt.nrows - 1
|
||||
lowest_row_copy1 = old_pt.get_lowest_row()
|
||||
lowest_row_copy2 = lowest_row_copy1.copy()
|
||||
|
||||
|
||||
start_mob = VGroup(lowest_row_copy1, lowest_row_copy2)
|
||||
self.add(start_mob)
|
||||
|
||||
new_pt = old_pt.copy()
|
||||
cell_height = old_pt.height / old_pt.nrows
|
||||
cell_width = old_pt.width / old_pt.nrows
|
||||
new_pt.nrows += 1
|
||||
new_pt.height = new_pt.nrows * cell_height
|
||||
new_pt.width = new_pt.nrows * cell_width
|
||||
|
||||
new_pt.generate_points()
|
||||
# align with original (copy got centered on screen)
|
||||
c1 = new_pt.coords_to_mobs[0][0].get_center()
|
||||
c2 = old_pt.coords_to_mobs[0][0].get_center()
|
||||
v = c2 - c1
|
||||
new_pt.shift(v)
|
||||
|
||||
new_row_left_copy = VGroup(*[
|
||||
new_pt.coords_to_mobs[n+1][k]
|
||||
for k in range(0,n+1)
|
||||
])
|
||||
|
||||
new_row_right_copy = VGroup(*[
|
||||
new_pt.coords_to_mobs[n+1][k]
|
||||
for k in range(1,n+2)
|
||||
]).copy()
|
||||
|
||||
target_mob = VGroup(new_row_left_copy, new_row_right_copy)
|
||||
self.play(Transform(start_mob, target_mob))
|
||||
|
||||
return new_pt
|
||||
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
cell_height = 1
|
||||
cell_width = 1
|
||||
nrows = 1
|
||||
pt = GeneralizedPascalsTriangle(
|
||||
nrows = nrows,
|
||||
height = nrows * cell_height,
|
||||
width = nrows * cell_width,
|
||||
submob_class = graded_square,
|
||||
portion_to_fill = 0.9
|
||||
)
|
||||
pt.shift(3 * UP)
|
||||
self.add(pt)
|
||||
lowest_row_copy = pt.get_lowest_row().copy()
|
||||
self.add(lowest_row_copy)
|
||||
#self.play(BuildNewPascalRow(pt, duplicate_row = lowest_row_copy))
|
||||
for i in range(7):
|
||||
pt = self.build_new_pascal_row(pt)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class PascalNetScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
unit_width = 0.25
|
||||
top_height = 4.0
|
||||
level_height = 2.0 * top_height / nb_levels
|
||||
|
||||
start_points = np.array([top_height * UP])
|
||||
|
||||
dev_start = start_points[0]
|
||||
|
||||
j = 0
|
||||
|
||||
for n in range(nb_levels):
|
||||
|
||||
half_width = 0.5 * (n + 0.5) * unit_width
|
||||
|
||||
stop_points_left = start_points.copy()
|
||||
stop_points_left[:,0] -= 0.5 * unit_width
|
||||
stop_points_left[:,1] -= level_height
|
||||
|
||||
stop_points_right = start_points.copy()
|
||||
stop_points_right[:,0] += 0.5 * unit_width
|
||||
stop_points_right[:,1] -= level_height
|
||||
|
||||
for (p,q) in zip(start_points,stop_points_left):
|
||||
alpha = np.abs((p[0]+q[0])/2) / half_width
|
||||
color = rainbow_color(alpha)
|
||||
line = Line(p,q, stroke_color = color)
|
||||
self.add(line)
|
||||
|
||||
for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)):
|
||||
alpha = np.abs((p[0]+q[0])/2) / half_width
|
||||
color = rainbow_color(alpha)
|
||||
line = Line(p,q, stroke_color = color)
|
||||
self.add(line)
|
||||
|
||||
if (n + 1) % dev_y_step == 0 and n != 1:
|
||||
j += dev_x_step
|
||||
dev_stop = stop_points_left[j]
|
||||
line = Line(dev_start,dev_stop,stroke_color = WHITE)
|
||||
self.add(line)
|
||||
dot = Dot(dev_stop, fill_color = WHITE)
|
||||
self.add_foreground_mobject(dot)
|
||||
dev_start = dev_stop
|
||||
|
||||
start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0)
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
class RescaledPascalNetScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
half_width = 3.0
|
||||
top_height = 4.0
|
||||
level_height = 2.0 * top_height / nb_levels
|
||||
|
||||
start_points = np.array([top_height * UP])
|
||||
left_edge = top_height * UP + half_width * LEFT
|
||||
right_edge = top_height * UP + half_width * RIGHT
|
||||
|
||||
dev_start = start_points[0]
|
||||
|
||||
j = 0
|
||||
|
||||
for n in range(nb_levels):
|
||||
|
||||
if n == 0:
|
||||
start_points_left_shift = np.array([left_edge])
|
||||
else:
|
||||
start_points_left_shift = start_points[:-1]
|
||||
start_points_left_shift = np.insert(start_points_left_shift,0,left_edge, axis = 0)
|
||||
stop_points_left = 0.5 * (start_points + start_points_left_shift)
|
||||
stop_points_left += level_height * DOWN
|
||||
|
||||
|
||||
if n == 0:
|
||||
start_points_right_shift = np.array([right_edge])
|
||||
else:
|
||||
start_points_right_shift = start_points[1:]
|
||||
start_points_right_shift = np.append(start_points_right_shift,np.array([right_edge]), axis = 0)
|
||||
stop_points_right = 0.5 * (start_points + start_points_right_shift)
|
||||
stop_points_right += level_height * DOWN
|
||||
|
||||
|
||||
for (i,(p,q)) in enumerate(zip(start_points,stop_points_left)):
|
||||
|
||||
color = LIGHT_GRAY
|
||||
|
||||
if n % 2 == 0 and i <= n/2:
|
||||
m = n/2 + 0.25
|
||||
jj = i
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 0 and i > n/2:
|
||||
m = n/2 + 0.25
|
||||
jj = n - i + 0.5
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 1 and i <= n/2:
|
||||
m = n/2 + 0.75
|
||||
jj = i
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 1 and i > n/2:
|
||||
m = n/2 + 0.75
|
||||
jj = n - i + 0.5
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
line = Line(p,q, stroke_color = color)
|
||||
self.add(line)
|
||||
|
||||
for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)):
|
||||
|
||||
color = LIGHT_GRAY
|
||||
|
||||
if n % 2 == 0 and i < n/2:
|
||||
m = n/2 + 0.25
|
||||
jj = i + 0.5
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 0 and i >= n/2:
|
||||
m = n/2 + 0.25
|
||||
jj = n - i
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 1 and i <= n/2:
|
||||
m = n/2 + 0.75
|
||||
jj = i + 0.5
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
elif n % 2 == 1 and i > n/2:
|
||||
m = n/2 + 0.75
|
||||
jj = n - i
|
||||
alpha = 1 - float(jj)/m
|
||||
color = rainbow_color(alpha)
|
||||
|
||||
|
||||
line = Line(p,q, stroke_color = color)
|
||||
self.add(line)
|
||||
|
||||
if (n + 1) % dev_y_step == 0 and n != 1:
|
||||
j += dev_x_step
|
||||
dev_stop = stop_points_left[j]
|
||||
line = Line(dev_start,dev_stop,stroke_color = WHITE)
|
||||
self.add(line)
|
||||
dot = Dot(dev_stop, fill_color = WHITE)
|
||||
self.add_foreground_mobject(dot)
|
||||
dev_start = dev_stop
|
||||
|
||||
|
||||
|
||||
start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0)
|
||||
|
||||
left_edge += level_height * DOWN
|
||||
right_edge += level_height * DOWN
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
from active_projects.eop.reusables.binary_option import *
|
||||
from active_projects.eop.reusables.brick_row import *
|
||||
from active_projects.eop.reusables.coin_flip_tree import *
|
||||
from active_projects.eop.reusables.coin_flipping_pi_creature import *
|
||||
from active_projects.eop.reusables.coin_stacks import *
|
||||
from active_projects.eop.reusables.dice import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.histograms import *
|
||||
from active_projects.eop.reusables.sick_pi_creature import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
@@ -1,15 +0,0 @@
|
||||
from mobject.types.vectorized_mobject import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
|
||||
class BinaryOption(VMobject):
|
||||
CONFIG = {
|
||||
"text_scale" : 0.5
|
||||
}
|
||||
|
||||
def __init__(self, mob1, mob2, **kwargs):
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
text = TextMobject("or").scale(self.text_scale)
|
||||
mob1.next_to(text, LEFT)
|
||||
mob2.next_to(text, RIGHT)
|
||||
self.add(mob1, text, mob2)
|
||||
@@ -1,208 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
|
||||
class BrickRow(VMobject):
|
||||
|
||||
CONFIG = {
|
||||
"left_color" : COLOR_HEADS,
|
||||
"right_color" : COLOR_TAILS,
|
||||
"height" : 1.0,
|
||||
"width" : 8.0,
|
||||
"outcome_shrinkage_factor_x" : 0.95,
|
||||
"outcome_shrinkage_factor_y" : 0.94
|
||||
}
|
||||
|
||||
def __init__(self, n, **kwargs):
|
||||
self.subdiv_level = n
|
||||
self.coloring_level = n
|
||||
VMobject.__init__(self, **kwargs)
|
||||
|
||||
|
||||
def generate_points(self):
|
||||
|
||||
self.submobjects = []
|
||||
self.rects = self.get_rects_for_level(self.coloring_level)
|
||||
self.add(self.rects)
|
||||
self.subdivs = self.get_subdivs_for_level(self.subdiv_level)
|
||||
self.add(self.subdivs)
|
||||
|
||||
self.border = SurroundingRectangle(self,
|
||||
buff = 0, color = WHITE)
|
||||
self.add(self.border)
|
||||
|
||||
|
||||
|
||||
def get_rects_for_level(self,r):
|
||||
rects = VGroup()
|
||||
for k in range(r + 1):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
new_rect = Rectangle(
|
||||
width = proportion * self.width,
|
||||
height = self.height,
|
||||
fill_color = graded_color(r,k),
|
||||
fill_opacity = 1,
|
||||
stroke_width = 0
|
||||
)
|
||||
if len(rects.submobjects) > 0:
|
||||
new_rect.next_to(rects,RIGHT,buff = 0)
|
||||
else:
|
||||
new_rect.next_to(self.get_center() + 0.5 * self.width * LEFT, RIGHT, buff = 0)
|
||||
rects.add(new_rect)
|
||||
return rects
|
||||
|
||||
|
||||
def get_subdivs_for_level(self,r):
|
||||
subdivs = VGroup()
|
||||
x = - 0.5 * self.width
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
x += proportion * self.width
|
||||
subdiv = Line(
|
||||
x * RIGHT + 0.5 * self.height * UP,
|
||||
x * RIGHT + 0.5 * self.height * DOWN,
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
subdivs.move_to(self.get_center())
|
||||
return subdivs
|
||||
|
||||
|
||||
def get_sequence_subdivs_for_level(self,r):
|
||||
subdivs = VGroup()
|
||||
x = - 0.5 * self.width
|
||||
dx = 1.0 / 2**r
|
||||
for k in range(1, 2 ** r):
|
||||
proportion = dx
|
||||
x += proportion * self.width
|
||||
subdiv = DashedLine(
|
||||
x * RIGHT + 0.5 * self.height * UP,
|
||||
x * RIGHT + 0.5 * self.height * DOWN,
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
subdivs.move_to(self.get_center())
|
||||
return subdivs
|
||||
|
||||
|
||||
def get_outcome_centers_for_level(self,r):
|
||||
|
||||
dpos = float(self.width) / (2 ** r) * RIGHT
|
||||
pos = 0.5 * self.width * LEFT + 0.5 * dpos
|
||||
centers = []
|
||||
for k in range(0, 2 ** r):
|
||||
centers.append(self.get_center() + pos + k * dpos)
|
||||
|
||||
return centers
|
||||
|
||||
def get_outcome_rects_for_level(self, r, inset = False, with_labels = False):
|
||||
|
||||
centers = self.get_outcome_centers_for_level(r)
|
||||
if inset == True:
|
||||
outcome_width = self.outcome_shrinkage_factor_x * float(self.width) / (2 ** r)
|
||||
outcome_height = self.outcome_shrinkage_factor_y * self.height
|
||||
else:
|
||||
outcome_width = float(self.width) / (2 ** r)
|
||||
outcome_height = self.height
|
||||
|
||||
corner_radius = 0.1 # max(0.1, 0.3 * min(outcome_width, outcome_height))
|
||||
# this scales down the corner radius for very narrow rects
|
||||
rect = RoundedRectangle(
|
||||
width = outcome_width,
|
||||
height = outcome_height,
|
||||
corner_radius = corner_radius,
|
||||
fill_color = OUTCOME_COLOR,
|
||||
fill_opacity = OUTCOME_OPACITY,
|
||||
stroke_width = 0
|
||||
)
|
||||
rects = VGroup()
|
||||
for center in centers:
|
||||
rects.add(rect.copy().move_to(center))
|
||||
|
||||
rects.move_to(self.get_center())
|
||||
|
||||
|
||||
if with_labels == False:
|
||||
return rects
|
||||
|
||||
# else
|
||||
sequences = self.get_coin_sequences_for_level(r)
|
||||
labels = VGroup()
|
||||
for (seq, rect) in zip(sequences, rects):
|
||||
coin_seq = CoinSequence(seq, direction = DOWN)
|
||||
coin_seq.shift(rect.get_center() - coin_seq.get_center())
|
||||
# not simply move_to bc coin_seq is not centered
|
||||
rect.add(coin_seq)
|
||||
rect.label = coin_seq
|
||||
|
||||
return rects
|
||||
|
||||
def get_coin_sequences_for_level(self,r):
|
||||
# array of arrays of characters
|
||||
if r < 0 or int(r) != r:
|
||||
raise Exception("Level must be a positive integer")
|
||||
if r == 0:
|
||||
return []
|
||||
if r == 1:
|
||||
return [["H"], ["T"]]
|
||||
|
||||
previous_seq_array = self.get_coin_sequences_for_level(r - 1)
|
||||
subdiv_lengths = [choose(r - 1, k) for k in range(r)]
|
||||
|
||||
seq_array = []
|
||||
index = 0
|
||||
for length in subdiv_lengths:
|
||||
|
||||
for seq in previous_seq_array[index:index + length]:
|
||||
seq_copy = copy.copy(seq)
|
||||
seq_copy.append("H")
|
||||
seq_array.append(seq_copy)
|
||||
|
||||
for seq in previous_seq_array[index:index + length]:
|
||||
seq_copy = copy.copy(seq)
|
||||
seq_copy.append("T")
|
||||
seq_array.append(seq_copy)
|
||||
index += length
|
||||
|
||||
return seq_array
|
||||
|
||||
|
||||
def get_outcome_width_for_level(self,r):
|
||||
return self.width / (2**r)
|
||||
|
||||
def get_rect_widths_for_level(self, r):
|
||||
ret_arr = []
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
ret_arr.append(proportion * self.width)
|
||||
return ret_arr
|
||||
|
||||
|
||||
|
||||
|
||||
class SplitRectsInBrickWall(AnimationGroup):
|
||||
|
||||
def __init__(self, mobject, **kwargs):
|
||||
|
||||
#print mobject.height, mobject.get_height()
|
||||
r = self.subdiv_level = mobject.subdiv_level + 1
|
||||
|
||||
subdivs = VGroup()
|
||||
x = -0.5 * mobject.get_width()
|
||||
|
||||
anims = []
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
x += proportion * mobject.get_width()
|
||||
subdiv = DashedLine(
|
||||
mobject.get_top() + x * RIGHT,
|
||||
mobject.get_bottom() + x * RIGHT,
|
||||
dash_length = 0.05
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
anims.append(ShowCreation(subdiv))
|
||||
|
||||
mobject.add(subdivs)
|
||||
AnimationGroup.__init__(self, *anims, **kwargs)
|
||||
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
from mobject.geometry import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
class CoinFlipTree(VGroup):
|
||||
CONFIG = {
|
||||
"total_width": 12,
|
||||
"level_height": 0.8,
|
||||
"nb_levels": 4,
|
||||
"sort_until_level": 3
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
VGroup.__init__(self, **kwargs)
|
||||
|
||||
self.rows = []
|
||||
for n in range(self.nb_levels + 1):
|
||||
if n <= self.sort_until_level:
|
||||
self.create_row(n, sorted = True)
|
||||
else:
|
||||
self.create_row(n, sorted = False)
|
||||
|
||||
|
||||
for row in self.rows:
|
||||
for leaf in row:
|
||||
dot = Dot()
|
||||
dot.move_to(leaf[0])
|
||||
line = Line(leaf[2], leaf[0])
|
||||
if leaf[2][0] > leaf[0][0]:
|
||||
line_color = COLOR_HEADS
|
||||
else:
|
||||
line_color = COLOR_TAILS
|
||||
line.set_stroke(color = line_color)
|
||||
group = VGroup()
|
||||
group.add(dot)
|
||||
group.add_to_back(line)
|
||||
self.add(group)
|
||||
|
||||
|
||||
|
||||
|
||||
def create_row(self, level, sorted = True):
|
||||
|
||||
if level == 0:
|
||||
new_row = [[ORIGIN,0,ORIGIN]] # is its own parent
|
||||
self.rows.append(new_row)
|
||||
return
|
||||
|
||||
previous_row = self.rows[level - 1]
|
||||
new_row = []
|
||||
dx = float(self.total_width) / (2 ** level)
|
||||
x = - 0.5 * self.total_width + 0.5 * dx
|
||||
y = - self.level_height * level
|
||||
for root in previous_row:
|
||||
root_point = root[0]
|
||||
root_tally = root[1]
|
||||
for i in range(2): # 0 = heads = left, 1 = tails = right
|
||||
leaf = x * RIGHT + y * UP
|
||||
new_row.append([leaf, root_tally + i, root_point]) # leaf and its parent
|
||||
x += dx
|
||||
|
||||
if sorted:
|
||||
# sort the new_row by its tallies
|
||||
sorted_row = []
|
||||
x = - 0.5 * self.total_width + 0.5 * dx
|
||||
for i in range(level + 1):
|
||||
for leaf in new_row:
|
||||
if leaf[1] == i:
|
||||
sorted_leaf = leaf
|
||||
sorted_leaf[0][0] = x
|
||||
x += dx
|
||||
sorted_row.append(leaf)
|
||||
self.rows.append(sorted_row)
|
||||
else:
|
||||
self.rows.append(new_row)
|
||||
@@ -1,112 +0,0 @@
|
||||
from mobject.types.vectorized_mobject import *
|
||||
from animation.animation import *
|
||||
from animation.composition import *
|
||||
from mobject.geometry import Rectangle, Line
|
||||
from utils.rate_functions import *
|
||||
from for_3b1b_videos.pi_creature_scene import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.coin_flipping_pi_creature import *
|
||||
|
||||
|
||||
class PiCreatureCoin(VMobject):
|
||||
CONFIG = {
|
||||
"diameter": 0.8,
|
||||
"thickness": 0.2,
|
||||
"nb_ridges" : 7,
|
||||
"stroke_color": YELLOW,
|
||||
"stroke_width": 3,
|
||||
"fill_color": YELLOW,
|
||||
"fill_opacity": 0.7,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
outer_rect = Rectangle(
|
||||
width = self.diameter,
|
||||
height = self.thickness,
|
||||
fill_color = self.fill_color,
|
||||
fill_opacity = self.fill_opacity,
|
||||
stroke_color = self.stroke_color,
|
||||
stroke_width = 0, #self.stroke_width
|
||||
)
|
||||
self.add(outer_rect)
|
||||
PI = TAU/2
|
||||
ridge_angles = np.arange(PI/self.nb_ridges,PI,PI/self.nb_ridges)
|
||||
ridge_positions = 0.5 * self.diameter * np.array([
|
||||
np.cos(theta) for theta in ridge_angles
|
||||
])
|
||||
ridge_color = interpolate_color(BLACK,self.stroke_color,0.5)
|
||||
for x in ridge_positions:
|
||||
ridge = Line(
|
||||
x * RIGHT + 0.5 * self.thickness * DOWN,
|
||||
x * RIGHT + 0.5 * self.thickness * UP,
|
||||
stroke_color = ridge_color,
|
||||
stroke_width = self.stroke_width
|
||||
)
|
||||
self.add(ridge)
|
||||
|
||||
class CoinFlippingPiCreature(PiCreature):
|
||||
CONFIG = {
|
||||
"flip_height": 3
|
||||
}
|
||||
|
||||
def __init__(self, mode = "coin_flip_1", **kwargs):
|
||||
|
||||
coin = PiCreatureCoin()
|
||||
PiCreature.__init__(self, mode = mode, **kwargs)
|
||||
self.coin = coin
|
||||
self.add(coin)
|
||||
right_arm = self.get_arm_copies()[1]
|
||||
coin.rotate(-TAU/24)
|
||||
coin.next_to(right_arm, RIGHT+UP, buff = 0)
|
||||
coin.shift(0.1 * self.get_width() * LEFT)
|
||||
coin.shift(0.2 * DOWN)
|
||||
|
||||
def flip_coin_up(self):
|
||||
self.change("coin_flip_2")
|
||||
|
||||
|
||||
|
||||
class FlipUpAndDown(Animation):
|
||||
CONFIG = {
|
||||
"vector" : UP,
|
||||
"height" : 3,
|
||||
"nb_turns" : 1
|
||||
}
|
||||
|
||||
def update(self,t):
|
||||
self.mobject.shift(self.height * 4 * t * (1 - t) * self.vector)
|
||||
self.mobject.rotate(t * self.nb_turns * TAU)
|
||||
|
||||
class FlipCoin(AnimationGroup):
|
||||
CONFIG = {
|
||||
"coin_rate_func" : there_and_back,
|
||||
"pi_rate_func" : lambda t : there_and_back_with_pause(t, 1./4)
|
||||
}
|
||||
def __init__(self, pi_creature, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
pi_creature_motion = ApplyMethod(
|
||||
pi_creature.flip_coin_up,
|
||||
rate_func = self.pi_rate_func,
|
||||
**kwargs
|
||||
)
|
||||
coin_motion = Succession(
|
||||
EmptyAnimation(run_time = 1.0),
|
||||
FlipUpAndDown(
|
||||
pi_creature.coin,
|
||||
vector = UP,
|
||||
nb_turns = 5,
|
||||
height = pi_creature.flip_height * pi_creature.get_height(),
|
||||
rate_func = self.coin_rate_func,
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
AnimationGroup.__init__(self,pi_creature_motion, coin_motion)
|
||||
|
||||
class CoinFlippingPiCreatureScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E)
|
||||
self.add(randy)
|
||||
self.play(FlipCoin(randy, run_time = 3))
|
||||
@@ -1,111 +0,0 @@
|
||||
from mobject.geometry import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
|
||||
|
||||
class CoinStack(VGroup):
|
||||
CONFIG = {
|
||||
"coin_thickness": COIN_THICKNESS,
|
||||
"size": 5,
|
||||
"face": FlatCoin,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
for n in range(self.size):
|
||||
coin = self.face(thickness = self.coin_thickness)
|
||||
coin.shift(n * self.coin_thickness * UP)
|
||||
self.add(coin)
|
||||
if self.size == 0:
|
||||
point = VectorizedPoint()
|
||||
self.add(point)
|
||||
|
||||
class HeadsStack(CoinStack):
|
||||
CONFIG = {
|
||||
"face": FlatHeads
|
||||
}
|
||||
|
||||
class TailsStack(CoinStack):
|
||||
CONFIG = {
|
||||
"face": FlatTails
|
||||
}
|
||||
|
||||
|
||||
|
||||
class DecimalTally(TextMobject):
|
||||
|
||||
def __init__(self, heads, tails, **kwargs):
|
||||
|
||||
TextMobject.__init__(self, str(heads), "\\textemdash\,", str(tails), **kwargs)
|
||||
self[0].set_color(COLOR_HEADS)
|
||||
self[-1].set_color(COLOR_TAILS)
|
||||
# this only works for single-digit tallies
|
||||
|
||||
|
||||
|
||||
|
||||
class TallyStack(VGroup):
|
||||
CONFIG = {
|
||||
"coin_thickness": COIN_THICKNESS,
|
||||
"show_decimals": True
|
||||
}
|
||||
|
||||
def __init__(self, h, t, anchor = ORIGIN, **kwargs):
|
||||
self.nb_heads = h
|
||||
self.nb_tails = t
|
||||
self.anchor = anchor
|
||||
VGroup.__init__(self,**kwargs)
|
||||
|
||||
def generate_points(self):
|
||||
stack1 = HeadsStack(size = self.nb_heads, coin_thickness = self.coin_thickness)
|
||||
stack2 = TailsStack(size = self.nb_tails, coin_thickness = self.coin_thickness)
|
||||
stack1.next_to(self.anchor, LEFT, buff = 0.5 * SMALL_BUFF)
|
||||
stack2.next_to(self.anchor, RIGHT, buff = 0.5 * SMALL_BUFF)
|
||||
stack1.align_to(self.anchor, DOWN)
|
||||
stack2.align_to(self.anchor, DOWN)
|
||||
self.heads_stack = stack1
|
||||
self.tails_stack = stack2
|
||||
self.add(stack1, stack2)
|
||||
self.background_rect = background_rect = RoundedRectangle(
|
||||
width = TALLY_BACKGROUND_WIDTH,
|
||||
height = TALLY_BACKGROUND_WIDTH,
|
||||
corner_radius = 0.1,
|
||||
fill_color = TALLY_BACKGROUND_COLOR,
|
||||
fill_opacity = 1.0,
|
||||
stroke_width = 3
|
||||
).align_to(self.anchor, DOWN).shift(0.1 * DOWN)
|
||||
self.add_to_back(background_rect)
|
||||
|
||||
self.decimal_tally = DecimalTally(self.nb_heads, self.nb_tails)
|
||||
self.position_decimal_tally(self.decimal_tally)
|
||||
if self.show_decimals:
|
||||
self.add(self.decimal_tally)
|
||||
|
||||
def position_decimal_tally(self, decimal_tally):
|
||||
decimal_tally.match_width(self.background_rect)
|
||||
decimal_tally.scale(0.6)
|
||||
decimal_tally.next_to(self.background_rect.get_top(), DOWN, buff = 0.15)
|
||||
return decimal_tally
|
||||
|
||||
|
||||
def move_anchor_to(self, new_anchor):
|
||||
for submob in self.submobjects:
|
||||
submob.shift(new_anchor - self.anchor)
|
||||
|
||||
self.anchor = new_anchor
|
||||
self.position_decimal_tally(self.decimal_tally)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
from mobject.svg.svg_mobject import *
|
||||
from mobject.geometry import *
|
||||
from mobject.numbers import *
|
||||
|
||||
class DieFace(SVGMobject):
|
||||
|
||||
def __init__(self, value, **kwargs):
|
||||
|
||||
self.value = value
|
||||
self.file_name = "Dice-" + str(value)
|
||||
self.ensure_valid_file()
|
||||
SVGMobject.__init__(self, file_name = self.file_name)
|
||||
|
||||
class RowOfDice(VGroup):
|
||||
CONFIG = {
|
||||
"values" : list(range(1,7)),
|
||||
"direction": RIGHT,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
for value in self.values:
|
||||
new_die = DieFace(value)
|
||||
new_die.submobjects[0].set_fill(opacity = 0)
|
||||
new_die.submobjects[0].set_stroke(width = 7)
|
||||
new_die.next_to(self, self.direction)
|
||||
self.add(new_die)
|
||||
self.move_to(ORIGIN)
|
||||
|
||||
|
||||
class TwoDiceTable(VMobject):
|
||||
CONFIG = {
|
||||
"cell_size" : 1,
|
||||
"label_scale": 0.7
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
colors = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], 13)
|
||||
|
||||
self.cells = VGroup()
|
||||
self.labels = VGroup()
|
||||
for i in range(1,7):
|
||||
for j in range(1,7):
|
||||
cell = Square(side_length = self.cell_size)
|
||||
cell.set_fill(color = colors[i+j], opacity = 0.8)
|
||||
cell.move_to(i*self.cell_size*DOWN + j*self.cell_size*RIGHT)
|
||||
self.cells.add(cell)
|
||||
label = Integer(i+j).scale(self.label_scale)
|
||||
label.move_to(cell)
|
||||
self.labels.add(label)
|
||||
|
||||
|
||||
self.add(self.cells, self.labels)
|
||||
row1 = RowOfDice().match_width(self)
|
||||
row2 = row1.copy().rotate(-TAU/4)
|
||||
row1.next_to(self, UP)
|
||||
row2.next_to(self, LEFT)
|
||||
self.rows = VGroup(row1, row2)
|
||||
self.add(self.rows)
|
||||
self.center()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
from constants import *
|
||||
|
||||
COIN_RADIUS = 0.18
|
||||
COIN_THICKNESS = 0.4 * COIN_RADIUS
|
||||
COIN_FORESHORTENING = 0.5
|
||||
COIN_NB_RIDGES = 20
|
||||
COIN_STROKE_WIDTH = 2
|
||||
|
||||
COIN_SEQUENCE_SPACING = 0.1
|
||||
|
||||
GRADE_COLOR_1 = COLOR_HEADS = RED_E
|
||||
GRADE_COLOR_2 = COLOR_TAILS = BLUE_C
|
||||
|
||||
COLOR_HEADS_COIN = RED
|
||||
COLOR_TAILS_COIN = BLUE_E
|
||||
|
||||
TALLY_BACKGROUND_WIDTH = 1.0
|
||||
TALLY_BACKGROUND_COLOR = BLACK
|
||||
|
||||
SICKLY_GREEN = "#9BBD37"
|
||||
|
||||
OUTCOME_COLOR = WHITE
|
||||
OUTCOME_OPACITY = 0.5
|
||||
@@ -1,36 +0,0 @@
|
||||
from utils.color import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
def binary(i):
|
||||
# returns an array of 0s and 1s
|
||||
if i == 0:
|
||||
return []
|
||||
j = i
|
||||
binary_array = []
|
||||
while j > 0:
|
||||
jj = j/2
|
||||
if jj > 0:
|
||||
binary_array.append(j % 2)
|
||||
else:
|
||||
binary_array.append(1)
|
||||
j = jj
|
||||
return binary_array[::-1]
|
||||
|
||||
def nb_of_ones(i):
|
||||
return binary(i).count(1)
|
||||
|
||||
|
||||
def rainbow_color(alpha):
|
||||
nb_colors = 100
|
||||
rainbow = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], nb_colors)
|
||||
rainbow = np.append(rainbow,PURPLE)
|
||||
index = int(alpha * nb_colors)
|
||||
return rainbow[index]
|
||||
|
||||
def graded_color(n,k):
|
||||
if n != 0:
|
||||
alpha = float(k)/n
|
||||
else:
|
||||
alpha = 0.5
|
||||
color = interpolate_color(GRADE_COLOR_1, GRADE_COLOR_2, alpha)
|
||||
return color
|
||||
@@ -1,348 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
from random import *
|
||||
|
||||
def text_range(start,stop,step): # a range as a list of strings
|
||||
numbers = np.arange(start,stop,step)
|
||||
labels = []
|
||||
for x in numbers:
|
||||
labels.append(str(x))
|
||||
return labels
|
||||
|
||||
|
||||
class Histogram(VMobject):
|
||||
|
||||
CONFIG = {
|
||||
"start_color" : RED,
|
||||
"end_color" : BLUE,
|
||||
"x_scale" : 1.0,
|
||||
"y_scale" : 1.0,
|
||||
"x_labels" : "auto", # widths, mids, auto, none, [...]
|
||||
"y_labels" : "auto", # auto, none, [...]
|
||||
"y_label_position" : "top", # "center"
|
||||
"x_min" : 0,
|
||||
"bar_stroke_width" : 5,
|
||||
"outline_stroke_width" : 0,
|
||||
"stroke_color" : WHITE
|
||||
}
|
||||
|
||||
def __init__(self, x_values, y_values, mode = "widths", **kwargs):
|
||||
# mode = "widths" : x_values means the widths of the bars
|
||||
# mode = "posts" : x_values means the delimiters btw the bars
|
||||
|
||||
digest_config(self, kwargs)
|
||||
|
||||
if mode == "widths" and len(x_values) != len(y_values):
|
||||
raise Exception("Array lengths do not match up!")
|
||||
elif mode == "posts" and len(x_values) != len(y_values) + 1:
|
||||
raise Exception("Array lengths do not match up!")
|
||||
|
||||
|
||||
self.y_values = y_values
|
||||
self.x_values = x_values
|
||||
self.mode = mode
|
||||
self.process_values()
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
|
||||
|
||||
def process_values(self):
|
||||
|
||||
# preliminaries
|
||||
self.y_values = np.array(self.y_values)
|
||||
|
||||
if self.mode == "widths":
|
||||
self.widths = self.x_values
|
||||
self.posts = np.cumsum(self.widths)
|
||||
self.posts = np.insert(self.posts, 0, 0)
|
||||
self.posts += self.x_min
|
||||
self.x_max = self.posts[-1]
|
||||
elif self.mode == "posts":
|
||||
self.posts = self.x_values
|
||||
self.widths = self.x_values[1:] - self.x_values[:-1]
|
||||
self.x_min = self.posts[0]
|
||||
self.x_max = self.posts[-1]
|
||||
else:
|
||||
raise Exception("Invalid mode or no mode specified!")
|
||||
|
||||
self.x_mids = 0.5 * (self.posts[:-1] + self.posts[1:])
|
||||
|
||||
self.widths_scaled = self.x_scale * self.widths
|
||||
self.posts_scaled = self.x_scale * self.posts
|
||||
self.x_min_scaled = self.x_scale * self.x_min
|
||||
self.x_max_scaled = self.x_scale * self.x_max
|
||||
|
||||
self.y_values_scaled = self.y_scale * self.y_values
|
||||
|
||||
|
||||
|
||||
def generate_points(self):
|
||||
|
||||
self.process_values()
|
||||
for submob in self.submobjects:
|
||||
self.remove(submob)
|
||||
|
||||
def empty_string_array(n):
|
||||
arr = []
|
||||
for i in range(n):
|
||||
arr.append("")
|
||||
return arr
|
||||
|
||||
def num_arr_to_string_arr(arr): # converts number array to string array
|
||||
ret_arr = []
|
||||
for x in arr:
|
||||
if x == np.floor(x):
|
||||
new_x = int(np.floor(x))
|
||||
else:
|
||||
new_x = x
|
||||
ret_arr.append(str(new_x))
|
||||
return ret_arr
|
||||
|
||||
previous_bar = ORIGIN
|
||||
self.bars = VGroup()
|
||||
self.x_labels_group = VGroup()
|
||||
self.y_labels_group = VGroup()
|
||||
outline_points = []
|
||||
|
||||
if self.x_labels == "widths":
|
||||
self.x_labels = num_arr_to_string_arr(self.widths)
|
||||
elif self.x_labels == "mids":
|
||||
self.x_labels = num_arr_to_string_arr(self.x_mids)
|
||||
elif self.x_labels == "auto":
|
||||
self.x_labels = num_arr_to_string_arr(self.x_mids)
|
||||
elif self.x_labels == "none":
|
||||
self.x_labels = empty_string_array(len(self.widths))
|
||||
|
||||
if self.y_labels == "auto":
|
||||
self.y_labels = num_arr_to_string_arr(self.y_values)
|
||||
elif self.y_labels == "none":
|
||||
self.y_labels = empty_string_array(len(self.y_values))
|
||||
|
||||
|
||||
|
||||
|
||||
for (i,x) in enumerate(self.x_mids):
|
||||
|
||||
bar = Rectangle(
|
||||
width = self.widths_scaled[i],
|
||||
height = self.y_values_scaled[i],
|
||||
stroke_width = self.bar_stroke_width,
|
||||
stroke_color = self.stroke_color,
|
||||
)
|
||||
if bar.height == 0:
|
||||
bar.height = 0.01
|
||||
bar.generate_points()
|
||||
|
||||
t = float(x - self.x_min)/(self.x_max - self.x_min)
|
||||
bar_color = interpolate_color(
|
||||
self.start_color,
|
||||
self.end_color,
|
||||
t
|
||||
)
|
||||
bar.set_fill(color = bar_color, opacity = 1)
|
||||
bar.next_to(previous_bar,RIGHT,buff = 0, aligned_edge = DOWN)
|
||||
|
||||
self.bars.add(bar)
|
||||
|
||||
x_label = TextMobject(self.x_labels[i])
|
||||
x_label.next_to(bar,DOWN)
|
||||
self.x_labels_group.add(x_label)
|
||||
|
||||
y_label = TextMobject(self.y_labels[i])
|
||||
if self.y_label_position == "top":
|
||||
y_label.next_to(bar, UP)
|
||||
elif self.y_label_position == "center":
|
||||
y_label.move_to(bar)
|
||||
else:
|
||||
raise Exception("y_label_position must be top or center")
|
||||
self.y_labels_group.add(y_label)
|
||||
|
||||
if i == 0:
|
||||
# start with the lower left
|
||||
outline_points.append(bar.get_anchors()[-2])
|
||||
|
||||
# upper two points of each bar
|
||||
outline_points.append(bar.get_anchors()[0])
|
||||
outline_points.append(bar.get_anchors()[1])
|
||||
|
||||
previous_bar = bar
|
||||
# close the outline
|
||||
# lower right
|
||||
outline_points.append(bar.get_anchors()[2])
|
||||
# lower left
|
||||
outline_points.append(outline_points[0])
|
||||
|
||||
self.outline = Polygon(*outline_points,
|
||||
stroke_width = self.outline_stroke_width,
|
||||
stroke_color = self.stroke_color)
|
||||
self.add(self.bars, self.x_labels_group, self.y_labels_group, self.outline)
|
||||
|
||||
self.move_to(ORIGIN)
|
||||
|
||||
def get_lower_left_point(self):
|
||||
return self.bars[0].get_anchors()[-2]
|
||||
|
||||
|
||||
|
||||
class BuildUpHistogram(Animation):
|
||||
|
||||
def __init__(self, hist, **kwargs):
|
||||
self.histogram = hist
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FlashThroughHistogram(Animation):
|
||||
CONFIG = {
|
||||
"cell_color" : WHITE,
|
||||
"cell_opacity" : 0.8,
|
||||
"hist_opacity" : 0.2
|
||||
}
|
||||
|
||||
def __init__(self, mobject,
|
||||
direction = "horizontal",
|
||||
mode = "random",
|
||||
**kwargs):
|
||||
|
||||
digest_config(self, kwargs)
|
||||
|
||||
self.cell_height = mobject.y_scale
|
||||
self.prototype_cell = Rectangle(
|
||||
width = 1,
|
||||
height = self.cell_height,
|
||||
fill_color = self.cell_color,
|
||||
fill_opacity = self.cell_opacity,
|
||||
stroke_width = 0,
|
||||
)
|
||||
|
||||
x_values = mobject.x_values
|
||||
y_values = mobject.y_values
|
||||
|
||||
self.mode = mode
|
||||
self.direction = direction
|
||||
|
||||
self.generate_cell_indices(x_values,y_values)
|
||||
Animation.__init__(self,mobject,**kwargs)
|
||||
|
||||
|
||||
|
||||
def generate_cell_indices(self,x_values,y_values):
|
||||
|
||||
self.cell_indices = []
|
||||
for (i,x) in enumerate(x_values):
|
||||
|
||||
nb_cells = int(np.floor(y_values[i]))
|
||||
for j in range(nb_cells):
|
||||
self.cell_indices.append((i, j))
|
||||
|
||||
self.reordered_cell_indices = self.cell_indices
|
||||
if self.mode == "random":
|
||||
shuffle(self.reordered_cell_indices)
|
||||
|
||||
|
||||
def cell_for_index(self,i,j):
|
||||
|
||||
if self.direction == "vertical":
|
||||
width = self.mobject.x_scale
|
||||
height = self.mobject.y_scale
|
||||
x = (i + 0.5) * self.mobject.x_scale
|
||||
y = (j + 0.5) * self.mobject.y_scale
|
||||
center = self.mobject.get_lower_left_point() + x * RIGHT + y * UP
|
||||
|
||||
elif self.direction == "horizontal":
|
||||
width = self.mobject.x_scale / self.mobject.y_values[i]
|
||||
height = self.mobject.y_scale * self.mobject.y_values[i]
|
||||
x = i * self.mobject.x_scale + (j + 0.5) * width
|
||||
y = height / 2
|
||||
center = self.mobject.get_lower_left_point() + x * RIGHT + y * UP
|
||||
|
||||
cell = Rectangle(width = width, height = height)
|
||||
cell.move_to(center)
|
||||
return cell
|
||||
|
||||
|
||||
def interpolate_mobject(self,t):
|
||||
|
||||
if t == 0:
|
||||
self.mobject.add(self.prototype_cell)
|
||||
|
||||
flash_nb = int(t * (len(self.cell_indices))) - 1
|
||||
(i,j) = self.reordered_cell_indices[flash_nb]
|
||||
cell = self.cell_for_index(i,j)
|
||||
self.prototype_cell.width = cell.get_width()
|
||||
self.prototype_cell.height = cell.get_height()
|
||||
self.prototype_cell.generate_points()
|
||||
self.prototype_cell.move_to(cell.get_center())
|
||||
|
||||
if t == 1:
|
||||
self.mobject.remove(self.prototype_cell)
|
||||
|
||||
|
||||
def clean_up_from_scene(self, scene = None):
|
||||
Animation.clean_up_from_scene(self, scene)
|
||||
self.update(1)
|
||||
if scene is not None:
|
||||
if self.is_remover():
|
||||
scene.remove(self.prototype_cell)
|
||||
else:
|
||||
scene.add(self.prototype_cell)
|
||||
return self
|
||||
|
||||
|
||||
|
||||
class OutlineableBars(VGroup):
|
||||
|
||||
# A group of bars (rectangles), together with
|
||||
# a method that draws an outline around them,
|
||||
# assuming the bars are arranged in a histogram
|
||||
# (aligned at the bottom without gaps).
|
||||
|
||||
# We use this to morph a row of bricks into a histogram.
|
||||
|
||||
CONFIG = {
|
||||
"outline_stroke_width" : 3,
|
||||
"stroke_color" : WHITE
|
||||
}
|
||||
def create_outline(self, animated = False, **kwargs):
|
||||
|
||||
outline_points = []
|
||||
|
||||
for (i, bar) in enumerate(self.submobjects):
|
||||
|
||||
if i == 0:
|
||||
# start with the lower left
|
||||
outline_points.append(bar.get_corner(DOWN + LEFT))
|
||||
|
||||
# upper two points of each bar
|
||||
outline_points.append(bar.get_corner(UP + LEFT))
|
||||
outline_points.append(bar.get_corner(UP + RIGHT))
|
||||
|
||||
previous_bar = bar
|
||||
# close the outline
|
||||
# lower right
|
||||
outline_points.append(previous_bar.get_corner(DOWN + RIGHT))
|
||||
# lower left
|
||||
outline_points.append(outline_points[0])
|
||||
|
||||
self.outline = Polygon(*outline_points,
|
||||
stroke_width = self.outline_stroke_width,
|
||||
stroke_color = self.stroke_color)
|
||||
|
||||
if animated:
|
||||
self.play(FadeIn(self.outline, **kwargs))
|
||||
return self.outline
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
from for_3b1b_videos.pi_creature import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
|
||||
class SicklyPiCreature(PiCreature):
|
||||
CONFIG = {
|
||||
"sick_color": SICKLY_GREEN
|
||||
}
|
||||
|
||||
def get_slightly_sick(self):
|
||||
|
||||
self.save_state()
|
||||
self.set_color(self.sick_color)
|
||||
|
||||
def get_sick(self):
|
||||
|
||||
self.get_slightly_sick()
|
||||
self.change_mode("sick")
|
||||
|
||||
def get_better(self):
|
||||
self.restore()
|
||||
@@ -1,132 +0,0 @@
|
||||
|
||||
from mobject.geometry import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
from utils.color import *
|
||||
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
class UprightCoin(Circle):
|
||||
# For use in coin sequences
|
||||
CONFIG = {
|
||||
"radius": COIN_RADIUS,
|
||||
"stroke_width": COIN_STROKE_WIDTH,
|
||||
"stroke_color": WHITE,
|
||||
"fill_opacity": 1,
|
||||
"symbol": "\euro"
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
Circle.__init__(self,**kwargs)
|
||||
self.symbol_mob = TextMobject(self.symbol, stroke_color = self.stroke_color)
|
||||
self.symbol_mob.set_height(0.5*self.get_height()).move_to(self)
|
||||
self.add(self.symbol_mob)
|
||||
|
||||
class UprightHeads(UprightCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_HEADS_COIN,
|
||||
"symbol": "H",
|
||||
}
|
||||
|
||||
class UprightTails(UprightCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_TAILS_COIN,
|
||||
"symbol": "T",
|
||||
}
|
||||
|
||||
class CoinSequence(VGroup):
|
||||
CONFIG = {
|
||||
"sequence": [],
|
||||
"radius" : COIN_RADIUS,
|
||||
"spacing": COIN_SEQUENCE_SPACING,
|
||||
"direction": RIGHT
|
||||
}
|
||||
|
||||
def __init__(self, sequence, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
self.sequence = sequence
|
||||
offset = 0
|
||||
for symbol in self.sequence:
|
||||
if symbol == "H":
|
||||
new_coin = UprightHeads(radius = self.radius)
|
||||
elif symbol == "T":
|
||||
new_coin = UprightTails(radius = self.radius)
|
||||
else:
|
||||
new_coin = UprightCoin(symbol = symbol, radius = self.radius)
|
||||
new_coin.shift(offset * self.direction)
|
||||
self.add(new_coin)
|
||||
offset += self.spacing
|
||||
|
||||
|
||||
class FlatCoin(UprightCoin):
|
||||
# For use in coin stacks
|
||||
CONFIG = {
|
||||
"thickness": COIN_THICKNESS,
|
||||
"foreshortening": COIN_FORESHORTENING,
|
||||
"nb_ridges": COIN_NB_RIDGES
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
UprightCoin.__init__(self, **kwargs)
|
||||
self.symbol_mob.rotate(TAU/8)
|
||||
self.stretch_in_place(self.foreshortening, 1)
|
||||
|
||||
# draw the edge
|
||||
control_points1 = self.points[12:25].tolist()
|
||||
control_points2 = self.copy().shift(self.thickness * DOWN).points[12:25].tolist()
|
||||
edge_anchors_and_handles = control_points1
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN)
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP)
|
||||
edge_anchors_and_handles += control_points2[::-1] # list concatenation
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP)
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN)
|
||||
edge_anchors_and_handles.append(control_points1[0])
|
||||
#edge_anchors_and_handles = edge_anchors_and_handles[::-1]
|
||||
edge = VMobject()
|
||||
edge.set_points(edge_anchors_and_handles)
|
||||
edge.set_fill(
|
||||
color = self.fill_color,
|
||||
opacity = self.fill_opacity
|
||||
)
|
||||
edge.set_stroke(width = self.stroke_width)
|
||||
self.add(edge)
|
||||
|
||||
# draw the ridges
|
||||
PI = TAU/2
|
||||
dtheta = PI/self.nb_ridges
|
||||
ridge_angles = np.arange(dtheta,PI,dtheta)
|
||||
# add a twist onto each coin
|
||||
ridge_angles += np.random.rand(1) * dtheta
|
||||
# crop the angles that overshoot on either side
|
||||
ridge_angles = ridge_angles[(ridge_angles > 0) * (ridge_angles < PI)]
|
||||
ridge_positions = 0.5 * 2 * self.radius * np.array([
|
||||
np.cos(theta) for theta in ridge_angles
|
||||
])
|
||||
ridge_color = interpolate_color(self.stroke_color, self.fill_color, 0.7)
|
||||
for x in ridge_positions:
|
||||
y = -(1 - (x/self.radius)**2)**0.5 * self.foreshortening * self.radius
|
||||
ridge = Line(
|
||||
x * RIGHT + y * UP,
|
||||
x * RIGHT + y * UP + self.thickness * DOWN,
|
||||
stroke_color = ridge_color,
|
||||
stroke_width = self.stroke_width
|
||||
)
|
||||
self.add(ridge)
|
||||
|
||||
# redraw the unfilled edge to cover the ridge ends
|
||||
empty_edge = edge.copy()
|
||||
empty_edge.set_fill(opacity = 0)
|
||||
self.add(empty_edge)
|
||||
|
||||
class FlatHeads(FlatCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_HEADS_COIN,
|
||||
"symbol": "H",
|
||||
}
|
||||
|
||||
class FlatTails(FlatCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_TAILS_COIN,
|
||||
"symbol": "T",
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
class WhatDoesItReallyMean(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
student_q = TextMobject("What does", "``probability''", "\emph{actually}", "mean?")
|
||||
student_q.set_color_by_tex("probability", YELLOW)
|
||||
self.student_says(student_q, target_mode = "sassy")
|
||||
self.wait()
|
||||
|
||||
question_bubble = VGroup(student_q, students[1].bubble)
|
||||
scaled_qb = question_bubble.copy()
|
||||
scaled_qb.scale(0.4).to_corner(UL)
|
||||
self.play(Transform(question_bubble, scaled_qb))
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
self.teacher_says("Don't worry -- philosophy can come later!")
|
||||
self.wait()
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
class ComplexAnalysisOverlay(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Complex analysis")
|
||||
words.scale(1.25)
|
||||
words.to_edge(UP)
|
||||
words.add_background_rectangle()
|
||||
self.add(words)
|
||||
self.wait()
|
||||
|
||||
|
||||
class AnalyzeZSquared(ComplexTransformationScene, ZoomedScene):
|
||||
CONFIG = {
|
||||
"plane_config": {
|
||||
"line_frequency": 0.1,
|
||||
},
|
||||
"num_anchors_to_add_per_line": 20,
|
||||
"complex_homotopy": lambda z, t: z**(1.0 + t),
|
||||
"zoom_factor": 0.05,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
ComplexTransformationScene.setup(self)
|
||||
ZoomedScene.setup(self)
|
||||
|
||||
def construct(self):
|
||||
self.edit_background_plane()
|
||||
self.add_title()
|
||||
# self.add_transforming_planes()
|
||||
# self.preview_some_numbers()
|
||||
self.zoom_in_to_one_plus_half_i()
|
||||
self.write_derivative()
|
||||
|
||||
def add_title(self):
|
||||
title = TexMobject("z \\rightarrow z^2")
|
||||
title.add_background_rectangle()
|
||||
title.scale(1.5)
|
||||
title.to_corner(UL, buff=MED_SMALL_BUFF)
|
||||
self.add_foreground_mobject(title)
|
||||
|
||||
def edit_background_plane(self):
|
||||
self.backgrounds.set_stroke(GREY, 2)
|
||||
self.background.secondary_lines.set_stroke(DARK_GREY, 1)
|
||||
self.add_foreground_mobject(self.background.coordinate_labels)
|
||||
|
||||
def add_transforming_planes(self):
|
||||
self.plane = self.get_plane()
|
||||
self.add_transformable_mobjects(self.plane)
|
||||
|
||||
def preview_some_numbers(self):
|
||||
dots = VGroup(*[
|
||||
Dot().move_to(self.background.number_to_point(z))
|
||||
for z in [
|
||||
1, 2, complex(0, 1),
|
||||
-1, complex(2, 0.5), complex(-1, -1), complex(3, 0.5),
|
||||
]
|
||||
])
|
||||
dots.set_color_by_gradient(RED, YELLOW)
|
||||
d_angle = 30 * DEGREES
|
||||
|
||||
dot_groups = VGroup()
|
||||
for dot in dots:
|
||||
point = dot.get_center()
|
||||
z = self.background.point_to_number(point)
|
||||
z_out = self.complex_homotopy(z, 1)
|
||||
out_point = self.background.number_to_point(z_out)
|
||||
path_arc = angle_of_vector(point)
|
||||
if abs(z - 1) < 0.01:
|
||||
# One is special
|
||||
arrow = Arc(
|
||||
start_angle=(-90 * DEGREES + d_angle),
|
||||
angle=(360 * DEGREES - 2 * d_angle),
|
||||
radius=0.25
|
||||
)
|
||||
arrow.add_tip(tip_length=0.15)
|
||||
arrow.pointwise_become_partial(arrow, 0, 0.9)
|
||||
arrow.next_to(dot, UP, buff=0)
|
||||
else:
|
||||
arrow = Arrow(
|
||||
point, out_point,
|
||||
path_arc=path_arc,
|
||||
buff=SMALL_BUFF,
|
||||
)
|
||||
arrow.match_color(dot)
|
||||
|
||||
out_dot = dot.copy()
|
||||
# out_dot.set_fill(opacity=0.5)
|
||||
out_dot.set_stroke(BLUE, 1)
|
||||
out_dot.move_to(out_point)
|
||||
dot.path_arc = path_arc
|
||||
dot.out_dot = out_dot
|
||||
|
||||
dot_group = VGroup(dot, arrow, out_dot)
|
||||
dot_groups.add(dot_group)
|
||||
|
||||
dot_copy = dot.copy()
|
||||
dot.save_state()
|
||||
dot.scale(3)
|
||||
dot.fade(1)
|
||||
|
||||
dot_group.anim = Succession(
|
||||
ApplyMethod(dot.restore),
|
||||
AnimationGroup(
|
||||
ShowCreation(arrow),
|
||||
ReplacementTransform(
|
||||
dot_copy, out_dot,
|
||||
path_arc=path_arc
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
for dot_group in dot_groups[:3]:
|
||||
self.play(dot_group.anim)
|
||||
self.wait()
|
||||
self.play(*[dg.anim for dg in dot_groups[3:]])
|
||||
|
||||
self.apply_complex_homotopy(
|
||||
self.complex_homotopy,
|
||||
added_anims=[Animation(dot_groups)]
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOut(dot_groups))
|
||||
self.wait()
|
||||
self.play(FadeOut(self.plane))
|
||||
self.transformable_mobjects.remove(self.plane)
|
||||
|
||||
def zoom_in_to_one_plus_half_i(self):
|
||||
z = complex(1, 0.5)
|
||||
point = self.background.number_to_point(z)
|
||||
point_mob = VectorizedPoint(point)
|
||||
frame = self.zoomed_camera.frame
|
||||
frame.move_to(point)
|
||||
tiny_plane = NumberPlane(
|
||||
x_radius=2, y_radius=2,
|
||||
color=GREEN,
|
||||
secondary_color=GREEN_E
|
||||
)
|
||||
tiny_plane.replace(frame)
|
||||
|
||||
plane = self.get_plane()
|
||||
|
||||
words = TextMobject("What does this look like")
|
||||
words.add_background_rectangle()
|
||||
words.next_to(self.zoomed_display, LEFT, aligned_edge=UP)
|
||||
arrow = Arrow(words.get_bottom(), self.zoomed_display.get_left())
|
||||
VGroup(words, arrow).set_color(YELLOW)
|
||||
|
||||
self.play(FadeIn(plane))
|
||||
self.activate_zooming(animate=True)
|
||||
self.play(ShowCreation(tiny_plane))
|
||||
self.wait()
|
||||
self.add_transformable_mobjects(plane, tiny_plane, point_mob)
|
||||
self.add_foreground_mobjects(words, arrow)
|
||||
self.apply_complex_homotopy(
|
||||
self.complex_homotopy,
|
||||
added_anims=[
|
||||
Write(words),
|
||||
GrowArrow(arrow),
|
||||
MaintainPositionRelativeTo(frame, point_mob)
|
||||
]
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
def write_derivative(self):
|
||||
pass
|
||||
|
||||
# Helpers
|
||||
|
||||
def get_plane(self):
|
||||
top_plane = NumberPlane(
|
||||
y_radius=FRAME_HEIGHT / 2,
|
||||
x_line_frequency=0.1,
|
||||
y_line_frequency=0.1,
|
||||
)
|
||||
self.prepare_for_transformation(top_plane)
|
||||
bottom_plane = top_plane.copy()
|
||||
tiny_tiny_buff = 0.001
|
||||
top_plane.next_to(ORIGIN, UP, buff=tiny_tiny_buff)
|
||||
bottom_plane.next_to(ORIGIN, DOWN, buff=tiny_tiny_buff)
|
||||
return VGroup(top_plane, bottom_plane)
|
||||
@@ -1,415 +0,0 @@
|
||||
from manimlib.imports import *
|
||||
|
||||
|
||||
# Helpers
|
||||
def get_shadow(mobject, opacity=0.5):
|
||||
result = mobject.deepcopy()
|
||||
result.apply_function(lambda p: [p[0], p[1], 0])
|
||||
color = interpolate_color(
|
||||
mobject.get_fill_color(), BLACK,
|
||||
mobject.get_fill_opacity()
|
||||
)
|
||||
# color = BLACK
|
||||
result.set_fill(color, opacity=opacity)
|
||||
result.set_stroke(BLACK, 0.5, opacity=opacity)
|
||||
result.set_shade_in_3d(False)
|
||||
return result
|
||||
|
||||
|
||||
def get_boundary_points(shadow, n_points=20):
|
||||
points = shadow.get_points_defining_boundary()
|
||||
return np.array([
|
||||
points[np.argmax(np.dot(points, vect.T))]
|
||||
for vect in compass_directions(n_points)
|
||||
])
|
||||
|
||||
|
||||
def get_area(planar_mobject):
|
||||
boundary = get_boundary_points(planar_mobject, 100)
|
||||
xs = boundary[:, 0]
|
||||
ys = boundary[:, 1]
|
||||
dxs = np.append(xs[-1], xs[:-1]) - xs
|
||||
dys = np.append(ys[-1], ys[:-1]) - ys
|
||||
return abs(sum([
|
||||
0.5 * (x * dy - y * dx)
|
||||
for x, dx, y, dy in zip(xs, dxs, ys, dys)
|
||||
]))
|
||||
|
||||
|
||||
def get_xy_plane_projection_point(p1, p2):
|
||||
"""
|
||||
Draw a line from source to p1 to p2. Where does it
|
||||
intersect the xy plane?
|
||||
"""
|
||||
vect = p2 - p1
|
||||
return p1 - (p1[2] / vect[2]) * vect
|
||||
|
||||
|
||||
# Scenes
|
||||
|
||||
|
||||
class ShowShadows(ThreeDScene):
|
||||
CONFIG = {
|
||||
"object_center": [0, 0, 3],
|
||||
"area_label_center": [0, -1.5, 0],
|
||||
"surface_area": 6.0,
|
||||
"num_reorientations": 10,
|
||||
"camera_config": {
|
||||
"light_source_start_point": 10 * OUT,
|
||||
"frame_center": [0, 0, 0.5],
|
||||
},
|
||||
"initial_orientation_config": {
|
||||
"phi": 60 * DEGREES,
|
||||
"theta": -120 * DEGREES,
|
||||
}
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
self.add_plane()
|
||||
self.setup_orientation_trackers()
|
||||
self.setup_object_and_shadow()
|
||||
self.add_shadow_area_label()
|
||||
self.add_surface_area_label()
|
||||
|
||||
def add_plane(self):
|
||||
plane = self.plane = Rectangle(
|
||||
width=FRAME_WIDTH,
|
||||
height=24.2,
|
||||
stroke_width=0,
|
||||
fill_color=WHITE,
|
||||
fill_opacity=0.35,
|
||||
)
|
||||
plane.set_sheen(0.2, DR)
|
||||
grid = NumberPlane(
|
||||
color=LIGHT_GREY,
|
||||
secondary_color=DARK_GREY,
|
||||
y_radius=int(plane.get_height() / 2),
|
||||
stroke_width=1,
|
||||
secondary_line_ratio=0,
|
||||
)
|
||||
plane.add(grid)
|
||||
plane.add(VectorizedPoint(10 * IN))
|
||||
plane.set_shade_in_3d(True, z_index_as_group=True)
|
||||
self.add(plane)
|
||||
|
||||
def setup_orientation_trackers(self):
|
||||
# Euler angles
|
||||
self.alpha_tracker = ValueTracker(0)
|
||||
self.beta_tracker = ValueTracker(0)
|
||||
self.gamma_tracker = ValueTracker(0)
|
||||
|
||||
def setup_object_and_shadow(self):
|
||||
self.obj3d = always_redraw(self.get_reoriented_object)
|
||||
self.shadow = always_redraw(lambda: get_shadow(self.obj3d))
|
||||
|
||||
def add_shadow_area_label(self):
|
||||
text = TextMobject("Shadow area: ")
|
||||
decimal = DecimalNumber(0)
|
||||
label = VGroup(text, decimal)
|
||||
label.arrange(RIGHT)
|
||||
label.scale(1.5)
|
||||
label.move_to(self.area_label_center - decimal.get_center())
|
||||
self.shadow_area_label = label
|
||||
self.shadow_area_decimal = decimal
|
||||
|
||||
# def update_decimal(decimal):
|
||||
# # decimal.set_value(get_area(self.shadow))
|
||||
# self.add_fixed_in_frame_mobjects(decimal)
|
||||
|
||||
# decimal.add_updater(update_decimal)
|
||||
decimal.add_updater(
|
||||
lambda d: d.set_value(get_area(self.shadow))
|
||||
)
|
||||
decimal.add_updater(
|
||||
lambda d: self.add_fixed_in_frame_mobjects(d)
|
||||
)
|
||||
|
||||
# self.add_fixed_orientation_mobjects(label)
|
||||
self.add_fixed_in_frame_mobjects(label)
|
||||
self.add(label)
|
||||
self.add(decimal)
|
||||
|
||||
def add_surface_area_label(self):
|
||||
text = TextMobject("Surface area: ")
|
||||
decimal = DecimalNumber(self.surface_area)
|
||||
label = VGroup(text, decimal)
|
||||
label.arrange(RIGHT)
|
||||
label.scale(1.25)
|
||||
label.set_fill(YELLOW)
|
||||
label.set_background_stroke(width=3)
|
||||
label.next_to(self.obj3d, RIGHT, LARGE_BUFF)
|
||||
label.shift(MED_LARGE_BUFF * IN)
|
||||
self.surface_area_label = label
|
||||
self.add_fixed_orientation_mobjects(label)
|
||||
|
||||
def construct(self):
|
||||
# Show creation
|
||||
obj3d = self.obj3d.copy()
|
||||
obj3d.clear_updaters()
|
||||
temp_shadow = always_redraw(lambda: get_shadow(obj3d))
|
||||
self.add(temp_shadow)
|
||||
self.move_camera(
|
||||
**self.initial_orientation_config,
|
||||
added_anims=[
|
||||
LaggedStartMap(DrawBorderThenFill, obj3d)
|
||||
],
|
||||
run_time=2
|
||||
)
|
||||
self.begin_ambient_camera_rotation(0.01)
|
||||
self.remove(obj3d, temp_shadow)
|
||||
|
||||
average_label = self.get_average_label()
|
||||
# Reorient
|
||||
self.add(self.obj3d, self.shadow)
|
||||
for n in range(self.num_reorientations):
|
||||
self.randomly_reorient()
|
||||
if n == 3:
|
||||
self.add_fixed_in_frame_mobjects(average_label)
|
||||
self.play(Write(average_label, run_time=2))
|
||||
else:
|
||||
self.wait()
|
||||
|
||||
def randomly_reorient(self, run_time=3):
|
||||
a, b, c = TAU * np.random.random(3)
|
||||
self.play(
|
||||
self.alpha_tracker.set_value, a,
|
||||
self.beta_tracker.set_value, b,
|
||||
self.gamma_tracker.set_value, c,
|
||||
run_time=run_time
|
||||
)
|
||||
|
||||
#
|
||||
def get_object(self):
|
||||
cube = Cube()
|
||||
cube.set_height(1)
|
||||
# cube.set_width(2, stretch=True)
|
||||
cube.set_stroke(WHITE, 0.5)
|
||||
return cube
|
||||
|
||||
def get_reoriented_object(self):
|
||||
obj3d = self.get_object()
|
||||
angles = [
|
||||
self.alpha_tracker.get_value(),
|
||||
self.beta_tracker.get_value(),
|
||||
self.gamma_tracker.get_value(),
|
||||
]
|
||||
vects = [OUT, RIGHT, OUT]
|
||||
|
||||
center = self.object_center
|
||||
obj3d.move_to(center)
|
||||
for angle, vect in zip(angles, vects):
|
||||
obj3d.rotate(angle, vect, about_point=center)
|
||||
return obj3d
|
||||
|
||||
def get_average_label(self):
|
||||
rect = SurroundingRectangle(
|
||||
self.shadow_area_decimal,
|
||||
buff=SMALL_BUFF,
|
||||
color=RED,
|
||||
)
|
||||
words = TextMobject(
|
||||
"Average", "=",
|
||||
"$\\frac{\\text{Surface area}}{4}$"
|
||||
)
|
||||
words.scale(1.5)
|
||||
words[0].match_color(rect)
|
||||
words[2].set_color(self.surface_area_label[0].get_fill_color())
|
||||
words.set_background_stroke(width=3)
|
||||
words.next_to(
|
||||
rect, DOWN,
|
||||
index_of_submobject_to_align=0,
|
||||
)
|
||||
# words.shift(MED_LARGE_BUFF * LEFT)
|
||||
return VGroup(rect, words)
|
||||
|
||||
|
||||
class ShowInfinitelyFarLightSource(ShowShadows):
|
||||
CONFIG = {
|
||||
"num_reorientations": 1,
|
||||
"camera_center": [0, 0, 1],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
ShowShadows.construct(self)
|
||||
self.revert_to_original_skipping_status()
|
||||
|
||||
self.add_light_source_based_shadow_updater()
|
||||
self.add_light()
|
||||
self.move_light_around()
|
||||
self.show_vertical_lines()
|
||||
|
||||
def add_light(self):
|
||||
light = self.light = self.get_light()
|
||||
light_source = self.camera.light_source
|
||||
light.move_to(light_source)
|
||||
light_source.add_updater(lambda m: m.move_to(light))
|
||||
self.add(light_source)
|
||||
self.add_fixed_orientation_mobjects(light)
|
||||
|
||||
def move_light_around(self):
|
||||
light = self.light
|
||||
self.add_foreground_mobjects(self.shadow_area_label)
|
||||
self.play(
|
||||
light.move_to, 5 * OUT + DOWN,
|
||||
run_time=3
|
||||
)
|
||||
self.play(Rotating(
|
||||
light, angle=TAU, about_point=5 * OUT,
|
||||
rate_func=smooth, run_time=3
|
||||
))
|
||||
self.play(
|
||||
light.move_to, 30 * OUT,
|
||||
run_time=3,
|
||||
)
|
||||
self.remove(light)
|
||||
|
||||
def show_vertical_lines(self):
|
||||
lines = self.get_vertical_lines()
|
||||
obj3d = self.obj3d
|
||||
shadow = self.shadow
|
||||
target_obj3d = obj3d.copy()
|
||||
target_obj3d.become(shadow)
|
||||
target_obj3d.match_style(obj3d)
|
||||
target_obj3d.set_shade_in_3d(False)
|
||||
source_obj3d = obj3d.copy()
|
||||
source_obj3d.set_shade_in_3d(False)
|
||||
source_obj3d.fade(1)
|
||||
|
||||
self.play(LaggedStartMap(ShowCreation, lines))
|
||||
self.wait()
|
||||
self.add(source_obj3d, lines)
|
||||
self.play(
|
||||
ReplacementTransform(source_obj3d, target_obj3d),
|
||||
run_time=2
|
||||
)
|
||||
self.add(target_obj3d, lines)
|
||||
self.play(FadeOut(target_obj3d),)
|
||||
self.wait()
|
||||
lines.add_updater(lambda m: m.become(self.get_vertical_lines()))
|
||||
for x in range(5):
|
||||
self.randomly_reorient()
|
||||
|
||||
def add_light_source_based_shadow_updater(self):
|
||||
shadow = self.shadow
|
||||
light_source = self.camera.light_source
|
||||
obj3d = self.obj3d
|
||||
center = obj3d.get_center()
|
||||
|
||||
def update(shadow):
|
||||
lsp = light_source.get_center()
|
||||
proj_center = get_xy_plane_projection_point(lsp, center)
|
||||
c_to_lsp = lsp - center
|
||||
unit_c_to_lsp = normalize(c_to_lsp)
|
||||
rotation = rotation_matrix(
|
||||
angle=np.arccos(np.dot(unit_c_to_lsp, OUT)),
|
||||
axis=normalize(np.cross(unit_c_to_lsp, OUT))
|
||||
)
|
||||
new_shadow = get_shadow(
|
||||
self.obj3d.copy().apply_matrix(rotation)
|
||||
)
|
||||
shadow.become(new_shadow)
|
||||
shadow.scale(get_norm(lsp) / get_norm(c_to_lsp))
|
||||
shadow.move_to(proj_center)
|
||||
return shadow
|
||||
shadow.add_updater(update)
|
||||
|
||||
def get_light(self):
|
||||
n_rings = 40
|
||||
radii = np.linspace(0, 2, n_rings)
|
||||
rings = VGroup(*[
|
||||
Annulus(inner_radius=r1, outer_radius=r2)
|
||||
for r1, r2 in zip(radii, radii[1:])
|
||||
])
|
||||
opacities = np.linspace(1, 0, n_rings)**1.5
|
||||
for opacity, ring in zip(opacities, rings):
|
||||
ring.set_fill(YELLOW, opacity)
|
||||
ring.set_stroke(YELLOW, width=0.1, opacity=opacity)
|
||||
return rings
|
||||
|
||||
def get_vertical_lines(self):
|
||||
shadow = self.shadow
|
||||
points = get_boundary_points(shadow, 10)
|
||||
# half_points = [(p1 + p2) / 2 for p1, p2 in adjacent_pairs(points)]
|
||||
# points = np.append(points, half_points, axis=0)
|
||||
light_source = self.light.get_center()
|
||||
lines = VGroup(*[
|
||||
DashedLine(light_source, point)
|
||||
for point in points
|
||||
])
|
||||
lines.set_shade_in_3d(True)
|
||||
for line in lines:
|
||||
line.remove(*line[:int(0.8 * len(line))])
|
||||
line[-10:].set_shade_in_3d(False)
|
||||
line.set_stroke(YELLOW, 1)
|
||||
return lines
|
||||
|
||||
|
||||
class CylinderShadows(ShowShadows):
|
||||
CONFIG = {
|
||||
"surface_area": 2 * PI + 2 * PI * 2,
|
||||
"area_label_center": [0, -2, 0],
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
height = 2
|
||||
cylinder = ParametricSurface(
|
||||
lambda u, v: np.array([
|
||||
np.cos(TAU * v),
|
||||
np.sin(TAU * v),
|
||||
height * (1 - u)
|
||||
]),
|
||||
resolution=(6, 32)
|
||||
)
|
||||
# circle = Circle(radius=1)
|
||||
circle = ParametricSurface(
|
||||
lambda u, v: np.array([
|
||||
(v + 0.01) * np.cos(TAU * u),
|
||||
(v + 0.01) * np.sin(TAU * u),
|
||||
0,
|
||||
]),
|
||||
resolution=(16, 8)
|
||||
)
|
||||
# circle.set_fill(GREEN, opacity=0.5)
|
||||
for surface in cylinder, circle:
|
||||
surface.set_fill_by_checkerboard(GREEN, GREEN_E, opacity=1.0)
|
||||
# surface.set_fill(GREEN, opacity=0.5)
|
||||
cylinder.add(circle)
|
||||
cylinder.add(circle.copy().flip().move_to(height * OUT))
|
||||
cylinder.set_shade_in_3d(True)
|
||||
cylinder.set_stroke(width=0)
|
||||
cylinder.scale(1.003)
|
||||
return cylinder
|
||||
|
||||
|
||||
class PrismShadows(ShowShadows):
|
||||
CONFIG = {
|
||||
"surface_area": 3 * np.sqrt(3) / 2 + 3 * (np.sqrt(3) * 2),
|
||||
"object_center": [0, 0, 3],
|
||||
"area_label_center": [0, -2.25, 0],
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
height = 2
|
||||
prism = VGroup()
|
||||
triangle = RegularPolygon(3)
|
||||
verts = triangle.get_anchors()[:3]
|
||||
rects = [
|
||||
Polygon(v1, v2, v2 + height * OUT, v1 + height * OUT)
|
||||
for v1, v2 in adjacent_pairs(verts)
|
||||
]
|
||||
prism.add(triangle, *rects)
|
||||
prism.add(triangle.copy().shift(height * OUT))
|
||||
triangle.reverse_points()
|
||||
prism.set_shade_in_3d(True)
|
||||
prism.set_fill(PINK, 0.8)
|
||||
prism.set_stroke(WHITE, 1)
|
||||
return prism
|
||||
|
||||
|
||||
class TheseFourPiAreSquare(PiCreatureScene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
def create_pi_creatures(self):
|
||||
pass
|
||||
@@ -1,16 +0,0 @@
|
||||
version: '3.1'
|
||||
|
||||
services:
|
||||
manim:
|
||||
# comment this line if you build the image to prevent overwriting the tag
|
||||
image: eulertour/manim:latest
|
||||
# uncomment this line to build rather than pull the image
|
||||
# build: .
|
||||
entrypoint:
|
||||
- manim
|
||||
- --media_dir=/tmp/output
|
||||
volumes:
|
||||
- ${INPUT_PATH:?INPUT_PATH environment variable isn't set}:/tmp/input
|
||||
- ${OUTPUT_PATH:?OUTPUT_PATH environment variable isn't set}:/tmp/output
|
||||
working_dir: /tmp/input
|
||||
network_mode: "none"
|
||||
@@ -1,9 +1,10 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
@@ -16,4 +17,4 @@ help:
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
37
docs/example.py
Normal file
37
docs/example.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from manimlib import *
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
square = Square()
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.wait()
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
self.wait()
|
||||
# Try typing the following lines
|
||||
# self.play(circle.animate.stretch(4, dim=0))
|
||||
# self.play(Rotate(circle, TAU / 4))
|
||||
# self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
|
||||
# circle.insert_n_curves(10)
|
||||
# self.play(circle.animate.apply_complex_function(lambda z: z**2))
|
||||
|
||||
class SquareToCircleEmbed(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
|
||||
self.add(circle)
|
||||
self.wait()
|
||||
self.play(circle.animate.stretch(4, dim=0))
|
||||
self.wait(1.5)
|
||||
self.play(Rotate(circle, TAU / 4))
|
||||
self.wait(1.5)
|
||||
self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
|
||||
self.wait(1.5)
|
||||
circle.insert_n_curves(10)
|
||||
self.play(circle.animate.apply_complex_function(lambda z: z**2))
|
||||
self.wait(2)
|
||||
@@ -1,35 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
||||
4
docs/requirements.txt
Normal file
4
docs/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Sphinx==3.0.3
|
||||
sphinx-copybutton
|
||||
furo==2020.10.5b9
|
||||
Jinja2
|
||||
BIN
docs/source/_static/icon.png
Normal file
BIN
docs/source/_static/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
@@ -1,11 +0,0 @@
|
||||
About
|
||||
=====
|
||||
|
||||
Animating technical concepts is traditionally pretty tedious, since it can be
|
||||
difficult to make the animations precise enough to convey them accurately.
|
||||
``Manim`` uses Python to generate animations programmatically, which makes it
|
||||
possible to specify exactly how each one should run.
|
||||
|
||||
This project is still very much a work in progress, but I hope that the
|
||||
information here will make it easier for newcomers to get started using
|
||||
``Manim``.
|
||||
@@ -1,210 +0,0 @@
|
||||
Animation
|
||||
=========
|
||||
|
||||
|
||||
|
||||
The simplest of which is ``Scene.add``. The object appears on the first frame
|
||||
without any animation::
|
||||
|
||||
class NoAnimation(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
self.add(square))
|
||||
|
||||
Animation are used in conjunction with ``scene.Play``
|
||||
|
||||
Fade
|
||||
----
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeIn.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeIn(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Fade In")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.play(FadeIn(square))
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeOut.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeOut(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Fade Out")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.add(square)
|
||||
self.play(FadeOut(square))
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFrom.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFrom(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Fade In from {label}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeInFrom(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeOutAndShift.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeOutAndShift(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Fade Out and shift {label}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeOutAndShift(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromLarge.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromLarge(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
for factor in [0.1, 0.5, 0.8, 1, 2, 5]:
|
||||
anno = TextMobject(f"Fade In from large scale\_factor={factor}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeInFromLarge(square, scale_factor=factor))
|
||||
self.remove(anno, square)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromPoint.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromPoint(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for i in range(-6, 7, 2):
|
||||
anno = TextMobject(f"Fade In from point {i}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.play(FadeInFromPoint(square, point=i))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
Grow
|
||||
----
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationGrowFromEdge.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationGrowFromEdge(Scene):
|
||||
def construct(self):
|
||||
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Grow from {label} edge")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
square = Square()
|
||||
self.play(GrowFromEdge(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationGrowFromCenter.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationGrowFromCenter(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Grow from center")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(GrowFromCenter(square))
|
||||
|
||||
|
||||
|
||||
|
||||
Diagonal Directions
|
||||
-------------------
|
||||
|
||||
You can combine cardinal directions to form diagonal animations
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromDiagonal.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromDiagonal(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for diag in [UP + LEFT, UP + RIGHT, DOWN + LEFT, DOWN + RIGHT]:
|
||||
self.play(FadeInFrom(square, diag))
|
||||
|
||||
.. note::
|
||||
You can also use the abbreviated forms like ``UL, UR, DL, DR``.
|
||||
See :ref:`ref-directions`.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user