mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Merge branch 'master' of https://github.com/3b1b/manim
This commit is contained in:
commit
80dda4eb28
20 changed files with 7962 additions and 4428 deletions
|
@ -82,12 +82,10 @@ class Write(ShowCreation):
|
||||||
|
|
||||||
def establish_run_time(self, mobject):
|
def establish_run_time(self, mobject):
|
||||||
num_subs = len(mobject.family_members_with_points())
|
num_subs = len(mobject.family_members_with_points())
|
||||||
if num_subs < 5:
|
if num_subs < 15:
|
||||||
self.run_time = 1
|
self.run_time = 1
|
||||||
elif num_subs < 15:
|
|
||||||
self.run_time = 2
|
|
||||||
else:
|
else:
|
||||||
self.run_time = 3
|
self.run_time = 2
|
||||||
|
|
||||||
class DrawBorderThenFill(Animation):
|
class DrawBorderThenFill(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
@ -330,9 +328,9 @@ class LaggedStart(Animation):
|
||||||
anim.update(alpha)
|
anim.update(alpha)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
# def clean_up(self, *args, **kwargs):
|
def clean_up(self, *args, **kwargs):
|
||||||
# for anim in self.subanimations:
|
for anim in self.subanimations:
|
||||||
# anim.clean_up(*args, **kwargs)
|
anim.clean_up(*args, **kwargs)
|
||||||
|
|
||||||
class DelayByOrder(Animation):
|
class DelayByOrder(Animation):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -59,7 +59,8 @@ class Transform(Animation):
|
||||||
Animation.clean_up(self, surrounding_scene)
|
Animation.clean_up(self, surrounding_scene)
|
||||||
if self.replace_mobject_with_target_in_scene and surrounding_scene is not None:
|
if self.replace_mobject_with_target_in_scene and surrounding_scene is not None:
|
||||||
surrounding_scene.remove(self.mobject)
|
surrounding_scene.remove(self.mobject)
|
||||||
surrounding_scene.add(self.original_target_mobject)
|
if not self.remover:
|
||||||
|
surrounding_scene.add(self.original_target_mobject)
|
||||||
|
|
||||||
class ReplacementTransform(Transform):
|
class ReplacementTransform(Transform):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
|
10
camera.py
10
camera.py
|
@ -141,15 +141,21 @@ class Camera(object):
|
||||||
|
|
||||||
def get_pen_and_fill(self, vmobject):
|
def get_pen_and_fill(self, vmobject):
|
||||||
pen = aggdraw.Pen(
|
pen = aggdraw.Pen(
|
||||||
self.get_stroke_color(vmobject).get_hex_l(),
|
self.color_to_hex_l(self.get_stroke_color(vmobject)),
|
||||||
max(vmobject.stroke_width, 0)
|
max(vmobject.stroke_width, 0)
|
||||||
)
|
)
|
||||||
fill = aggdraw.Brush(
|
fill = aggdraw.Brush(
|
||||||
self.get_fill_color(vmobject).get_hex_l(),
|
self.color_to_hex_l(self.get_fill_color(vmobject)),
|
||||||
opacity = int(255*vmobject.get_fill_opacity())
|
opacity = int(255*vmobject.get_fill_opacity())
|
||||||
)
|
)
|
||||||
return (pen, fill)
|
return (pen, fill)
|
||||||
|
|
||||||
|
def color_to_hex_l(self, color):
|
||||||
|
try:
|
||||||
|
return color.get_hex_l()
|
||||||
|
except:
|
||||||
|
return Color(BLACK).get_hex_l()
|
||||||
|
|
||||||
def get_stroke_color(self, vmobject):
|
def get_stroke_color(self, vmobject):
|
||||||
return vmobject.get_stroke_color()
|
return vmobject.get_stroke_color()
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ DEFAULT_WIDTH = 1920
|
||||||
|
|
||||||
LOW_QUALITY_FRAME_DURATION = 1./15
|
LOW_QUALITY_FRAME_DURATION = 1./15
|
||||||
MEDIUM_QUALITY_FRAME_DURATION = 1./30
|
MEDIUM_QUALITY_FRAME_DURATION = 1./30
|
||||||
# PRODUCTION_QUALITY_FRAME_DURATION = 1./60
|
PRODUCTION_QUALITY_FRAME_DURATION = 1./60
|
||||||
PRODUCTION_QUALITY_FRAME_DURATION = 1./30
|
|
||||||
|
|
||||||
#There might be other configuration than pixel_shape later...
|
#There might be other configuration than pixel_shape later...
|
||||||
PRODUCTION_QUALITY_CAMERA_CONFIG = {
|
PRODUCTION_QUALITY_CAMERA_CONFIG = {
|
||||||
|
|
|
@ -37,7 +37,6 @@ def play_chord(*nums):
|
||||||
def play_error_sound():
|
def play_error_sound():
|
||||||
play_chord(11, 8, 6, 1)
|
play_chord(11, 8, 6, 1)
|
||||||
|
|
||||||
|
|
||||||
def play_finish_sound():
|
def play_finish_sound():
|
||||||
play_chord(12, 9, 5, 2)
|
play_chord(12, 9, 5, 2)
|
||||||
|
|
||||||
|
@ -422,7 +421,7 @@ def get_full_image_path(image_file_name):
|
||||||
for path in possible_paths:
|
for path in possible_paths:
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return path
|
return path
|
||||||
raise IOError("File not Found")
|
raise IOError("File %s not Found"%image_file_name)
|
||||||
|
|
||||||
def drag_pixels(frames):
|
def drag_pixels(frames):
|
||||||
curr = frames[0]
|
curr = frames[0]
|
||||||
|
|
|
@ -399,11 +399,17 @@ class Mobject(object):
|
||||||
|
|
||||||
## Color functions
|
## Color functions
|
||||||
|
|
||||||
def highlight(self, color = YELLOW_C, family = True, condition = None):
|
def highlight(self, color = YELLOW_C, family = True):
|
||||||
"""
|
"""
|
||||||
Condition is function which takes in one arguments, (x, y, z).
|
Condition is function which takes in one arguments, (x, y, z).
|
||||||
|
Here it just recurses to submobjects, but in subclasses this
|
||||||
|
should be further implemented based on the the inner workings
|
||||||
|
of color
|
||||||
"""
|
"""
|
||||||
raise Exception("Not implemented")
|
if family:
|
||||||
|
for submob in self.submobjects:
|
||||||
|
submob.highlight(color, family = family)
|
||||||
|
return self
|
||||||
|
|
||||||
def gradient_highlight(self, *colors):
|
def gradient_highlight(self, *colors):
|
||||||
self.submobject_gradient_highlight(*colors)
|
self.submobject_gradient_highlight(*colors)
|
||||||
|
@ -446,11 +452,14 @@ class Mobject(object):
|
||||||
return self.color
|
return self.color
|
||||||
##
|
##
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self, use_deepcopy = False):
|
||||||
if hasattr(self, "saved_state"):
|
if hasattr(self, "saved_state"):
|
||||||
#Prevent exponential growth of data
|
#Prevent exponential growth of data
|
||||||
self.saved_state = None
|
self.saved_state = None
|
||||||
self.saved_state = self.copy()
|
if use_deepcopy:
|
||||||
|
self.saved_state = self.deepcopy()
|
||||||
|
else:
|
||||||
|
self.saved_state = self.copy()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def restore(self):
|
def restore(self):
|
||||||
|
|
|
@ -30,15 +30,11 @@ class PMobject(Mobject):
|
||||||
self.rgbas = np.append(self.rgbas, rgbas, axis = 0)
|
self.rgbas = np.append(self.rgbas, rgbas, axis = 0)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def highlight(self, color = YELLOW_C, family = True, condition = None):
|
def highlight(self, color = YELLOW_C, family = True):
|
||||||
rgba = color_to_rgba(color)
|
rgba = color_to_rgba(color)
|
||||||
mobs = self.family_members_with_points() if family else [self]
|
mobs = self.family_members_with_points() if family else [self]
|
||||||
for mob in mobs:
|
for mob in mobs:
|
||||||
if condition:
|
mob.rgbas[:,:] = rgba
|
||||||
to_change = np.apply_along_axis(condition, 1, mob.points)
|
|
||||||
mob.rgbas[to_change, :] = rgba
|
|
||||||
else:
|
|
||||||
mob.rgbas[:,:] = rgba
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def gradient_highlight(self, start_color, end_color):
|
def gradient_highlight(self, start_color, end_color):
|
||||||
|
|
|
@ -26,7 +26,6 @@ class TexSymbol(VMobjectFromSVGPathstring):
|
||||||
self.set_stroke(width = added_width + mobject.get_stroke_width())
|
self.set_stroke(width = added_width + mobject.get_stroke_width())
|
||||||
self.set_fill(opacity = opacity)
|
self.set_fill(opacity = opacity)
|
||||||
|
|
||||||
|
|
||||||
class TexMobject(SVGMobject):
|
class TexMobject(SVGMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"template_tex_file" : TEMPLATE_TEX_FILE,
|
"template_tex_file" : TEMPLATE_TEX_FILE,
|
||||||
|
@ -264,6 +263,43 @@ class Brace(TexMobject):
|
||||||
vect = self.get_tip() - self.get_center()
|
vect = self.get_tip() - self.get_center()
|
||||||
return vect/np.linalg.norm(vect)
|
return vect/np.linalg.norm(vect)
|
||||||
|
|
||||||
|
class BulletedList(TextMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"buff" : MED_LARGE_BUFF,
|
||||||
|
"dot_scale_factor" : 2,
|
||||||
|
#Have to include because of handle_multiple_args implementation
|
||||||
|
"template_tex_file" : TEMPLATE_TEXT_FILE,
|
||||||
|
"alignment" : "",
|
||||||
|
}
|
||||||
|
def __init__(self, *items, **kwargs):
|
||||||
|
line_separated_items = [s + "\\\\" for s in items]
|
||||||
|
TextMobject.__init__(self, *line_separated_items, **kwargs)
|
||||||
|
for part in self:
|
||||||
|
dot = TexMobject("\\cdot").scale(self.dot_scale_factor)
|
||||||
|
dot.next_to(part[0], LEFT, SMALL_BUFF)
|
||||||
|
part.add_to_back(dot)
|
||||||
|
self.arrange_submobjects(
|
||||||
|
DOWN,
|
||||||
|
aligned_edge = LEFT,
|
||||||
|
buff = self.buff
|
||||||
|
)
|
||||||
|
|
||||||
|
def fade_all_but(self, index_or_string, opacity = 0.5):
|
||||||
|
arg = index_or_string
|
||||||
|
if isinstance(arg, str):
|
||||||
|
part = self.get_part_by_tex(arg)
|
||||||
|
elif isinstance(arg, int):
|
||||||
|
part = self.submobjects[arg]
|
||||||
|
else:
|
||||||
|
raise Exception("Expected int or string, got {0}".format(arg))
|
||||||
|
for other_part in self.submobjects:
|
||||||
|
if other_part is part:
|
||||||
|
other_part.set_fill(opacity = 1)
|
||||||
|
else:
|
||||||
|
other_part.set_fill(opacity = opacity)
|
||||||
|
|
||||||
|
##########
|
||||||
|
|
||||||
def tex_hash(expression, template_tex_file):
|
def tex_hash(expression, template_tex_file):
|
||||||
return str(hash(expression + template_tex_file))
|
return str(hash(expression + template_tex_file))
|
||||||
|
|
||||||
|
|
|
@ -97,13 +97,13 @@ class VMobject(Mobject):
|
||||||
|
|
||||||
def get_fill_color(self):
|
def get_fill_color(self):
|
||||||
try:
|
try:
|
||||||
self.fill_rgb = np.clip(self.fill_rgb, 0, 1)
|
self.fill_rgb = np.clip(self.fill_rgb, 0.0, 1.0)
|
||||||
return Color(rgb = self.fill_rgb)
|
return Color(rgb = self.fill_rgb)
|
||||||
except:
|
except:
|
||||||
return Color(WHITE)
|
return Color(WHITE)
|
||||||
|
|
||||||
def get_fill_opacity(self):
|
def get_fill_opacity(self):
|
||||||
return self.fill_opacity
|
return np.clip(self.fill_opacity, 0, 1)
|
||||||
|
|
||||||
def get_stroke_color(self):
|
def get_stroke_color(self):
|
||||||
try:
|
try:
|
||||||
|
@ -113,7 +113,7 @@ class VMobject(Mobject):
|
||||||
return Color(WHITE)
|
return Color(WHITE)
|
||||||
|
|
||||||
def get_stroke_width(self):
|
def get_stroke_width(self):
|
||||||
return self.stroke_width
|
return max(0, self.stroke_width)
|
||||||
|
|
||||||
def get_color(self):
|
def get_color(self):
|
||||||
if self.fill_opacity == 0:
|
if self.fill_opacity == 0:
|
||||||
|
|
|
@ -21,12 +21,12 @@ import cPickle
|
||||||
from nn.mnist_loader import load_data_wrapper
|
from nn.mnist_loader import load_data_wrapper
|
||||||
|
|
||||||
NN_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
|
NN_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
|
||||||
# PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases_36")
|
# PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases_80")
|
||||||
# PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases_ReLU")
|
# PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases_ReLU")
|
||||||
PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases")
|
PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases")
|
||||||
IMAGE_MAP_DATA_FILE = os.path.join(NN_DIRECTORY, "image_map")
|
IMAGE_MAP_DATA_FILE = os.path.join(NN_DIRECTORY, "image_map")
|
||||||
# PRETRAINED_DATA_FILE = "/Users/grant/cs/manim/nn/pretrained_weights_and_biases_on_zero"
|
# PRETRAINED_DATA_FILE = "/Users/grant/cs/manim/nn/pretrained_weights_and_biases_on_zero"
|
||||||
# DEFAULT_LAYER_SIZES = [28**2, 36, 10]
|
# DEFAULT_LAYER_SIZES = [28**2, 80, 10]
|
||||||
DEFAULT_LAYER_SIZES = [28**2, 16, 16, 10]
|
DEFAULT_LAYER_SIZES = [28**2, 16, 16, 10]
|
||||||
|
|
||||||
class Network(object):
|
class Network(object):
|
||||||
|
|
31
nn/part1.py
31
nn/part1.py
|
@ -122,7 +122,7 @@ class NetworkMobject(VGroup):
|
||||||
"neuron_fill_color" : GREEN,
|
"neuron_fill_color" : GREEN,
|
||||||
"edge_color" : LIGHT_GREY,
|
"edge_color" : LIGHT_GREY,
|
||||||
"edge_stroke_width" : 2,
|
"edge_stroke_width" : 2,
|
||||||
"edge_propogation_color" : GREEN,
|
"edge_propogation_color" : YELLOW,
|
||||||
"edge_propogation_time" : 1,
|
"edge_propogation_time" : 1,
|
||||||
"max_shown_neurons" : 16,
|
"max_shown_neurons" : 16,
|
||||||
"brace_for_large_layers" : True,
|
"brace_for_large_layers" : True,
|
||||||
|
@ -196,21 +196,28 @@ class NetworkMobject(VGroup):
|
||||||
for l1, l2 in zip(self.layers[:-1], self.layers[1:]):
|
for l1, l2 in zip(self.layers[:-1], self.layers[1:]):
|
||||||
edge_group = VGroup()
|
edge_group = VGroup()
|
||||||
for n1, n2 in it.product(l1.neurons, l2.neurons):
|
for n1, n2 in it.product(l1.neurons, l2.neurons):
|
||||||
edge = Line(
|
edge = self.get_edge(n1, n2)
|
||||||
n1.get_center(),
|
|
||||||
n2.get_center(),
|
|
||||||
buff = self.neuron_radius,
|
|
||||||
stroke_color = self.edge_color,
|
|
||||||
stroke_width = self.edge_stroke_width,
|
|
||||||
)
|
|
||||||
edge_group.add(edge)
|
edge_group.add(edge)
|
||||||
n1.edges_out.add(edge)
|
n1.edges_out.add(edge)
|
||||||
n2.edges_in.add(edge)
|
n2.edges_in.add(edge)
|
||||||
self.edge_groups.add(edge_group)
|
self.edge_groups.add(edge_group)
|
||||||
self.add_to_back(self.edge_groups)
|
self.add_to_back(self.edge_groups)
|
||||||
|
|
||||||
|
def get_edge(self, neuron1, neuron2):
|
||||||
|
return Line(
|
||||||
|
neuron1.get_center(),
|
||||||
|
neuron2.get_center(),
|
||||||
|
buff = self.neuron_radius,
|
||||||
|
stroke_color = self.edge_color,
|
||||||
|
stroke_width = self.edge_stroke_width,
|
||||||
|
)
|
||||||
|
|
||||||
def get_active_layer(self, layer_index, activation_vector):
|
def get_active_layer(self, layer_index, activation_vector):
|
||||||
layer = self.layers[layer_index].deepcopy()
|
layer = self.layers[layer_index].deepcopy()
|
||||||
|
self.activate_layer(layer, activation_vector)
|
||||||
|
return layer
|
||||||
|
|
||||||
|
def activate_layer(self, layer, activation_vector):
|
||||||
n_neurons = len(layer.neurons)
|
n_neurons = len(layer.neurons)
|
||||||
av = activation_vector
|
av = activation_vector
|
||||||
def arr_to_num(arr):
|
def arr_to_num(arr):
|
||||||
|
@ -238,6 +245,11 @@ class NetworkMobject(VGroup):
|
||||||
)
|
)
|
||||||
return layer
|
return layer
|
||||||
|
|
||||||
|
def activate_layers(self, input_vector):
|
||||||
|
activations = self.neural_network.get_activation_of_all_layers(input_vector)
|
||||||
|
for activation, layer in zip(activations, self.layers):
|
||||||
|
self.activate_layer(layer, activation)
|
||||||
|
|
||||||
def deactivate_layers(self):
|
def deactivate_layers(self):
|
||||||
all_neurons = VGroup(*it.chain(*[
|
all_neurons = VGroup(*it.chain(*[
|
||||||
layer.neurons
|
layer.neurons
|
||||||
|
@ -2980,6 +2992,7 @@ class ContinualEdgeUpdate(ContinualAnimation):
|
||||||
"max_stroke_width" : 3,
|
"max_stroke_width" : 3,
|
||||||
"stroke_width_exp" : 7,
|
"stroke_width_exp" : 7,
|
||||||
"n_cycles" : 5,
|
"n_cycles" : 5,
|
||||||
|
"colors" : [GREEN, GREEN, GREEN, RED],
|
||||||
}
|
}
|
||||||
def __init__(self, network_mob, **kwargs):
|
def __init__(self, network_mob, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
@ -2988,7 +3001,7 @@ class ContinualEdgeUpdate(ContinualAnimation):
|
||||||
self.move_to_targets = []
|
self.move_to_targets = []
|
||||||
for edge in edges:
|
for edge in edges:
|
||||||
edge.colors = [
|
edge.colors = [
|
||||||
random.choice([GREEN, GREEN, GREEN, RED])
|
random.choice(self.colors)
|
||||||
for x in range(n_cycles)
|
for x in range(n_cycles)
|
||||||
]
|
]
|
||||||
msw = self.max_stroke_width
|
msw = self.max_stroke_width
|
||||||
|
|
3340
nn/part2.py
3340
nn/part2.py
File diff suppressed because it is too large
Load diff
4519
nn/part3.py
Normal file
4519
nn/part3.py
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
4248
nn/scenes.py
4248
nn/scenes.py
File diff suppressed because it is too large
Load diff
|
@ -61,6 +61,10 @@ class Scene(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def setup_bases(self):
|
||||||
|
for base in self.__class__.__bases__:
|
||||||
|
base.setup(self)
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass #To be implemented in subclasses
|
pass #To be implemented in subclasses
|
||||||
|
|
||||||
|
@ -71,20 +75,24 @@ class Scene(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def update_shared_locals(self, *keys):
|
def set_variables_as_attrs(self, *objects, **newly_named_objects):
|
||||||
"""
|
"""
|
||||||
Often in constructing a scene, it's nice to refer to
|
This method is slightly hacky, making it a little easier
|
||||||
what was a local variable from a previous subroutine,
|
for certain methods (typically subroutines of construct)
|
||||||
so a dict of shared_locals is recorded, and it can be updated
|
to share local variables.
|
||||||
by passing in the objects directly.
|
|
||||||
"""
|
"""
|
||||||
caller_locals = inspect.currentframe().f_back.f_locals
|
caller_locals = inspect.currentframe().f_back.f_locals
|
||||||
self.shared_locals.update(dict([
|
for key, value in caller_locals.items():
|
||||||
(key, caller_locals[key])
|
for o in objects:
|
||||||
for key in keys
|
if value is o:
|
||||||
]))
|
setattr(self, key, value)
|
||||||
|
for key, value in newly_named_objects.items():
|
||||||
|
setattr(self, key, value)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def get_attrs(self, *keys):
|
||||||
|
return [getattr(self, key) for key in keys]
|
||||||
|
|
||||||
### Only these methods should touch the camera
|
### Only these methods should touch the camera
|
||||||
|
|
||||||
def set_camera(self, camera):
|
def set_camera(self, camera):
|
||||||
|
@ -341,7 +349,7 @@ class Scene(object):
|
||||||
animations.pop()
|
animations.pop()
|
||||||
#method should already have target then.
|
#method should already have target then.
|
||||||
else:
|
else:
|
||||||
mobject.target = mobject.deepcopy()
|
mobject.target = mobject.copy()
|
||||||
state["curr_method"].im_func(
|
state["curr_method"].im_func(
|
||||||
mobject.target, *state["method_args"]
|
mobject.target, *state["method_args"]
|
||||||
)
|
)
|
||||||
|
@ -479,14 +487,14 @@ class Scene(object):
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
FFMPEG_BIN,
|
FFMPEG_BIN,
|
||||||
'-y', # overwrite output file if it exists
|
'-y', # overwrite output file if it exists
|
||||||
'-f', 'rawvideo',
|
'-f', 'rawvideo',
|
||||||
'-vcodec','rawvideo',
|
'-vcodec','rawvideo',
|
||||||
'-s', '%dx%d'%(width, height), # size of one frame
|
'-s', '%dx%d'%(width, height), # size of one frame
|
||||||
'-pix_fmt', 'rgba',
|
'-pix_fmt', 'rgba',
|
||||||
'-r', str(fps), # frames per second
|
'-r', str(fps), # frames per second
|
||||||
'-i', '-', # The imput comes from a pipe
|
'-i', '-', # The imput comes from a pipe
|
||||||
'-an', # Tells FFMPEG not to expect any audio
|
'-an', # Tells FFMPEG not to expect any audio
|
||||||
'-vcodec', 'mpeg',
|
'-vcodec', 'mpeg',
|
||||||
'-c:v', 'libx264',
|
'-c:v', 'libx264',
|
||||||
'-pix_fmt', 'yuv420p',
|
'-pix_fmt', 'yuv420p',
|
||||||
|
|
|
@ -276,7 +276,7 @@ class Eyes(VMobject):
|
||||||
|
|
||||||
pi = Randolph(mode = mode)
|
pi = Randolph(mode = mode)
|
||||||
eyes = VGroup(pi.eyes, pi.pupils)
|
eyes = VGroup(pi.eyes, pi.pupils)
|
||||||
eyes.scale_to_fit_height(self.height)
|
pi.scale(self.height/eyes.get_height())
|
||||||
if self.submobjects:
|
if self.submobjects:
|
||||||
eyes.move_to(self, DOWN)
|
eyes.move_to(self, DOWN)
|
||||||
else:
|
else:
|
||||||
|
@ -526,18 +526,17 @@ class PiCreatureScene(Scene):
|
||||||
lambda anim : pi_creature in anim.mobject.submobject_family(),
|
lambda anim : pi_creature in anim.mobject.submobject_family(),
|
||||||
animations
|
animations
|
||||||
)
|
)
|
||||||
if anims_with_pi_creature:
|
for anim in anims_with_pi_creature:
|
||||||
for anim in anims_with_pi_creature:
|
if isinstance(anim, Transform):
|
||||||
if isinstance(anim, Transform):
|
index = anim.mobject.submobject_family().index(pi_creature)
|
||||||
index = anim.mobject.submobject_family().index(pi_creature)
|
target_family = anim.target_mobject.submobject_family()
|
||||||
target_family = anim.target_mobject.submobject_family()
|
target = target_family[index]
|
||||||
target = target_family[index]
|
if isinstance(target, PiCreature):
|
||||||
if isinstance(target, PiCreature):
|
target.look_at(point_of_interest)
|
||||||
target.look_at(point_of_interest)
|
if not anims_with_pi_creature:
|
||||||
continue
|
animations.append(
|
||||||
animations.append(
|
ApplyMethod(pi_creature.look_at, point_of_interest)
|
||||||
ApplyMethod(pi_creature.look_at, point_of_interest)
|
)
|
||||||
)
|
|
||||||
return animations
|
return animations
|
||||||
|
|
||||||
def blink(self):
|
def blink(self):
|
||||||
|
|
|
@ -61,36 +61,7 @@ class OpeningQuote(Scene):
|
||||||
|
|
||||||
class PatreonThanks(Scene):
|
class PatreonThanks(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"specific_patrons" : [
|
"specific_patrons" : [],
|
||||||
"Ali Yahya",
|
|
||||||
"Meshal Alshammari",
|
|
||||||
"CrypticSwarm ",
|
|
||||||
"Justin Helps",
|
|
||||||
"Ankit Agarwal",
|
|
||||||
"Yu Jun",
|
|
||||||
"Shelby Doolittle",
|
|
||||||
"Dave Nicponski",
|
|
||||||
"Damion Kistler",
|
|
||||||
"Juan Benet",
|
|
||||||
"Othman Alikhan",
|
|
||||||
"Markus Persson",
|
|
||||||
"Dan Buchoff",
|
|
||||||
"Derek Dai",
|
|
||||||
"Joseph John Cox",
|
|
||||||
"Luc Ritchie",
|
|
||||||
"Nils Schneider",
|
|
||||||
"Mathew Bramson",
|
|
||||||
"Guido Gambardella",
|
|
||||||
"Jerry Ling",
|
|
||||||
"Mark Govea",
|
|
||||||
"Vecht",
|
|
||||||
"Shimin Kuang",
|
|
||||||
"Rish Kundalia",
|
|
||||||
"Achille Brighton",
|
|
||||||
"Kirk Werklund",
|
|
||||||
"Ripta Pasay",
|
|
||||||
"Felipe Diniz",
|
|
||||||
],
|
|
||||||
"max_patron_group_size" : 20,
|
"max_patron_group_size" : 20,
|
||||||
"patron_scale_val" : 0.8,
|
"patron_scale_val" : 0.8,
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,7 @@ class Line(VMobject):
|
||||||
def put_start_and_end_on(self, new_start, new_end):
|
def put_start_and_end_on(self, new_start, new_end):
|
||||||
self.start = new_start
|
self.start = new_start
|
||||||
self.end = new_end
|
self.end = new_end
|
||||||
|
self.buff = 0
|
||||||
self.generate_points()
|
self.generate_points()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -242,9 +243,13 @@ class Arrow(Line):
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
args = (points[0]+UP+LEFT, points[0])
|
args = (points[0]+UP+LEFT, points[0])
|
||||||
Line.__init__(self, *args, **kwargs)
|
Line.__init__(self, *args, **kwargs)
|
||||||
self.add_tip()
|
self.init_tip()
|
||||||
if self.use_rectangular_stem and not hasattr(self, "rect"):
|
if self.use_rectangular_stem and not hasattr(self, "rect"):
|
||||||
self.add_rectangular_stem()
|
self.add_rectangular_stem()
|
||||||
|
self.init_colors()
|
||||||
|
|
||||||
|
def init_tip(self):
|
||||||
|
self.tip = self.add_tip()
|
||||||
|
|
||||||
def add_tip(self, add_at_end = True):
|
def add_tip(self, add_at_end = True):
|
||||||
tip = VMobject(
|
tip = VMobject(
|
||||||
|
@ -253,11 +258,11 @@ class Arrow(Line):
|
||||||
fill_color = self.color,
|
fill_color = self.color,
|
||||||
fill_opacity = 1,
|
fill_opacity = 1,
|
||||||
stroke_color = self.color,
|
stroke_color = self.color,
|
||||||
|
stroke_width = 0,
|
||||||
)
|
)
|
||||||
self.set_tip_points(tip, add_at_end, preserve_normal = False)
|
self.set_tip_points(tip, add_at_end, preserve_normal = False)
|
||||||
self.tip = tip
|
self.add(tip)
|
||||||
self.add(self.tip)
|
return tip
|
||||||
self.init_colors()
|
|
||||||
|
|
||||||
def add_rectangular_stem(self):
|
def add_rectangular_stem(self):
|
||||||
self.rect = Rectangle(
|
self.rect = Rectangle(
|
||||||
|
@ -283,6 +288,10 @@ class Arrow(Line):
|
||||||
self.rectangular_stem_width,
|
self.rectangular_stem_width,
|
||||||
self.max_stem_width_to_tip_width_ratio*tip_base_width,
|
self.max_stem_width_to_tip_width_ratio*tip_base_width,
|
||||||
)
|
)
|
||||||
|
if hasattr(self, "second_tip"):
|
||||||
|
start = center_of_mass(
|
||||||
|
self.second_tip.get_anchors()[1:]
|
||||||
|
)
|
||||||
self.rect.set_points_as_corners([
|
self.rect.set_points_as_corners([
|
||||||
tip_base + perp_vect*width/2,
|
tip_base + perp_vect*width/2,
|
||||||
start + perp_vect*width/2,
|
start + perp_vect*width/2,
|
||||||
|
@ -310,7 +319,7 @@ class Arrow(Line):
|
||||||
|
|
||||||
indices = (-2, -1) if add_at_end else (1, 0)
|
indices = (-2, -1) if add_at_end else (1, 0)
|
||||||
pre_end_point, end_point = [
|
pre_end_point, end_point = [
|
||||||
self.points[index]
|
self.get_anchors()[index]
|
||||||
for index in indices
|
for index in indices
|
||||||
]
|
]
|
||||||
vect = end_point - pre_end_point
|
vect = end_point - pre_end_point
|
||||||
|
@ -319,7 +328,6 @@ class Arrow(Line):
|
||||||
if np.linalg.norm(v) == 0:
|
if np.linalg.norm(v) == 0:
|
||||||
v[0] = 1
|
v[0] = 1
|
||||||
v *= tip_length/np.linalg.norm(v)
|
v *= tip_length/np.linalg.norm(v)
|
||||||
|
|
||||||
ratio = self.tip_width_to_length_ratio
|
ratio = self.tip_width_to_length_ratio
|
||||||
tip.set_points_as_corners([
|
tip.set_points_as_corners([
|
||||||
end_point,
|
end_point,
|
||||||
|
@ -360,7 +368,8 @@ class Arrow(Line):
|
||||||
Line.scale(self, scale_factor, **kwargs)
|
Line.scale(self, scale_factor, **kwargs)
|
||||||
if self.preserve_tip_size_when_scaling:
|
if self.preserve_tip_size_when_scaling:
|
||||||
self.set_tip_points(self.tip)
|
self.set_tip_points(self.tip)
|
||||||
self.set_rectangular_stem_points()
|
if self.use_rectangular_stem:
|
||||||
|
self.set_rectangular_stem_points()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Vector(Arrow):
|
class Vector(Arrow):
|
||||||
|
@ -374,9 +383,9 @@ class Vector(Arrow):
|
||||||
Arrow.__init__(self, ORIGIN, direction, **kwargs)
|
Arrow.__init__(self, ORIGIN, direction, **kwargs)
|
||||||
|
|
||||||
class DoubleArrow(Arrow):
|
class DoubleArrow(Arrow):
|
||||||
def __init__(self, *args, **kwargs):
|
def init_tip(self):
|
||||||
Arrow.__init__(self, *args, **kwargs)
|
self.tip = self.add_tip()
|
||||||
self.add_tip(add_at_end = False)
|
self.second_tip = self.add_tip(add_at_end = False)
|
||||||
|
|
||||||
class CubicBezier(VMobject):
|
class CubicBezier(VMobject):
|
||||||
def __init__(self, points, **kwargs):
|
def __init__(self, points, **kwargs):
|
||||||
|
|
|
@ -11,9 +11,9 @@ class DecimalNumber(VMobject):
|
||||||
"num_decimal_points" : 2,
|
"num_decimal_points" : 2,
|
||||||
"digit_to_digit_buff" : 0.05
|
"digit_to_digit_buff" : 0.05
|
||||||
}
|
}
|
||||||
def __init__(self, float_num, **kwargs):
|
def __init__(self, number, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs, locals())
|
||||||
num_string = '%.*f'%(self.num_decimal_points, float_num)
|
num_string = '%.*f'%(self.num_decimal_points, number)
|
||||||
VMobject.__init__(self, *[
|
VMobject.__init__(self, *[
|
||||||
TexMobject(char)
|
TexMobject(char)
|
||||||
for char in num_string
|
for char in num_string
|
||||||
|
@ -22,7 +22,7 @@ class DecimalNumber(VMobject):
|
||||||
buff = self.digit_to_digit_buff,
|
buff = self.digit_to_digit_buff,
|
||||||
aligned_edge = DOWN
|
aligned_edge = DOWN
|
||||||
)
|
)
|
||||||
if float_num < 0:
|
if number < 0:
|
||||||
minus = self.submobjects[0]
|
minus = self.submobjects[0]
|
||||||
minus.next_to(
|
minus.next_to(
|
||||||
self.submobjects[1], LEFT,
|
self.submobjects[1], LEFT,
|
||||||
|
@ -46,13 +46,15 @@ class Integer(VGroup):
|
||||||
|
|
||||||
class ChangingDecimal(Animation):
|
class ChangingDecimal(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"num_decimal_points" : 2,
|
"num_decimal_points" : None,
|
||||||
"spare_parts" : 2,
|
"spare_parts" : 2,
|
||||||
"position_update_func" : None,
|
"position_update_func" : None,
|
||||||
"tracked_mobject" : None,
|
"tracked_mobject" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, decimal_number, number_update_func, **kwargs):
|
def __init__(self, decimal_number, number_update_func, **kwargs):
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
|
if self.num_decimal_points is None:
|
||||||
|
self.num_decimal_points = decimal_number.num_decimal_points
|
||||||
decimal_number.add(*[
|
decimal_number.add(*[
|
||||||
VectorizedPoint(decimal_number.get_corner(DOWN+LEFT))
|
VectorizedPoint(decimal_number.get_corner(DOWN+LEFT))
|
||||||
for x in range(self.spare_parts)]
|
for x in range(self.spare_parts)]
|
||||||
|
@ -65,9 +67,9 @@ class ChangingDecimal(Animation):
|
||||||
|
|
||||||
def update_number(self, alpha):
|
def update_number(self, alpha):
|
||||||
decimal = self.decimal_number
|
decimal = self.decimal_number
|
||||||
|
new_number = self.number_update_func(alpha)
|
||||||
new_decimal = DecimalNumber(
|
new_decimal = DecimalNumber(
|
||||||
self.number_update_func(alpha),
|
new_number, num_decimal_points = self.num_decimal_points
|
||||||
num_decimal_points = self.num_decimal_points
|
|
||||||
)
|
)
|
||||||
new_decimal.replace(decimal, dim_to_match = 1)
|
new_decimal.replace(decimal, dim_to_match = 1)
|
||||||
new_decimal.highlight(decimal.get_color())
|
new_decimal.highlight(decimal.get_color())
|
||||||
|
@ -78,6 +80,7 @@ class ChangingDecimal(Animation):
|
||||||
]
|
]
|
||||||
for sm1, sm2 in zip(*families):
|
for sm1, sm2 in zip(*families):
|
||||||
sm1.interpolate(sm1, sm2, 1)
|
sm1.interpolate(sm1, sm2, 1)
|
||||||
|
self.mobject.number = new_number
|
||||||
|
|
||||||
def update_position(self):
|
def update_position(self):
|
||||||
if self.position_update_func is not None:
|
if self.position_update_func is not None:
|
||||||
|
|
Loading…
Add table
Reference in a new issue