Animating Arrays#
Manim Array - MArray#
The most basic data structure this package provides is the MArray
(short for Manim Array 😄). To create a MArray
simply create an instance by passing a python list
.
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(self, [1, 2, 3])
4 self.play(Create(arr))
5 self.wait(1)
Animating MArray#
To animate the MArray
, simply invoke the animate
property as shown below:
1self.play(arr.animate.shift(UP * 2 + LEFT * 5))
Moreover, you can also use the MArray.animate_elem()
method to animate a single element of the MArray
as well:
1self.play(arr.animate_elem(1).shift(DOWN))
Lastly, you can also animate the body, value and the index of any element using the MArray.animate_elem_square()
, MArray.animate_elem_value()
and MArray.animate_elem_index()
respectively.
1self.play(
2 arr.animate_elem_square(1).set_fill(BLACK),
3 arr.animate_elem_value(1).set_fill(RED),
4 arr.animate_elem_index(1).rotate(PI / 2)
5)
Customizing MArray#
The MArray
also allows you to alter the way your array looks. While creating your array pass arguments to Square
(used to represent the element body) and Text
(used to represent the element value and index) mobjects.
1arr = MArray(
2 self,
3 [1, 2, 3],
4 mob_square_args={'fill_color': RED_D},
5 mob_value_args={'color': BLACK},
6 mob_index_args={'color': GOLD_A}
7)
Growth Direction#
Furthermore, you can also create MArray
that grows in different directions (e.g. up, down, right and left etc.).
To do this, simply pass your preferred direction enum from MArrayDirection
as the arr_dir
argument to the constructor. The code snippet below generates four different arrays in each direction.
1class MyScene(Scene):
2 def construct(self):
3 arr_up = MArray(self, [1, 2], arr_dir=MArrayDirection.UP)
4 arr_right = MArray(self, [3, 4], arr_dir=MArrayDirection.RIGHT)
5 arr_down = MArray(self, [5, 6], arr_dir=MArrayDirection.DOWN)
6 arr_left = MArray(self, [7, 8], arr_dir=MArrayDirection.LEFT)
7
8 self.play(Create(arr_up))
9 self.play(arr_up.animate.shift(UP * 2))
10 self.play(Create(arr_right))
11 self.play(arr_right.animate.shift(RIGHT * 2))
12 self.play(Create(arr_down))
13 self.play(arr_down.animate.shift(DOWN * 2))
14 self.play(Create(arr_left))
15 self.play(arr_left.animate.shift(LEFT * 2))
16
17 self.wait(1)
Array Label#
For an MArray
, you can also a label with the array via specifying the label
argument.
Similar to how we specify the growth direction using MArrayDirection
enum, we can dictate the position of the label.
1class MyScene(Scene):
2 def construct(self):
3 arr_label_left = MArray(self, [1, 2, 3], label='Arr')
4 arr_label_right = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.RIGHT)
5 arr_label_down = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.DOWN)
6 arr_label_up = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.UP, arr_label_gap=0.75)
7
8 self.play(Create(arr_label_left))
9 self.play(arr_label_left.animate.shift(UP * 2 + LEFT * 4))
10 self.play(Create(arr_label_right))
11 self.play(arr_label_right.animate.shift(DOWN * 2 + LEFT * 4))
12 self.play(Create(arr_label_down))
13 self.play(arr_label_down.animate.shift(UP * 2 + RIGHT))
14 self.play(Create(arr_label_up))
15 self.play(arr_label_up.animate.shift(DOWN * 2 + RIGHT))
16
17 self.wait(1)
Note
The arr_label_gap
argument specifies the distance between the MArrayElement
‘s Square
and the array label itself.
Hex Indices#
Lets say you want to show a 4-byte integer array with its addresses. You can simply achieve this by using index_hex_display
and index_offset
arguments of the MArray
constructor.
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(
4 self,
5 [1, 2, 3, 4],
6 index_hex_display=True,
7 index_offset=4
8 )
9 self.play(Create(arr))
10 self.wait(1)
Hide Indices#
Or if you don’t want to show the indices at all, simply pass True
as the hide_index
argument to the constructor
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(
4 self,
5 [1, 2, 3, 4],
6 hide_index=True
7 )
8 self.play(Create(arr))
9 self.wait(1)
Misc Functions#
The MArray
provides some auxiliary methods which this secion will discuss.
Append Element#
For an existing array, you can also append an element simply by invoking the MArray.append_elem()
method.
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN)
4 self.add(arr)
5 self.wait(1)
6 arr.append_elem(4)
7 self.wait(1)
Note
You can also pass mob_*_args
to this method to customize the inserted element.
Moreover, you can also specify the animation that is played for the inserted element via the append_anim
argument. The code snippet below passes the GrowFromCenter
animation to the MArray.append_elem()
method:
1arr.append_elem(4, append_anim=GrowFromCenter)
Note
You can also specify arguments to the passed animation via the append_anim_args
parameter and also set the target of the animation using the append_anim_target
parameter that takes in MArrayElementComp
enum.
Did you notice that in both snippets, we didn’t pass any animation to our Scene
but the append animation still played? This is thanks to the self
that we pass as the first argument to our MArray
constructor, which is basically a reference to the current Scene
.
However, if you’d like to play the animation yourself, we have got you covered! The MArrayElement
method returns a list of Animation
that you can pass to the Scene.play()
method as follows:
1self.play(*arr.append_elem(4, play_anim=False))
Remove Element#
To remove an element simply invoke the MArray.remove_elem()
method with the index of element you wish to remove.
1arr.remove_elem(1)
Similar to how you were able to pass the append animation to the MArray.append_elem()
function, you can specify two animations for the MArray.remove_elem()
method:
Element removal animation via the
removal_anim
parameter.Indices update animation via the
update_anim
parameter.
The code snippet below provides an example:
1arr.remove_elem(1, removal_anim=ShowPassingFlash , update_anim=Write)
Note
You can also specify arguments to the passed animation via the *_anim_args
parameter and also set the target of the animation using the *_anim_target
parameter.
Lastly, as the MArray.append_elem()
returns a list of Animation
, the MArray.remove_elem()
returns two objects; a removal animation and a function that udpates the indices of the remaining elements and returns their animations. Hence, you can animate this as follows:
1(remove_anim, update_indices) = arr.remove_elem(1, removal_anim=ShowPassingFlash , update_anim=Write, play_anim=False)
2self.play(remove_anim) # Play removal animation first
3self.play(*update_indices(play_anim=False)) # Then play the update_indices animation
Update Element#
You can also update the value and the index of an existing array using the MArray.update_elem_value()
and MArray.update_elem_index()
methods respectively.
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(self, [1, 2, 3])
4 self.add(arr)
5 self.wait(1)
6 arr.update_elem_value(1, 20)
7 arr.update_elem_index(1, -2)
8 self.wait(1)
Note
You can also pass mob_value_args
and mob_index_args
to respective methods to customize the updated element mobject.
Using MArrayPointer#
Thus far, if you had been hoping for a pointer to associate with your array, then your prayers have been answered. The MArrayPointer
allows you to attach a pointer with your array. The following snippet demonstrates its capabilities:
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
4 arr.shift(UP + LEFT * 2)
5 self.add(arr)
6
7 pointer = MArrayPointer(self, arr, 2, 'P')
8 self.play(Create(pointer))
9 self.wait(1)
10 pointer.shift_to_elem(4)
11 self.wait(1)
12 pointer.shift_to_elem(0)
13 self.wait(1)
14 pointer.attach_to_elem(2)
15
16 self.wait(1)
Using MArraySlidingWindow#
In addition to the MArrayPointer
, we also have the MArraySlidingWindow
that allows you to attach a sliding window with your array. The following snippet demonstrates its capabilities:
1class MyScene(Scene):
2 def construct(self):
3 arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
4 arr.shift(UP + LEFT * 2)
5 self.add(arr)
6
7 window = MArraySlidingWindow(self, arr, 1, 1, 'W')
8 self.play(Create(window))
9 self.wait(1)
10 window.shift_to_elem(2)
11 self.wait(1)
12 window.resize_window(3)
13 self.wait(1)
14 window.shift_to_elem(0)
15 self.wait(1)
16 window.resize_window(1)
17 self.wait(1)
18 window.attach_to_elem(2)
19
20 self.wait(1)
With this we conclude this guide. We hope you found it useful! ✌️