The line rotate with unexpected scaling - manim

The scene is simple, one Line and rotate PI/2 with below code:
ln = Line(ORIGIN, RIGHT*2)
self.add(ln)
self.wait()
self.play(ApplyMethod(ln.rotate, PI/2, OUT))
However, during the rotating, seemingly scaling at the same time, I check the axis is [0 0 1] that is z axis, I suppose the length of the line should be kept unchanged.
How to prevent the line from scaling? Thanks!

Use Rotate or Rotating, see this.
class RotateVector(Scene):
def construct(self):
coord_start=[1,1,0]
coord_end=[2,3,0]
dot_start=Dot().move_to(coord_start)
dot_end=Dot().move_to(coord_end)
vector=Arrow(coord_start,coord_end,buff=0)
vector.set_color(RED)
self.add(dot_start,dot_end)
self.play(GrowArrow(vector))
self.play(
Rotating(
vector,
radians=PI*2,
about_point=coord_start,
rate_func=smooth,
run_time=1
)
)
self.wait()
self.play(
Rotating(
vector,
radians=PI*2,
about_point=coord_end,
rate_func=linear,
run_time=1
)
)
self.wait()
Edits
You can create a custom animation:
class RotatingAndMove(Animation):
CONFIG = {
"axis": OUT,
"radians": TAU,
"run_time": 5,
"rate_func": linear,
"about_point": None,
"about_edge": None,
}
def __init__(self, mobject, direction,**kwargs):
assert(isinstance(mobject, Mobject))
digest_config(self, kwargs)
self.mobject = mobject
self.direction = direction
def interpolate_mobject(self, alpha):
self.mobject.become(self.starting_mobject)
self.mobject.rotate(
alpha * self.radians,
axis=self.axis,
about_point=self.about_point,
about_edge=self.about_edge,
)
self.mobject.shift(alpha*self.direction)
class NewSceneRotate(Scene):
def construct(self):
arrow=Vector(UP)
arrow.to_corner(UL)
self.play(GrowArrow(arrow))
self.play(
RotatingAndMove(arrow,RIGHT*12+DOWN*4)
)
self.wait()
Or you can use UpdateFromAlphaFunc:
class NewSceneRotateUpdate(Scene):
def construct(self):
arrow=Vector(UP)
arrow.to_corner(UL)
direction=RIGHT*12+DOWN*4
radians=TAU
arrow.starting_mobject=arrow.copy()
def update_arrow(mob,alpha):
mob.become(mob.starting_mobject)
mob.rotate(alpha*radians)
mob.shift(alpha*direction)
self.play(GrowArrow(arrow))
self.play(
UpdateFromAlphaFunc(arrow,update_arrow,rate_func=linear,run_time=5)
)
self.wait()
Something that should be very clear is that when you define an update function, it is not the same to use dt as alpha. That is, it is not the same to define
def update_function(mob,dt)
as
def update_function(mob,alpha)
dt varies with the fps of the video, and is calculated as follows:
dt = 1/self.camera.frame_rate
# You don't have to calculate it, manim already does it by default,
# I just write it so you know where it comes from.
Where self refers to the Scene class.
And alpha varies from 0 to 1, in fact, you can write the previus scene with this update method and get the same result:
def update_arrow(mob,dt):
alpha=interpolate(0,1,dt)
mob.become(mob.starting_mobject)
mob.rotate(alpha*radians)
mob.shift(alpha*direction)
This can be useful if you want alpha to vary in different intervals, use
alpha=interpolate(alpha_start,alpha_end,dt)

Related

NumberPlane grid not showing ManimGL Scene

I recently started using ManimGL version 1.6.1
When I ran the "OpeningManimExample" scene from the example_scenes.py,
there should be a grid in the scene. But it shows only the labels, there are no grid lines.
class OpeningManimExample(Scene):
def construct(self):
intro_words = Text("""
The original motivation for manim was to
better illustrate mathematical functions
as transformations.
""")
intro_words.to_edge(UP)
self.play(Write(intro_words))
self.wait(2)
# Linear transform
grid = NumberPlane((-10, 10), (-5, 5))
matrix = [[1, 1], [0, 1]]
linear_transform_words = VGroup(
Text("This is what the matrix"),
IntegerMatrix(matrix, include_background_rectangle=True),
Text("looks like")
)
linear_transform_words.arrange(RIGHT)
linear_transform_words.to_edge(UP)
linear_transform_words.set_stroke(BLACK, 10, background=True)
self.play(
ShowCreation(grid),
FadeTransform(intro_words, linear_transform_words)
)
self.wait()
self.play(grid.animate.apply_matrix(matrix), run_time=3)
self.wait()
# Complex map
c_grid = ComplexPlane()
moving_c_grid = c_grid.copy()
moving_c_grid.prepare_for_nonlinear_transform()
c_grid.set_stroke(BLUE_E, 1)
c_grid.add_coordinate_labels(font_size=24)
complex_map_words = TexText("""
Or thinking of the plane as $\\mathds{C}$,\\\\
this is the map $z \\rightarrow z^2$
""")
complex_map_words.to_corner(UR)
complex_map_words.set_stroke(BLACK, 5, background=True)
self.play(
FadeOut(grid),
Write(c_grid, run_time=3),
FadeIn(moving_c_grid),
FadeTransform(linear_transform_words, complex_map_words),
)
self.wait()
self.play(
moving_c_grid.animate.apply_complex_function(lambda z: z**2),
run_time=6,
)
self.wait(2)
Output is like this:
OpeningManimExample
I also found similar problem in Flash, FlashAround animations.

