mirror of
https://github.com/3b1b/manim.git
synced 2025-07-31 22:13:30 +08:00
Finally have faster video writing capabilities
This commit is contained in:
@ -59,7 +59,6 @@ TEX_DIR = os.path.join(FILE_DIR, "Tex")
|
|||||||
TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex")
|
TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex")
|
||||||
MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects")
|
MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects")
|
||||||
IMAGE_MOBJECT_DIR = os.path.join(MOBJECT_DIR, "image")
|
IMAGE_MOBJECT_DIR = os.path.join(MOBJECT_DIR, "image")
|
||||||
TMP_IMAGE_DIR = "/tmp/animation_images/"
|
|
||||||
|
|
||||||
for folder in [IMAGE_DIR, GIF_DIR, MOVIE_DIR, TEX_DIR, TMP_IMAGE_DIR,
|
for folder in [IMAGE_DIR, GIF_DIR, MOVIE_DIR, TEX_DIR, TMP_IMAGE_DIR,
|
||||||
TEX_IMAGE_DIR, MOBJECT_DIR, IMAGE_MOBJECT_DIR]:
|
TEX_IMAGE_DIR, MOBJECT_DIR, IMAGE_MOBJECT_DIR]:
|
||||||
|
116
displayer.py
116
displayer.py
@ -1,8 +1,9 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
import subprocess as sp
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import subprocess
|
|
||||||
import cv2
|
import cv2
|
||||||
from colour import Color
|
from colour import Color
|
||||||
import progressbar
|
import progressbar
|
||||||
@ -10,6 +11,8 @@ import progressbar
|
|||||||
from mobject import *
|
from mobject import *
|
||||||
from constants import *
|
from constants import *
|
||||||
|
|
||||||
|
FFMPEG_BIN = "ffmpeg"
|
||||||
|
|
||||||
def get_pixels(image_array): #TODO, FIX WIDTH/HEIGHT PROBLEM HERE
|
def get_pixels(image_array): #TODO, FIX WIDTH/HEIGHT PROBLEM HERE
|
||||||
if image_array is None:
|
if image_array is None:
|
||||||
return np.zeros(
|
return np.zeros(
|
||||||
@ -126,97 +129,34 @@ def write_to_gif(scene, name):
|
|||||||
os.system("rm " + temppath)
|
os.system("rm " + temppath)
|
||||||
|
|
||||||
def write_to_movie(scene, name):
|
def write_to_movie(scene, name):
|
||||||
frames = scene.frames
|
filepath = os.path.join(MOVIE_DIR, name) + ".mp4"
|
||||||
progress_bar = progressbar.ProgressBar(maxval=len(frames))
|
print "Writing to %s"%filepath
|
||||||
progress_bar.start()
|
|
||||||
print "writing " + name + "..."
|
|
||||||
|
|
||||||
filepath = os.path.join(MOVIE_DIR, name)
|
fps = int(1/scene.display_config["frame_duration"])
|
||||||
filedir = "/".join(filepath.split("/")[:-1])
|
dim = (scene.display_config["width"], scene.display_config["height"])
|
||||||
if not os.path.exists(filedir):
|
|
||||||
os.makedirs(filedir)
|
|
||||||
rate = int(1/scene.frame_duration)
|
|
||||||
|
|
||||||
tmp_stem = os.path.join(TMP_IMAGE_DIR, name.replace("/", "_"))
|
command = [
|
||||||
suffix = "-%04d.png"
|
FFMPEG_BIN,
|
||||||
image_files = []
|
'-y', # overwrite output file if it exists
|
||||||
for frame, count in zip(frames, it.count()):
|
'-f', 'rawvideo',
|
||||||
progress_bar.update(int(0.9 * count))
|
'-vcodec','rawvideo',
|
||||||
Image.fromarray(frame).save(tmp_stem + suffix%count)
|
'-s', '%dx%d'%dim, # size of one frame
|
||||||
image_files.append(tmp_stem + suffix%count)
|
'-pix_fmt', 'rgb24',
|
||||||
commands = [
|
'-r', str(fps), # frames per second
|
||||||
"ffmpeg",
|
'-i', '-', # The imput comes from a pipe
|
||||||
"-y",
|
'-an', # Tells FFMPEG not to expect any audio
|
||||||
"-loglevel",
|
'-vcodec', 'mpeg',
|
||||||
"error",
|
'-c:v', 'libx264',
|
||||||
"-i",
|
'-pix_fmt', 'yuv420p',
|
||||||
tmp_stem + suffix,
|
'-loglevel', 'error',
|
||||||
"-c:v",
|
filepath,
|
||||||
"libx264",
|
|
||||||
"-vf",
|
|
||||||
"fps=%d,format=yuv420p"%rate,
|
|
||||||
filepath + ".mp4"
|
|
||||||
]
|
]
|
||||||
os.system(" ".join(commands))
|
process = sp.Popen(command, stdin=sp.PIPE)
|
||||||
for image_file in image_files:
|
for frame in scene.frames:
|
||||||
os.remove(image_file)
|
process.stdin.write(frame.tostring())
|
||||||
progress_bar.finish()
|
|
||||||
|
|
||||||
|
process.stdin.close()
|
||||||
# vs = VideoSink(scene.shape, filepath, rate)
|
process.wait()
|
||||||
# for frame in frames:
|
|
||||||
# vs.run(frame)
|
|
||||||
# vs.close()
|
|
||||||
# progress_bar.finish()
|
|
||||||
|
|
||||||
|
|
||||||
# filepath = os.path.join(MOVIE_DIR, name + ".mov")
|
|
||||||
# fourcc = cv2.cv.FOURCC(*"8bps")
|
|
||||||
# out = cv2.VideoWriter(
|
|
||||||
# filepath, fourcc, 1.0/scene.frame_duration, (DEFAULT_WIDTH, DEFAULT_HEIGHT), True
|
|
||||||
# )
|
|
||||||
# progress = 0
|
|
||||||
# for frame in frames:
|
|
||||||
# if progress == 0:
|
|
||||||
# print "Writing movie"
|
|
||||||
# progress_bar.update(progress)
|
|
||||||
# r, g, b = cv2.split(np.array(frame))
|
|
||||||
# bgr_frame = cv2.merge([b, g, r])
|
|
||||||
# out.write(bgr_frame)
|
|
||||||
# progress += 1
|
|
||||||
# out.release()
|
|
||||||
# progress_bar.finish()
|
|
||||||
|
|
||||||
|
|
||||||
# class VideoSink(object):
|
|
||||||
# def __init__(self, size, filename="output", rate=10, byteorder="bgra") :
|
|
||||||
# self.size = size
|
|
||||||
# cmdstring = [
|
|
||||||
# 'mencoder',
|
|
||||||
# '/dev/stdin',
|
|
||||||
# '-demuxer', 'rawvideo',
|
|
||||||
# '-rawvideo', 'w=%i:h=%i'%size[::-1]+":fps=%i:format=%s"%(rate,byteorder),
|
|
||||||
# '-o', filename+'.mp4',
|
|
||||||
# '-ovc', 'lavc',
|
|
||||||
# ]
|
|
||||||
# self.p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE, shell=False)
|
|
||||||
|
|
||||||
# def run(self, image):
|
|
||||||
# """
|
|
||||||
# Image comes in as HEIGHTxWIDTHx3 numpy array, order rgb
|
|
||||||
# """
|
|
||||||
# assert image.shape == self.size + (3,)
|
|
||||||
# r, g, b = [image[:,:,i].astype('uint32') for i in range(3)]
|
|
||||||
# a = np.ones(image.shape[:2], dtype = 'uint32')
|
|
||||||
# #hacky
|
|
||||||
# image = sum([
|
|
||||||
# arr << 8**i
|
|
||||||
# for arr, i in zip(range(4), [a, r, g, b])
|
|
||||||
# ])
|
|
||||||
# self.p.stdin.write(image.tostring())
|
|
||||||
|
|
||||||
# def close(self):
|
|
||||||
# self.p.stdin.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,6 +196,7 @@ class NumberPlane(Mobject1D):
|
|||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
color = self.color
|
color = self.color
|
||||||
faded = Color(rgb = self.fade_factor*np.array(color.get_rgb()))
|
faded = Color(rgb = self.fade_factor*np.array(color.get_rgb()))
|
||||||
|
#Vertical Lines
|
||||||
freq_color_pairs = [
|
freq_color_pairs = [
|
||||||
(self.x_faded_line_frequency, faded),
|
(self.x_faded_line_frequency, faded),
|
||||||
(self.x_line_frequency, color)
|
(self.x_line_frequency, color)
|
||||||
|
@ -16,10 +16,10 @@ from script_wrapper import command_line_create_scene
|
|||||||
|
|
||||||
class SampleScene(Scene):
|
class SampleScene(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
plane = NumberPlane()
|
circle = Circle().repeat(6)
|
||||||
arrow1 = Arrow(ORIGIN, UP, color = "green", point_thickness = 5)
|
self.play(Transform(circle, Square(), run_time = 3))
|
||||||
arrow2 = Arrow(ORIGIN, LEFT, color = "Red")
|
self.dither()
|
||||||
self.add(plane, arrow1, arrow2)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
command_line_create_scene()
|
command_line_create_scene()
|
@ -51,6 +51,7 @@ class Scene(object):
|
|||||||
return self.name
|
return self.name
|
||||||
return self.__class__.__name__ + \
|
return self.__class__.__name__ + \
|
||||||
self.args_to_string(*self.construct_args)
|
self.args_to_string(*self.construct_args)
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
return self
|
return self
|
||||||
|
@ -3,6 +3,7 @@ import getopt
|
|||||||
import imp
|
import imp
|
||||||
import itertools as it
|
import itertools as it
|
||||||
import inspect
|
import inspect
|
||||||
|
import traceback
|
||||||
from helpers import cammel_case_initials
|
from helpers import cammel_case_initials
|
||||||
from scene import Scene
|
from scene import Scene
|
||||||
|
|
||||||
@ -58,8 +59,8 @@ def get_configuration(sys_argv):
|
|||||||
config["write_all"] = True
|
config["write_all"] = True
|
||||||
config["quiet"] = True
|
config["quiet"] = True
|
||||||
#By default, write to file
|
#By default, write to file
|
||||||
actions = set(["write", "preview", "save_image"])
|
actions = ["write", "preview", "save_image"]
|
||||||
if len(actions.intersection(config)) == 0:
|
if not any([config[key] for key in actions]):
|
||||||
config["write"] = True
|
config["write"] = True
|
||||||
|
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
@ -78,13 +79,15 @@ def handle_scene(scene, **config):
|
|||||||
if config["write"]:
|
if config["write"]:
|
||||||
scene.write_to_movie(os.path.join(config["movie_prefix"], name))
|
scene.write_to_movie(os.path.join(config["movie_prefix"], name))
|
||||||
if config["save_image"]:
|
if config["save_image"]:
|
||||||
scene.show_frame()
|
if not config["write_all"]:
|
||||||
|
scene.show_frame()
|
||||||
path = os.path.join(MOVIE_DIR, config["movie_prefix"], "images")
|
path = os.path.join(MOVIE_DIR, config["movie_prefix"], "images")
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
scene.save_image(path, name)
|
scene.save_image(path, name)
|
||||||
|
|
||||||
if config["quiet"]:
|
if config["quiet"]:
|
||||||
|
sys.stdout.close()
|
||||||
sys.stdout = curr_stdout
|
sys.stdout = curr_stdout
|
||||||
|
|
||||||
def prompt_user_for_args(SceneClass):
|
def prompt_user_for_args(SceneClass):
|
||||||
@ -143,7 +146,14 @@ def command_line_create_scene(movie_prefix = ""):
|
|||||||
if type(args) is not tuple:
|
if type(args) is not tuple:
|
||||||
args = (args,)
|
args = (args,)
|
||||||
scene_kwargs["construct_args"] = args
|
scene_kwargs["construct_args"] = args
|
||||||
handle_scene(SceneClass(**scene_kwargs), **config)
|
try:
|
||||||
|
handle_scene(SceneClass(**scene_kwargs), **config)
|
||||||
|
except:
|
||||||
|
print "\n\n"
|
||||||
|
traceback.print_exc()
|
||||||
|
print "\n\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ from script_wrapper import command_line_create_scene
|
|||||||
|
|
||||||
MOVIE_PREFIX = "matrix_as_transform_2d/"
|
MOVIE_PREFIX = "matrix_as_transform_2d/"
|
||||||
|
|
||||||
|
ARROW_CONFIG = {"point_thickness" : 2*DEFAULT_POINT_THICKNESS}
|
||||||
|
LIGHT_RED = "#F40"
|
||||||
|
|
||||||
def matrix_to_string(matrix):
|
def matrix_to_string(matrix):
|
||||||
return "--".join(["-".join(map(str, row)) for row in matrix])
|
return "--".join(["-".join(map(str, row)) for row in matrix])
|
||||||
|
|
||||||
@ -44,9 +47,21 @@ class ShowMultiplication(NumberLineScene):
|
|||||||
def args_to_string(num, show_original_line):
|
def args_to_string(num, show_original_line):
|
||||||
end_string = "WithCopiedOriginalLine" if show_original_line else ""
|
end_string = "WithCopiedOriginalLine" if show_original_line else ""
|
||||||
return str(num) + end_string
|
return str(num) + end_string
|
||||||
|
@staticmethod
|
||||||
|
def string_to_args(string):
|
||||||
|
parts = string.split()
|
||||||
|
if len(parts) == 2:
|
||||||
|
num, original_line = parts
|
||||||
|
show_original_line = original_line == "WithCopiedOriginalLine"
|
||||||
|
return float(num), False
|
||||||
|
else:
|
||||||
|
return float(parts[0]), False
|
||||||
|
|
||||||
def construct(self, num, show_original_line):
|
def construct(self, num, show_original_line):
|
||||||
config = {"density" : abs(num)*DEFAULT_POINT_DENSITY_1D}
|
config = {
|
||||||
|
"density" : abs(num)*DEFAULT_POINT_DENSITY_1D,
|
||||||
|
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||||
|
}
|
||||||
if abs(num) < 1:
|
if abs(num) < 1:
|
||||||
config["numerical_radius"] = SPACE_WIDTH/num
|
config["numerical_radius"] = SPACE_WIDTH/num
|
||||||
|
|
||||||
@ -54,7 +69,7 @@ class ShowMultiplication(NumberLineScene):
|
|||||||
if show_original_line:
|
if show_original_line:
|
||||||
self.copy_original_line()
|
self.copy_original_line()
|
||||||
self.dither()
|
self.dither()
|
||||||
self.show_multiplication(num, run_time = 2.0)
|
self.show_multiplication(num, run_time = 1.5)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
def copy_original_line(self):
|
def copy_original_line(self):
|
||||||
@ -62,7 +77,7 @@ class ShowMultiplication(NumberLineScene):
|
|||||||
copied_num_mobs = deepcopy(self.number_mobs)
|
copied_num_mobs = deepcopy(self.number_mobs)
|
||||||
self.play(
|
self.play(
|
||||||
ApplyFunction(
|
ApplyFunction(
|
||||||
lambda m : m.shift(DOWN).highlight("green"),
|
lambda m : m.shift(DOWN).highlight("lightgreen"),
|
||||||
copied_line
|
copied_line
|
||||||
), *[
|
), *[
|
||||||
ApplyMethod(mob.shift, DOWN)
|
ApplyMethod(mob.shift, DOWN)
|
||||||
@ -90,7 +105,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
|
|||||||
def shift_zero((x, y, z)):
|
def shift_zero((x, y, z)):
|
||||||
return (2*x+4, y, z)
|
return (2*x+4, y, z)
|
||||||
self.nonlinear = text_mobject("Not a Linear Transform")
|
self.nonlinear = text_mobject("Not a Linear Transform")
|
||||||
self.nonlinear.highlight("red").to_edge(UP)
|
self.nonlinear.highlight(LIGHT_RED).to_edge(UP, buff = 1.5)
|
||||||
pairs = [
|
pairs = [
|
||||||
(sinx_plux_x, "numbers don't remain evenly spaced"),
|
(sinx_plux_x, "numbers don't remain evenly spaced"),
|
||||||
(shift_zero, "zero does not remain fixed")
|
(shift_zero, "zero does not remain fixed")
|
||||||
@ -104,7 +119,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
|
|||||||
self.clear()
|
self.clear()
|
||||||
self.add(self.nonlinear)
|
self.add(self.nonlinear)
|
||||||
NumberLineScene.construct(self)
|
NumberLineScene.construct(self)
|
||||||
words = text_mobject(explanation).highlight("red")
|
words = text_mobject(explanation).highlight(LIGHT_RED)
|
||||||
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
||||||
self.add(words)
|
self.add(words)
|
||||||
|
|
||||||
@ -136,7 +151,6 @@ class ShowTwoThenThree(ShowMultiplication):
|
|||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
class TransformScene2D(Scene):
|
class TransformScene2D(Scene):
|
||||||
@ -144,7 +158,8 @@ class TransformScene2D(Scene):
|
|||||||
config = {
|
config = {
|
||||||
"x_radius" : 2*SPACE_WIDTH,
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
"y_radius" : 2*SPACE_HEIGHT,
|
"y_radius" : 2*SPACE_HEIGHT,
|
||||||
"density" : DEFAULT_POINT_DENSITY_1D*density_factor
|
"density" : DEFAULT_POINT_DENSITY_1D*density_factor,
|
||||||
|
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||||
}
|
}
|
||||||
if not use_faded_lines:
|
if not use_faded_lines:
|
||||||
config["x_faded_line_frequency"] = None
|
config["x_faded_line_frequency"] = None
|
||||||
@ -153,20 +168,22 @@ class TransformScene2D(Scene):
|
|||||||
self.add(self.number_plane)
|
self.add(self.number_plane)
|
||||||
|
|
||||||
def add_background(self):
|
def add_background(self):
|
||||||
self.paint_into_background(
|
grey_plane = NumberPlane(color = "grey")
|
||||||
NumberPlane(color = "grey").add_coordinates()
|
num_mobs = grey_plane.get_coordinate_labels()
|
||||||
)
|
self.paint_into_background(grey_plane, *num_mobs)
|
||||||
|
|
||||||
def add_x_y_arrows(self):
|
def add_x_y_arrows(self):
|
||||||
self.x_arrow = Arrow(
|
self.x_arrow = Arrow(
|
||||||
ORIGIN,
|
ORIGIN,
|
||||||
self.number_plane.num_pair_to_point((1, 0)),
|
self.number_plane.num_pair_to_point((1, 0)),
|
||||||
color = "green"
|
color = "lightgreen",
|
||||||
|
**ARROW_CONFIG
|
||||||
)
|
)
|
||||||
self.y_arrow = Arrow(
|
self.y_arrow = Arrow(
|
||||||
ORIGIN,
|
ORIGIN,
|
||||||
self.number_plane.num_pair_to_point((0, 1)),
|
self.number_plane.num_pair_to_point((0, 1)),
|
||||||
color = "red"
|
color = LIGHT_RED,
|
||||||
|
**ARROW_CONFIG
|
||||||
)
|
)
|
||||||
self.add(self.x_arrow, self.y_arrow)
|
self.add(self.x_arrow, self.y_arrow)
|
||||||
self.number_plane.filter_out(
|
self.number_plane.filter_out(
|
||||||
@ -180,6 +197,8 @@ class TransformScene2D(Scene):
|
|||||||
|
|
||||||
class ShowMatrixTransform(TransformScene2D):
|
class ShowMatrixTransform(TransformScene2D):
|
||||||
args_list = [
|
args_list = [
|
||||||
|
([[1, 3], [-2, 0]], False, False),
|
||||||
|
([[1, 3], [-2, 0]], True, False),
|
||||||
([[1, 0.5], [0.5, 1]], True, False),
|
([[1, 0.5], [0.5, 1]], True, False),
|
||||||
([[2, 0], [0, 2]], True, False),
|
([[2, 0], [0, 2]], True, False),
|
||||||
([[0.5, 0], [0, 0.5]], True, False),
|
([[0.5, 0], [0, 0.5]], True, False),
|
||||||
@ -223,7 +242,8 @@ class ShowMatrixTransform(TransformScene2D):
|
|||||||
new_arrow = Arrow(
|
new_arrow = Arrow(
|
||||||
ORIGIN,
|
ORIGIN,
|
||||||
self.number_plane.num_pair_to_point(matrix[:,index]),
|
self.number_plane.num_pair_to_point(matrix[:,index]),
|
||||||
color = arrow.get_color()
|
color = arrow.get_color(),
|
||||||
|
**ARROW_CONFIG
|
||||||
)
|
)
|
||||||
arrow.remove_tip()
|
arrow.remove_tip()
|
||||||
new_arrow.remove_tip()
|
new_arrow.remove_tip()
|
||||||
@ -233,8 +253,6 @@ class ShowMatrixTransform(TransformScene2D):
|
|||||||
anims.append(Transform(arrow, new_arrow, **kwargs))
|
anims.append(Transform(arrow, new_arrow, **kwargs))
|
||||||
self.play(*anims)
|
self.play(*anims)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.set_name(str(self) + self.args_to_string(matrix, with_background, show_matrix))
|
|
||||||
self.save_image(os.path.join(MOVIE_DIR, MOVIE_PREFIX, "images"))
|
|
||||||
|
|
||||||
def get_density_factor(self, matrix):
|
def get_density_factor(self, matrix):
|
||||||
max_norm = max([
|
max_norm = max([
|
||||||
@ -288,7 +306,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
|||||||
def shift_zero((x, y, z)):
|
def shift_zero((x, y, z)):
|
||||||
return (2*x + 3*y + 4, -1*x+y+2, z)
|
return (2*x + 3*y + 4, -1*x+y+2, z)
|
||||||
self.nonlinear = text_mobject("Nonlinear Transform")
|
self.nonlinear = text_mobject("Nonlinear Transform")
|
||||||
self.nonlinear.highlight("red").to_edge(UP)
|
self.nonlinear.highlight(LIGHT_RED).to_edge(UP, buff = 1.5)
|
||||||
pairs = [
|
pairs = [
|
||||||
(squiggle, "lines to not remain straight"),
|
(squiggle, "lines to not remain straight"),
|
||||||
(shift_zero, "the origin does not remain fixed")
|
(shift_zero, "the origin does not remain fixed")
|
||||||
@ -305,7 +323,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
|||||||
density = 3*DEFAULT_POINT_DENSITY_1D,
|
density = 3*DEFAULT_POINT_DENSITY_1D,
|
||||||
)
|
)
|
||||||
numbers = number_plane.get_coordinate_labels()
|
numbers = number_plane.get_coordinate_labels()
|
||||||
words = text_mobject(explanation).highlight("red")
|
words = text_mobject(explanation).highlight(LIGHT_RED)
|
||||||
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
||||||
|
|
||||||
self.add(number_plane, self.nonlinear, words, *numbers)
|
self.add(number_plane, self.nonlinear, words, *numbers)
|
||||||
@ -330,8 +348,8 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
|||||||
phrase1, phrase2 = text_mobject([
|
phrase1, phrase2 = text_mobject([
|
||||||
"These might look like they keep lines straight...",
|
"These might look like they keep lines straight...",
|
||||||
"but diagonal lines get curved"
|
"but diagonal lines get curved"
|
||||||
]).to_edge(UP).split()
|
]).to_edge(UP, buff = 1.5).split()
|
||||||
phrase2.highlight("red")
|
phrase2.highlight(LIGHT_RED)
|
||||||
diagonal = Line(
|
diagonal = Line(
|
||||||
DOWN*SPACE_HEIGHT+LEFT*SPACE_WIDTH,
|
DOWN*SPACE_HEIGHT+LEFT*SPACE_WIDTH,
|
||||||
UP*SPACE_HEIGHT+RIGHT*SPACE_WIDTH
|
UP*SPACE_HEIGHT+RIGHT*SPACE_WIDTH
|
||||||
@ -363,7 +381,7 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
|||||||
|
|
||||||
|
|
||||||
############# HORRIBLE! ##########################
|
############# HORRIBLE! ##########################
|
||||||
class ShowMatrixTransformHack(TransformScene2D):
|
class ShowMatrixTransformWithDot(TransformScene2D):
|
||||||
args_list = [
|
args_list = [
|
||||||
([[1, 3], [-2, 0]], True, False),
|
([[1, 3], [-2, 0]], True, False),
|
||||||
]
|
]
|
||||||
@ -392,7 +410,7 @@ class ShowMatrixTransformHack(TransformScene2D):
|
|||||||
return mobject
|
return mobject
|
||||||
dot = Dot((-1, 2, 0), color = "yellow")
|
dot = Dot((-1, 2, 0), color = "yellow")
|
||||||
x_arrow_copy = deepcopy(self.x_arrow)
|
x_arrow_copy = deepcopy(self.x_arrow)
|
||||||
y_arrow_copy = Arrow(LEFT, LEFT+2*UP, color = "red")
|
y_arrow_copy = Arrow(LEFT, LEFT+2*UP, color = LIGHT_RED, **ARROW_CONFIG)
|
||||||
|
|
||||||
self.number_plane.add(dot)
|
self.number_plane.add(dot)
|
||||||
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
||||||
@ -409,7 +427,8 @@ class ShowMatrixTransformHack(TransformScene2D):
|
|||||||
new_arrow = Arrow(
|
new_arrow = Arrow(
|
||||||
ORIGIN,
|
ORIGIN,
|
||||||
self.number_plane.num_pair_to_point(matrix[:,index]),
|
self.number_plane.num_pair_to_point(matrix[:,index]),
|
||||||
color = arrow.get_color()
|
color = arrow.get_color(),
|
||||||
|
**ARROW_CONFIG
|
||||||
)
|
)
|
||||||
arrow.remove_tip()
|
arrow.remove_tip()
|
||||||
new_arrow.remove_tip()
|
new_arrow.remove_tip()
|
||||||
@ -421,7 +440,7 @@ class ShowMatrixTransformHack(TransformScene2D):
|
|||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
x_arrow_copy = deepcopy(self.x_arrow)
|
x_arrow_copy = deepcopy(self.x_arrow)
|
||||||
y_arrow_copy = Arrow(LEFT+2*UP, 5*RIGHT+2*UP, color = "red")
|
y_arrow_copy = Arrow(LEFT+2*UP, 5*RIGHT+2*UP, color = LIGHT_RED, **ARROW_CONFIG)
|
||||||
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
||||||
self.play(ShowCreation(y_arrow_copy))
|
self.play(ShowCreation(y_arrow_copy))
|
||||||
self.remove(x_arrow_copy, y_arrow_copy)
|
self.remove(x_arrow_copy, y_arrow_copy)
|
||||||
|
Reference in New Issue
Block a user