mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
Merge branch 'master' of github.com:3b1b/manim into wallis-g
This commit is contained in:
@ -1,5 +1,9 @@
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from old_projects.eoc.chapter8 import *
|
||||
from active_projects.eop.histograms import *
|
||||
from svgpathtools import *
|
||||
|
||||
import scipy.special
|
||||
|
||||
COIN_RADIUS = 0.3
|
||||
COIN_THICKNESS = 0.4 * COIN_RADIUS
|
||||
@ -665,19 +669,35 @@ class IllustrateAreaModel1(Scene):
|
||||
label_B_knowing_A = label_B
|
||||
|
||||
self.play(FadeOut(label_B_copy))
|
||||
self.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[-2], RIGHT
|
||||
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[-1][8]),
|
||||
)
|
||||
|
||||
|
||||
# # # # # # # # # # # # # # # # #
|
||||
# Old version with SampleSpace #
|
||||
# # # # # # # # # # # # # # # # #
|
||||
|
||||
# def show_independent_events(self):
|
||||
# sample_space = SampleSpace(
|
||||
@ -747,62 +767,200 @@ class IllustrateAreaModel1(Scene):
|
||||
|
||||
|
||||
|
||||
def color_label(self, label):
|
||||
label.set_color_by_tex("B", RED)
|
||||
label.set_color_by_tex("I", GREEN)
|
||||
# def color_label(self, label):
|
||||
# label.set_color_by_tex("B", RED)
|
||||
# label.set_color_by_tex("I", GREEN)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class IllustrateAreaModel2(AreaIsDerivative):
|
||||
|
||||
class IllustrateAreaModel2(GraphScene):
|
||||
CONFIG = {
|
||||
"y_max" : 4,
|
||||
"y_min" : -4,
|
||||
"num_iterations" : 7,
|
||||
"x_min" : -5,
|
||||
"x_max" : 5,
|
||||
"y_min" : -0,
|
||||
"y_max" : 0.6,
|
||||
"graph_origin": 3*DOWN,
|
||||
"num_rects": 20,
|
||||
"y_axis_label" : "",
|
||||
"num_rects" : 400,
|
||||
"dT" : 0.25,
|
||||
"variable_point_label" : "T",
|
||||
"area_opacity" : 0.8,
|
||||
"x_axis_label" : "",
|
||||
"variable_point_label" : "x",
|
||||
"y_axis_height" : 4
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
x_max_1 = 0
|
||||
x_min_1 = -x_max_1
|
||||
|
||||
x_max_2 = 5
|
||||
x_min_2 = -x_max_2
|
||||
|
||||
|
||||
self.setup_axes()
|
||||
self.introduce_variable_area()
|
||||
graph = self.get_graph(lambda x: np.exp(-x**2) / ((0.5 * TAU) ** 0.5))
|
||||
|
||||
graph, label = self.get_v_graph_and_label()
|
||||
self.add(graph)
|
||||
|
||||
rect_list = self.get_riemann_rectangles_list(
|
||||
graph, self.num_iterations
|
||||
|
||||
cdf_formula = TexMobject("P(|X-\mu| < x) = \int_{-x}^x {\exp(-{1\over 2}({t\over \sigma})^2) \over \sigma\sqrt{2\pi}} dt")
|
||||
cdf_formula.set_color_by_tex("x", YELLOW)
|
||||
cdf_formula.next_to(graph, LEFT, buff = 1)
|
||||
self.add(cdf_formula)
|
||||
|
||||
|
||||
self.v_graph = graph
|
||||
self.add_T_label(x_min_1, color = YELLOW, animated = False)
|
||||
|
||||
self.remove(self.T_label_group, self.right_v_line)
|
||||
#self.T_label_group[0].set_fill(opacity = 0).set_stroke(width = 0)
|
||||
#self.T_label_group[1].set_fill(opacity = 0).set_stroke(width = 0)
|
||||
#self.right_v_line.set_fill(opacity = 0).set_stroke(width = 0)
|
||||
|
||||
#self.add(self.T_label_group)
|
||||
area = self.area = self.get_area(graph, x_min_1, x_max_1)
|
||||
|
||||
right_bound_label = TexMobject("x", color = YELLOW)
|
||||
right_bound_label.next_to(self.coords_to_point(0,0), DOWN)
|
||||
right_bound_label.target = right_bound_label.copy().next_to(self.coords_to_point(self.x_max,0), DOWN)
|
||||
right_bound_label.set_fill(opacity = 0).set_stroke(width = 0)
|
||||
|
||||
left_bound_label = TexMobject("-x", color = YELLOW)
|
||||
left_bound_label.next_to(self.coords_to_point(0,0), DOWN)
|
||||
left_bound_label.target = right_bound_label.copy().next_to(self.coords_to_point(self.x_min,0), DOWN)
|
||||
left_bound_label.set_fill(opacity = 0).set_stroke(width = 0)
|
||||
|
||||
#integral = self.get_riemann_rectangles(
|
||||
#graph,x_min = self.x_min, x_max = x_max_1)
|
||||
self.add(area)
|
||||
|
||||
def integral_update_func(t):
|
||||
return 100 * scipy.special.erf(
|
||||
self.point_to_coords(self.right_v_line.get_center())[0]
|
||||
)
|
||||
VGroup(*rect_list).set_fill(opacity = 0.8)
|
||||
rects = rect_list[0]
|
||||
|
||||
self.play(ShowCreation(graph))
|
||||
self.play(Write(rects))
|
||||
for new_rects in rect_list[1:]:
|
||||
rects.align_submobjects(new_rects)
|
||||
for every_other_rect in rects[::2]:
|
||||
every_other_rect.set_fill(opacity = 0)
|
||||
self.play(Transform(
|
||||
rects, new_rects,
|
||||
run_time = 2,
|
||||
submobject_mode = "lagged_start"
|
||||
cdf_value = DecimalNumber(0, unit = "\%")
|
||||
cdf_value.move_to(self.coords_to_point(0,0.2))
|
||||
self.add_foreground_mobject(cdf_value)
|
||||
|
||||
self.add(ContinualChangingDecimal(
|
||||
decimal_number_mobject = cdf_value,
|
||||
number_update_func = integral_update_func,
|
||||
num_decimal_points = 1
|
||||
))
|
||||
self.wait()
|
||||
|
||||
# self.play(FadeOut(self.x_axis.numbers))
|
||||
self.add_T_label(6)
|
||||
self.change_area_bounds(
|
||||
new_t_max = 4,
|
||||
rate_func = there_and_back,
|
||||
run_time = 2
|
||||
anim = self.get_animation_integral_bounds_change(
|
||||
graph, x_min_2, x_max_2, run_time = 3)
|
||||
|
||||
# changing_cdf_value = ChangingDecimal(
|
||||
# decimal_number_mobject = cdf_value,
|
||||
# number_update_func = integral_update_func,
|
||||
# num_decimal_points = 1
|
||||
# )
|
||||
|
||||
self.play(
|
||||
anim
|
||||
)
|
||||
|
||||
def func(self, x):
|
||||
return np.exp(-x**2/2)
|
||||
|
||||
|
||||
|
||||
|
||||
class IllustrateAreaModel3(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
formula = TexMobject("E[X] = \sum_{i=1}^N p_i x_i").move_to(3 * LEFT + UP)
|
||||
self.add(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)
|
||||
print cumulative_probabilities
|
||||
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(
|
||||
Write(group)
|
||||
)
|
||||
|
||||
|
||||
|
||||
labels = VGroup()
|
||||
for (y, bar) in zip(y_values, hist.bars):
|
||||
label = TexMobject(str(int(y))).scale(0.7).next_to(bar, UP, buff = SMALL_BUFF)
|
||||
self.play(FadeIn(label))
|
||||
labels.add(label)
|
||||
|
||||
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"
|
||||
).fade(0.2)
|
||||
|
||||
ghost_hist = hist.copy().fade(0.8)
|
||||
labels.fade(0.8)
|
||||
self.bring_to_back(ghost_hist)
|
||||
|
||||
self.play(Transform(hist, averaged_hist))
|
||||
|
||||
average_label = TexMobject(str(y_average)).scale(0.7).next_to(averaged_hist, UP, SMALL_BUFF)
|
||||
|
||||
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_label),
|
||||
Transform(braces, one_brace),
|
||||
Transform(p_labels, one_p_label),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class AreaSplitting(Scene):
|
||||
@ -932,6 +1090,62 @@ class AreaSplitting(Scene):
|
||||
#self.play(FadeIn(tally))
|
||||
|
||||
|
||||
class DieFace(SVGMobject):
|
||||
|
||||
def __init__(self, value, **kwargs):
|
||||
|
||||
self.value = value
|
||||
self.file_name = "Dice-" + str(value)
|
||||
self.ensure_valid_file()
|
||||
|
||||
paths, attributes = svg2paths(self.file_path)
|
||||
print paths, attributes
|
||||
SVGMobject.__init__(self, file_name = self.file_name)
|
||||
# for submob in self.submobject_family():
|
||||
# if type(submob) == Rectangle:
|
||||
# submob.set_fill(opacity = 0)
|
||||
# submob.set_stroke(width = 7)
|
||||
|
||||
class RowOfDice(VGroup):
|
||||
CONFIG = {
|
||||
"values" : range(1,7)
|
||||
}
|
||||
|
||||
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, RIGHT)
|
||||
self.add(new_die)
|
||||
|
||||
|
||||
|
||||
class ShowUncertainty(PiCreatureScene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
row_of_dice = RowOfDice().scale(0.5).move_to(ORIGIN)
|
||||
self.add(row_of_dice)
|
||||
rounded_rect = RoundedRectangle(
|
||||
width = 3,
|
||||
height = 2,
|
||||
corner_radius = 0.1
|
||||
).shift(3*LEFT)
|
||||
self.add(rounded_rect)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -16,31 +16,44 @@ class Histogram(VMobject):
|
||||
"end_color" : BLUE,
|
||||
"x_scale" : 1.0,
|
||||
"y_scale" : 1.0,
|
||||
"x_labels" : "auto",
|
||||
"x_min" : 0
|
||||
}
|
||||
|
||||
def __init__(self, x_values, y_values, **kwargs):
|
||||
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!")
|
||||
|
||||
# preliminaries
|
||||
self.x_values = x_values
|
||||
self.y_values = y_values
|
||||
self.y_values = np.array(y_values)
|
||||
|
||||
self.x_steps = x_values[1:] - x_values[:-1]
|
||||
self.x_min = x_values[0] - self.x_steps[0] * 0.5
|
||||
self.x_posts = (x_values[1:] + x_values[:-1]) * 0.5
|
||||
self.x_max = x_values[-1] + self.x_steps[-1] * 0.5
|
||||
self.x_posts = np.insert(self.x_posts,0,self.x_min)
|
||||
self.x_posts = np.append(self.x_posts,self.x_max)
|
||||
if mode == "widths":
|
||||
self.widths = 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 mode == "posts":
|
||||
self.posts = x_values
|
||||
self.widths = x_values[1:] - 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_widths = self.x_posts[1:] - self.x_posts[:-1]
|
||||
self.x_mids = 0.5 * (self.posts[:-1] + self.posts[1:])
|
||||
|
||||
self.x_values_scaled = self.x_scale * x_values
|
||||
self.x_steps_scaled = self.x_scale * self.x_steps
|
||||
self.x_posts_scaled = self.x_scale * self.x_posts
|
||||
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.x_widths_scaled = self.x_scale * self.x_widths
|
||||
|
||||
self.y_values_scaled = self.y_scale * self.y_values
|
||||
|
||||
@ -50,18 +63,38 @@ class Histogram(VMobject):
|
||||
|
||||
def generate_points(self):
|
||||
|
||||
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:
|
||||
ret_arr.append(str(x))
|
||||
return ret_arr
|
||||
|
||||
previous_bar = ORIGIN
|
||||
self.bars = []
|
||||
outline_points = []
|
||||
self.x_labels = text_range(self.x_values[0], self.x_max, self.x_steps[0])
|
||||
if self.x_labels == "widths":
|
||||
self.x_labels = num_arr_to_string_arr(self.widths)
|
||||
elif self.x_labels == "mids":
|
||||
print self.x_mids
|
||||
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))
|
||||
|
||||
for (i,x) in enumerate(self.x_values):
|
||||
print self.x_labels
|
||||
|
||||
for (i,x) in enumerate(self.x_mids):
|
||||
|
||||
bar = Rectangle(
|
||||
width = self.x_widths_scaled[i],
|
||||
width = self.widths_scaled[i],
|
||||
height = self.y_values_scaled[i],
|
||||
)
|
||||
t = float(x - self.x_values[0])/(self.x_values[-1] - self.x_values[0])
|
||||
t = float(x - self.x_min)/(self.x_max - self.x_min)
|
||||
bar_color = interpolate_color(
|
||||
self.start_color,
|
||||
self.end_color,
|
||||
@ -87,7 +120,6 @@ class Histogram(VMobject):
|
||||
outline_points.append(bar.get_anchors()[1])
|
||||
|
||||
previous_bar = bar
|
||||
|
||||
# close the outline
|
||||
# lower right
|
||||
outline_points.append(bar.get_anchors()[2])
|
||||
@ -103,6 +135,15 @@ class Histogram(VMobject):
|
||||
|
||||
|
||||
|
||||
class BuildUpHistogram(Animation):
|
||||
|
||||
def __init__(self, hist, **kwargs):
|
||||
self.histogram = hist
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FlashThroughHistogram(Animation):
|
||||
|
@ -717,6 +717,41 @@ class Square(Rectangle):
|
||||
)
|
||||
|
||||
|
||||
class RoundedRectangle(Rectangle):
|
||||
CONFIG = {
|
||||
"corner_radius" : 0.5,
|
||||
"close_new_points" : True
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
y, x = self.height / 2., self.width / 2.
|
||||
r = self.corner_radius
|
||||
|
||||
arc_ul = ArcBetweenPoints(x * LEFT + (y - r) * UP, (x - r) * LEFT + y * UP, angle = -TAU/4)
|
||||
arc_ur = ArcBetweenPoints((x - r) * RIGHT + y * UP, x * RIGHT + (y - r) * UP, angle = -TAU/4)
|
||||
arc_lr = ArcBetweenPoints(x * RIGHT + (y - r) * DOWN, (x - r) * RIGHT + y * DOWN, angle = -TAU/4)
|
||||
arc_ll = ArcBetweenPoints(x * LEFT + (y - r) * DOWN, (x - r) * LEFT + y * DOWN, angle = TAU/4) # sic! bug in ArcBetweenPoints?
|
||||
|
||||
points = arc_ul.points
|
||||
points = np.append(points,np.array([y * UP]), axis = 0)
|
||||
points = np.append(points,np.array([y * UP]), axis = 0)
|
||||
points = np.append(points,arc_ur.points, axis = 0)
|
||||
points = np.append(points,np.array([x * RIGHT]), axis = 0)
|
||||
points = np.append(points,np.array([x * RIGHT]), axis = 0)
|
||||
points = np.append(points,arc_lr.points, axis = 0)
|
||||
points = np.append(points,np.array([y * DOWN]), axis = 0)
|
||||
points = np.append(points,np.array([y * DOWN]), axis = 0)
|
||||
points = np.append(points,arc_ll.points[::-1], axis = 0) # sic! see comment above
|
||||
points = np.append(points,np.array([x * LEFT]), axis = 0)
|
||||
points = np.append(points,np.array([x * LEFT]), axis = 0)
|
||||
points = np.append(points,np.array([x * LEFT + (y - r) * UP]), axis = 0)
|
||||
|
||||
points = points[::-1]
|
||||
|
||||
self.set_points(points)
|
||||
|
||||
|
||||
|
||||
class Grid(VMobject):
|
||||
CONFIG = {
|
||||
"height": 6.0,
|
||||
|
@ -4,10 +4,12 @@ import string
|
||||
import warnings
|
||||
|
||||
from xml.dom import minidom
|
||||
from utils.color import *
|
||||
|
||||
from constants import *
|
||||
from mobject.geometry import Circle
|
||||
from mobject.geometry import Rectangle
|
||||
from mobject.geometry import RoundedRectangle
|
||||
from utils.bezier import is_closed
|
||||
from utils.config_ops import digest_config
|
||||
from utils.config_ops import digest_locals
|
||||
@ -34,7 +36,7 @@ class SVGMobject(VMobject):
|
||||
"file_name": None,
|
||||
"unpack_groups": True, # if False, creates a hierarchy of VGroups
|
||||
"stroke_width": 0,
|
||||
"fill_opacity": 1,
|
||||
"fill_opacity": 1.0,
|
||||
# "fill_color" : LIGHT_GREY,
|
||||
"propagate_style_to_family": True,
|
||||
}
|
||||
@ -155,16 +157,54 @@ class SVGMobject(VMobject):
|
||||
return Circle().scale(rx * RIGHT + ry * UP).shift(x * RIGHT + y * DOWN)
|
||||
|
||||
def rect_to_mobject(self, rect_element):
|
||||
if rect_element.hasAttribute("fill"):
|
||||
if Color(str(rect_element.getAttribute("fill"))) == Color(WHITE):
|
||||
fill_color = rect_element.getAttribute("fill")
|
||||
stroke_color = rect_element.getAttribute("stroke")
|
||||
stroke_width = rect_element.getAttribute("stroke-width")
|
||||
corner_radius = rect_element.getAttribute("rx")
|
||||
|
||||
# input preprocessing
|
||||
if fill_color in ["", "none", "#FFF", "#FFFFFF"] or Color(fill_color) == Color(WHITE):
|
||||
opacity = 0
|
||||
fill_color = BLACK # shdn't be necessary but avoids error msgs
|
||||
if fill_color in ["#000", "#000000"]:
|
||||
fill_color = WHITE
|
||||
if stroke_color in ["", "none", "#FFF", "#FFFFFF"] or Color(stroke_color) == Color(WHITE):
|
||||
stroke_width = 0
|
||||
stroke_color = BLACK
|
||||
if stroke_color in ["#000", "#000000"]:
|
||||
stroke_color = WHITE
|
||||
if stroke_width in ["", "none", "0"]:
|
||||
stroke_width = 0
|
||||
|
||||
# is there sth to draw?
|
||||
if opacity == 0 and stroke_width == 0:
|
||||
return
|
||||
|
||||
if corner_radius in ["", "0", "none"]:
|
||||
corner_radius = 0
|
||||
|
||||
corner_radius = float(corner_radius)
|
||||
|
||||
if corner_radius == 0:
|
||||
mob = Rectangle(
|
||||
width=float(rect_element.getAttribute("width")),
|
||||
height=float(rect_element.getAttribute("height")),
|
||||
stroke_width=0,
|
||||
fill_color=WHITE,
|
||||
fill_opacity=1.0
|
||||
width = float(rect_element.getAttribute("width")),
|
||||
height = float(rect_element.getAttribute("height")),
|
||||
stroke_width = stroke_width,
|
||||
stroke_color = stroke_color,
|
||||
fill_color = fill_color,
|
||||
fill_opacity = opacity
|
||||
)
|
||||
else:
|
||||
mob = RoundedRectangle(
|
||||
width = float(rect_element.getAttribute("width")),
|
||||
height = float(rect_element.getAttribute("height")),
|
||||
stroke_width = stroke_width,
|
||||
stroke_color = stroke_color,
|
||||
fill_color = fill_color,
|
||||
fill_opacity = opacity,
|
||||
corner_radius = corner_radius
|
||||
)
|
||||
|
||||
mob.shift(mob.get_center() - mob.get_corner(UP + LEFT))
|
||||
return mob
|
||||
|
||||
|
@ -4,12 +4,13 @@ from constants import *
|
||||
import itertools as it
|
||||
|
||||
from scene.scene import Scene
|
||||
from animation.creation import Write
|
||||
from animation.creation import Write, DrawBorderThenFill, ShowCreation
|
||||
from animation.transform import Transform
|
||||
from animation.update import UpdateFromAlphaFunc
|
||||
from mobject.functions import ParametricFunction
|
||||
from mobject.geometry import Line
|
||||
from mobject.geometry import Rectangle
|
||||
from mobject.geometry import RegularPolygon
|
||||
from mobject.number_line import NumberLine
|
||||
from mobject.svg.tex_mobject import TexMobject
|
||||
from mobject.svg.tex_mobject import TextMobject
|
||||
@ -49,6 +50,8 @@ class GraphScene(Scene):
|
||||
"default_input_color": YELLOW,
|
||||
"default_riemann_start_color": BLUE,
|
||||
"default_riemann_end_color": GREEN,
|
||||
"area_opacity" : 0.8,
|
||||
"num_rects" : 50,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
@ -245,6 +248,8 @@ class GraphScene(Scene):
|
||||
sample_input = x
|
||||
elif input_sample_type == "right":
|
||||
sample_input = x + dx
|
||||
elif input_sample_type == "center":
|
||||
sample_input = x + 0.5 * dx
|
||||
else:
|
||||
raise Exception("Invalid input sample type")
|
||||
graph_point = self.input_to_graph_point(sample_input, graph)
|
||||
@ -284,6 +289,18 @@ class GraphScene(Scene):
|
||||
for n in range(n_iterations)
|
||||
]
|
||||
|
||||
|
||||
def get_area(self, graph, t_min, t_max):
|
||||
numerator = max(t_max - t_min, 0.01)
|
||||
dx = float(numerator) / self.num_rects
|
||||
return self.get_riemann_rectangles(
|
||||
graph,
|
||||
x_min = t_min,
|
||||
x_max = t_max,
|
||||
dx = dx,
|
||||
stroke_width = 0,
|
||||
).set_fill(opacity = self.area_opacity)
|
||||
|
||||
def transform_between_riemann_rects(self, curr_rects, new_rects, **kwargs):
|
||||
transform_kwargs = {
|
||||
"run_time": 2,
|
||||
@ -421,6 +438,84 @@ class GraphScene(Scene):
|
||||
|
||||
return group
|
||||
|
||||
|
||||
def add_T_label(self, x_val, color = WHITE, animated = False, **kwargs):
|
||||
triangle = RegularPolygon(n=3, start_angle = np.pi/2)
|
||||
triangle.scale_to_fit_height(MED_SMALL_BUFF)
|
||||
triangle.move_to(self.coords_to_point(x_val, 0), UP)
|
||||
triangle.set_fill(color, 1)
|
||||
triangle.set_stroke(width = 0)
|
||||
T_label = TexMobject(self.variable_point_label, fill_color = color)
|
||||
T_label.next_to(triangle, DOWN)
|
||||
v_line = self.get_vertical_line_to_graph(
|
||||
x_val, self.v_graph,
|
||||
color = YELLOW
|
||||
)
|
||||
|
||||
if animated:
|
||||
self.play(
|
||||
DrawBorderThenFill(triangle),
|
||||
ShowCreation(v_line),
|
||||
Write(T_label, run_time = 1),
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
self.add(triangle, v_line, T_label)
|
||||
|
||||
self.T_label_group = VGroup(T_label, triangle)
|
||||
self.right_v_line = v_line
|
||||
|
||||
|
||||
|
||||
def get_animation_integral_bounds_change(
|
||||
self,
|
||||
graph,
|
||||
new_t_min,
|
||||
new_t_max,
|
||||
run_time = 1.0
|
||||
):
|
||||
curr_t_min = self.x_axis.point_to_number(self.area.get_left())
|
||||
curr_t_max = self.x_axis.point_to_number(self.area.get_right())
|
||||
if new_t_min is None:
|
||||
new_t_min = curr_t_min
|
||||
if new_t_max is None:
|
||||
new_t_max = curr_t_max
|
||||
|
||||
group = VGroup(self.area)
|
||||
if hasattr(self, "right_v_line"):
|
||||
group.add(self.right_v_line)
|
||||
else:
|
||||
group.add(VGroup())
|
||||
# because update_group expects 3 elements in group
|
||||
if hasattr(self, "T_label_group"):
|
||||
group.add(self.T_label_group)
|
||||
else:
|
||||
group.add(VGroup())
|
||||
|
||||
def update_group(group, alpha):
|
||||
area, v_line, T_label = group
|
||||
t_min = interpolate(curr_t_min, new_t_min, alpha)
|
||||
t_max = interpolate(curr_t_max, new_t_max, alpha)
|
||||
new_area = self.get_area(graph,t_min, t_max)
|
||||
new_v_line = self.get_vertical_line_to_graph(
|
||||
t_max, graph
|
||||
)
|
||||
new_v_line.set_color(v_line.get_color())
|
||||
T_label.move_to(new_v_line.get_bottom(), UP)
|
||||
|
||||
#Fade close to 0
|
||||
if len(T_label) > 0:
|
||||
T_label[0].set_fill(opacity = min(1, t_max))
|
||||
|
||||
Transform(area, new_area).update(1)
|
||||
Transform(v_line, new_v_line).update(1)
|
||||
return group
|
||||
|
||||
return UpdateFromAlphaFunc(group, update_group, run_time = run_time)
|
||||
|
||||
|
||||
|
||||
|
||||
def animate_secant_slope_group_change(
|
||||
self, secant_slope_group,
|
||||
target_dx=None,
|
||||
@ -462,3 +557,23 @@ class GraphScene(Scene):
|
||||
)
|
||||
secant_slope_group.kwargs["x"] = target_x
|
||||
secant_slope_group.kwargs["dx"] = target_dx
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user