PyTorch augmentation

i'm new to machine learning and pytorch. I'm using imgaug library for images augmentation (https://github.com/aleju/imgaug)
I have this code:
class ImgAugTransform:
def __init__(self):
self.aug = seq = iaa.Sequential(
[
# Apply the following augmenters to most images
iaa.Fliplr(0.5), # horizontally flip 50% of all images
iaa.Flipud(0.2), # vertically flip 20% of all images
random_aug_use(iaa.CropAndPad( # crop images by -5% to 10% of their height/width
percent=(-0.1, 0.2),
pad_mode=ia.ALL,
pad_cval=(0.,255)
)),
random_aug_use(iaa.Affine(
scale={"x": (0.8, 1.2), "y": (0.8, 1.2)}, # scale images to 80-120% of their size, individually per axis
translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)}, # translate by -20 to +20 percent (per axis)
rotate=(-45, 45), # rotate by -45 to +45 degrees
shear=(-16, 16), # shear by -16 to +16 degrees
order=[0, 1], # use nearest neighbour or bilinear interpolation (fast)
cval=(0, 255), # if mode is constant, use a cval between 0 and 255
mode=ia.ALL # use any of scikit-image's warping modes (see 2nd image from the top for examples)
))
],
random_order=True)
def __call__(self, img):
img = np.array(img)
return self.aug.augment_image(img)
train_transforms = ImgAugTransform()
train_dataset = torchvision.datasets.ImageFolder(train_dir, train_transforms)
train_dataloader = torch.utils.data.DataLoader(
train_dataset, batch_size=batch_size, shuffle=True, num_workers=batch_size)
So now i cant do this:
X_batch, y_batch = next(iter(train_dataloader))
I get error:
ValueError: some of the strides of a given numpy array are negative. This is currently not supported, but will be added in future releases.
I came across this error as well.
The solution that worked to me was:
def __call__(self, img):
img = np.array(img)
return self.aug.augment_image(img).copy()
But, if you're composing imgaug with torchvision.transforms you can do something like:
def __call__(self, img):
img = self.aug.augment_image(np.array(img))
transforms = torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(self.normalization[0],
self.normalization[1]),
])
return transforms(img.copy())
You should make your augmented numpy arrays contiguous again.
try modifying your augmenter code to:
def __call__(self, img):
img = np.array(img)
return np.ascontiguousarray(self.aug.augment_image(img))

Manim Zoom Not Preserving Line Thickness?

