From ecca09be72b38b0ba2a2075cb35982722e62e31c Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 30 Apr 2018 22:59:36 -0700 Subject: [PATCH 1/4] Start gauss --- active_projects/eola2/gauss.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 active_projects/eola2/gauss.py diff --git a/active_projects/eola2/gauss.py b/active_projects/eola2/gauss.py new file mode 100644 index 00000000..c36621d8 --- /dev/null +++ b/active_projects/eola2/gauss.py @@ -0,0 +1,24 @@ +from big_ol_pile_of_manim_imports import * + + +class ShowRowReduction(Scene): + CONFIG = { + "matrix": [ + [2, -1, -1], + [0, 3, -4], + [-3, 2, 1], + ] + } + + def construct(self): + pass + + def initialize_terms(self): + # Create Integer mobjects, and arrange in appropriate grid + pass + + def apply_row_rescaling(self, row_index, scale_factor): + pass + + def add_row_multiple_to_row(self, row1_index, row2_index, scale_factor): + pass From 4504fa3819868801a9f0c85b7bdac22487dbd61c Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 1 May 2018 01:53:59 -0700 Subject: [PATCH 2/4] Fixed problem with output_directory_getters.py on new files --- extract_scene.py | 1 + scene/scene.py | 3 --- utils/output_directory_getters.py | 13 ++++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/extract_scene.py b/extract_scene.py index 5fe81b79..ae52be31 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -21,6 +21,7 @@ HELP_MESSAGE = """ -p preview in low quality -s show and save picture of last frame -w write result to file [this is default if nothing else is stated] + -o write to a different file_name -l use low quality -m use medium quality -a run and save every scene in the script, or all args for the given scene diff --git a/scene/scene.py b/scene/scene.py index 2c9bd581..f136982f 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -545,9 +545,6 @@ class Scene(Container): def save_image(self, name=None, mode="RGB", dont_update=False): path = self.get_image_file_path(name, dont_update) - directory_path = os.path.dirname(path) - if not os.path.exists(directory_path): - os.makedirs(directory_path) if not dont_update: self.update_frame(dont_update_when_skipping=False) image = self.get_image() diff --git a/utils/output_directory_getters.py b/utils/output_directory_getters.py index 6306d398..8011392e 100644 --- a/utils/output_directory_getters.py +++ b/utils/output_directory_getters.py @@ -12,6 +12,12 @@ def add_extension_if_not_present(file_name, extension): return file_name +def guarantee_existance(path): + if not os.path.exists(path): + os.makedirs(path) + return path + + def get_scene_output_directory(scene_class): file_path = os.path.abspath(inspect.getfile(scene_class)) @@ -22,7 +28,7 @@ def get_scene_output_directory(scene_class): file_path = os.path.join(*sub_parts) file_path = file_path.replace(".pyc", "") file_path = file_path.replace(".py", "") - return os.path.join(ANIMATIONS_DIR, file_path) + return guarantee_existance(os.path.join(ANIMATIONS_DIR, file_path)) def get_movie_output_directory(scene_class, camera_config, frame_duration): @@ -31,8 +37,9 @@ def get_movie_output_directory(scene_class, camera_config, frame_duration): camera_config["pixel_shape"][0], int(1.0 / frame_duration) ) - return os.path.join(directory, sub_dir) + return guarantee_existance(os.path.join(directory, sub_dir)) def get_image_output_directory(scene_class, sub_dir="images"): - return os.path.join(get_scene_output_directory(scene_class), sub_dir) + directory = get_scene_output_directory(scene_class) + return guarantee_existance(os.path.join(directory, sub_dir)) From e3cfdaa293ac5b59f40db47fed7044838b447ebe Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 1 May 2018 21:12:10 -0700 Subject: [PATCH 3/4] Early version of ShowRowReduction --- active_projects/eola2/gauss.py | 215 +++++++++++++++++++++++++++++++-- 1 file changed, 206 insertions(+), 9 deletions(-) diff --git a/active_projects/eola2/gauss.py b/active_projects/eola2/gauss.py index c36621d8..5e2cdab8 100644 --- a/active_projects/eola2/gauss.py +++ b/active_projects/eola2/gauss.py @@ -1,24 +1,221 @@ +from fractions import Fraction + from big_ol_pile_of_manim_imports import * +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.scale_to_fit_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 = { - "matrix": [ - [2, -1, -1], - [0, 3, -4], - [-3, 2, 1], - ] + "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): - pass + 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): - # Create Integer mobjects, and arrange in appropriate grid + 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): - pass + 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_submobjects(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): - pass + 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_submobjects(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.scale_to_fit_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 From 7b2adc8f3642a55ed8cf8c252ad875be96e08062 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 2 May 2018 08:17:34 -0700 Subject: [PATCH 4/4] Improved there_and_back_with_pause --- utils/rate_functions.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/rate_functions.py b/utils/rate_functions.py index 27da4ff1..5587cb51 100644 --- a/utils/rate_functions.py +++ b/utils/rate_functions.py @@ -33,13 +33,14 @@ def there_and_back(t, inflection=10.0): return smooth(new_t, inflection) -def there_and_back_with_pause(t): - if t < 1. / 3: - return smooth(3 * t) - elif t < 2. / 3: +def there_and_back_with_pause(t, pause_ratio=1. / 3): + a = 1. / pause_ratio + if t < 0.5 - pause_ratio / 2: + return smooth(a * t) + elif t < 0.5 + pause_ratio / 2: return 1 else: - return smooth(3 - 3 * t) + return smooth(a - a * t) def running_start(t, pull_factor=-0.5):