Here is a modified version of some example code, which is from the bottom of this page. The only change is that I've added a line:
from manimlib.imports import *
class ZoomedSceneExample(ZoomedScene):
CONFIG = {
"zoom_factor": 0.3,
"zoomed_display_height": 1,
"zoomed_display_width": 6,
"image_frame_stroke_width": 20,
"zoomed_camera_config": {
"default_frame_stroke_width": 3,
},
}
def construct(self):
# Set objects
dot = Dot().shift(UL*2)
a_line = Line((0,0,0),(1,1,0)).shift(UL*2) ## THIS IS THE ONLY CHANGE
self.add(a_line) ## TO THE EXAMPLE CODE
image=ImageMobject(np.uint8([[ 0, 100,30 , 200],
[255,0,5 , 33]]))
image.set_height(7)
frame_text=TextMobject("Frame",color=PURPLE).scale(1.4)
zoomed_camera_text=TextMobject("Zommed camera",color=RED).scale(1.4)
self.add(image,dot)
# Set camera
zoomed_camera = self.zoomed_camera
zoomed_display = self.zoomed_display
frame = zoomed_camera.frame
zoomed_display_frame = zoomed_display.display_frame
frame.move_to(dot)
frame.set_color(PURPLE)
zoomed_display_frame.set_color(RED)
zoomed_display.shift(DOWN)
# brackground zoomed_display
zd_rect = BackgroundRectangle(
zoomed_display,
fill_opacity=0,
buff=MED_SMALL_BUFF,
)
self.add_foreground_mobject(zd_rect)
# animation of unfold camera
unfold_camera = UpdateFromFunc(
zd_rect,
lambda rect: rect.replace(zoomed_display)
)
frame_text.next_to(frame,DOWN)
self.play(
ShowCreation(frame),
FadeInFromDown(frame_text)
)
# Activate zooming
self.activate_zooming()
self.play(
# You have to add this line
self.get_zoomed_display_pop_out_animation(),
unfold_camera
)
zoomed_camera_text.next_to(zoomed_display_frame,DOWN)
self.play(FadeInFromDown(zoomed_camera_text))
# Scale in x y z
scale_factor=[0.5,1.5,0]
# Resize the frame and zoomed camera
self.play(
frame.scale, scale_factor,
zoomed_display.scale, scale_factor,
FadeOut(zoomed_camera_text),
FadeOut(frame_text)
)
# Resize the frame
self.play(
frame.scale,3,
frame.shift,2.5*DOWN
)
# Resize zoomed camera
self.play(
ScaleInPlace(zoomed_display,2)
)
self.wait()
self.play(
self.get_zoomed_display_pop_out_animation(),
unfold_camera,
# -------> Inverse
rate_func=lambda t: smooth(1-t),
)
self.play(
Uncreate(zoomed_display_frame),
FadeOut(frame),
)
self.wait()
When I render this with Manim, I find that the zooming does not work as I expected. Here is a screenshot from the video:
When not zoomed in, the line is quite thick. But in the zoomed in display, the line appears significantly thinner. Why is this? Can I fix this effect, so that line thickness scales properly with zoom?
Try this:
# Set camera
zoomed_camera = self.zoomed_camera
zoomed_camera.cairo_line_width_multiple = 0.1 # <-
The thickness is calculated in this way.

How to apply multiple animations for one geometry at the same time

There is a square location in the ORIGIN, I want to move it to UP*3 and scale to 0.5 at the same with below code snippet:
sq = Square()
self.add(sq)
self.play(ApplyMethod(sq.scale, 0.5), ApplyMethod(sq.move_to, UP*3), run_time=5)
However, the first one is skipped, only the last one works.
I know creating another small square and using transform can do, but that will bring more code, is there simple solution for this? thanks!
There are 3 ways:
class MultipleMethods1(Scene):
def construct(self):
sq = Square()
self.add(sq)
self.play(
sq.scale, 0.5,
sq.move_to, UP*3,
run_time=5
)
self.wait()
class MultipleMethods2(Scene):
def construct(self):
sq = Square()
cr = Circle()
VGroup(sq,cr).arrange(RIGHT)
self.add(sq)
def apply_function(mob):
mob.scale(0.5)
mob.shift(UP*3)
return mob
self.play(
ApplyFunction(apply_function,sq),
ApplyFunction(apply_function,cr),
run_time=5
)
self.wait()
class MultipleMethods3(Scene):
def construct(self):
sq = Square()
self.add(sq)
sq.generate_target()
sq.target.scale(0.5)
sq.target.move_to(UP*3)
self.play(
MoveToTarget(sq),
run_time=5
)
self.wait()

How to FadeOut the axes in GraphScene?

In GraphScene, using setup_axes to setup the axes, How to FadeOut the axes to prepare the room for other animation?
After setup_axes, I try to change the graph_origin to move the axes, also failed.
Technically you can do it using the self.axes object:
class Plot(GraphScene):
CONFIG = {
"y_max" : 50,
"y_min" : 0,
"x_max" : 7,
"x_min" : 0,
"y_tick_frequency" : 5,
"x_tick_frequency" : 0.5,
}
def construct(self):
self.setup_axes()
graph = self.get_graph(lambda x : x**2,
color = GREEN,
x_min = 0,
x_max = 7
)
self.play(
ShowCreation(graph),
run_time = 2
)
self.wait()
self.play(FadeOut(self.axes))
self.wait()
But, GraphScene was intended to be used once for each axes (you can create multiple graphs on the axes, but not change the axes), if you are going to be changing them then use Scene, here is an example:
class Plot2(Scene):
def construct(self):
c1 = FunctionGraph(lambda x: 2*np.exp(-2*(x-1)**2))
c2 = FunctionGraph(lambda x: x**2)
axes1=Axes(y_min=-3,y_max=3)
axes2=Axes(y_min=0,y_max=10)
self.play(ShowCreation(axes1),ShowCreation(c1))
self.wait()
self.play(
ReplacementTransform(axes1,axes2),
ReplacementTransform(c1,c2)
)
self.wait()
However, in case you want to make a very personalized graph, you will have to add more options to the axes, and the axes are created using NumberLine. This is not so easy to do but you can use the manimlib/scene/graph_scene.py example to guide you, the Axes code is in manimlib/mobject/coordinate_systems.py, the NumberLine code is in manimlib/mobject/number_line.py and the FunctionGraph code is in manimlib/mobject/functions.py to see more options.

Resources