523 |
524 | .. manim:: MyScene
525 | :hide_source:
526 | :quality: low
527 |
528 | from manim_data_structures import *
529 |
530 | class MyScene(Scene):
531 | def construct(self):
532 | arr = MArray(self, [1, 2, 3])
533 | self.add(arr)
534 | self.wait(1)
535 | arr.update_elem_value(1, 20)
536 | arr.update_elem_index(1, -2)
537 | self.wait(1)
538 |
539 | .. note::
540 |
541 | You can also pass ``mob_value_args`` and ``mob_index_args`` to respective methods to customize the updated element mobject.
542 |
543 | Using MArrayPointer
544 | ~~~~~~~~~~~~~~~~~~~
545 |
546 | 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:
547 |
548 | .. code-block:: python
549 | :linenos:
550 |
551 | class MyScene(Scene):
552 | def construct(self):
553 | arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
554 | arr.shift(UP + LEFT * 2)
555 | self.add(arr)
556 |
557 | pointer = MArrayPointer(self, arr, 2, 'P')
558 | self.play(Create(pointer))
559 | self.wait(1)
560 | pointer.shift_to_elem(4)
561 | self.wait(1)
562 | pointer.shift_to_elem(0)
563 | self.wait(1)
564 | pointer.attach_to_elem(2)
565 |
566 | self.wait(1)
567 |
568 | .. raw:: html
569 |
570 |
571 |
572 | .. manim:: MyScene
573 | :hide_source:
574 | :quality: low
575 |
576 | from manim_data_structures import *
577 |
578 | class MyScene(Scene):
579 | def construct(self):
580 | arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
581 | arr.shift(UP + LEFT * 2)
582 | self.add(arr)
583 |
584 | pointer = MArrayPointer(self, arr, 2, 'P')
585 | self.play(Create(pointer))
586 | self.wait(1)
587 | pointer.shift_to_elem(4)
588 | self.wait(1)
589 | pointer.shift_to_elem(0)
590 | self.wait(1)
591 | pointer.attach_to_elem(2)
592 |
593 | self.wait(1)
594 |
595 | Using MArraySlidingWindow
596 | ~~~~~~~~~~~~~~~~~~~
597 |
598 | 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:
599 |
600 | .. code-block:: python
601 | :linenos:
602 |
603 | class MyScene(Scene):
604 | def construct(self):
605 | arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
606 | arr.shift(UP + LEFT * 2)
607 | self.add(arr)
608 |
609 | window = MArraySlidingWindow(self, arr, 1, 1, 'W')
610 | self.play(Create(window))
611 | self.wait(1)
612 | window.shift_to_elem(2)
613 | self.wait(1)
614 | window.resize_window(3)
615 | self.wait(1)
616 | window.shift_to_elem(0)
617 | self.wait(1)
618 | window.resize_window(1)
619 | self.wait(1)
620 | window.attach_to_elem(2)
621 |
622 | self.wait(1)
623 |
624 | .. raw:: html
625 |
626 |
627 |
628 | .. manim:: MyScene
629 | :hide_source:
630 | :quality: low
631 |
632 | from manim_data_structures import *
633 |
634 | class MyScene(Scene):
635 | def construct(self):
636 | arr = MArray(self, [1, 2, 3, 4, 5], label='Array')
637 | arr.shift(UP + LEFT * 2)
638 | self.add(arr)
639 |
640 | window = MArraySlidingWindow(self, arr, 1, 1, 'W')
641 | self.play(Create(window))
642 | self.wait(1)
643 | window.shift_to_elem(2)
644 | self.wait(1)
645 | window.resize_window(3)
646 | self.wait(1)
647 | window.shift_to_elem(0)
648 | self.wait(1)
649 | window.resize_window(1)
650 | self.wait(1)
651 | window.attach_to_elem(2)
652 |
653 | self.wait(1)
654 |
655 | With this we conclude this guide. We hope you found it useful! ✌️
656 |
--------------------------------------------------------------------------------
/docs/source/guides/index.rst:
--------------------------------------------------------------------------------
1 | Guides
2 | ======
3 |
4 | .. toctree::
5 | :caption: Table of Contents
6 | :maxdepth: 2
7 | :glob:
8 |
9 | arrays
10 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. Manim Data Structures documentation master file, created by
2 | sphinx-quickstart on Fri Nov 25 19:14:42 2022.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Manim Data Structures
7 | =====================
8 |
9 | A plugin for Manim Community Edition that provides Manim objects for common data structures.
10 |
11 | Installation
12 | ------------
13 |
14 | Simply execute the following command to install the package:
15 |
16 | .. code-block:: console
17 |
18 | $ pip install manim-data-structures
19 |
20 | Usage
21 | -----
22 |
23 | To import the package in your script, add the following import statement:
24 |
25 | .. code-block:: python
26 |
27 | from manim_data_structures import *
28 |
29 | Variables
30 | ~~~~~~~~~
31 |
32 | .. manim:: VarScene
33 | :save_last_frame:
34 |
35 | from manim_data_structures import *
36 |
37 | class VarScene(Scene):
38 | def construct(self):
39 | var = MVariable(self, 10, 0, 'Var')
40 | self.add(var)
41 |
42 | Arrays
43 | ~~~~~~
44 |
45 | .. manim:: ArrayScene
46 | :save_last_frame:
47 |
48 | from manim_data_structures import *
49 |
50 | class ArrayScene(Scene):
51 | def construct(self):
52 | arr = MArray(self, [1, 2, 3], label='Arr')
53 | self.add(arr)
54 |
55 | Next Steps
56 | ----------
57 |
58 | - Visit the :doc:`guides/index` section to learn how to use the library.
59 | - Also check out the :doc:`reference/index` to view detailed documentation of the classes.
60 |
61 |
62 | Index
63 | -----
64 |
65 | .. toctree::
66 | :maxdepth: 2
67 |
68 | example
69 | guides/index
70 | reference/index
71 |
--------------------------------------------------------------------------------
/docs/source/reference/arrays.rst:
--------------------------------------------------------------------------------
1 | Arrays
2 | ======
3 |
4 | .. currentmodule:: manim_data_structures
5 |
6 | .. autosummary::
7 | :toctree: generated
8 |
9 | ~m_array.MArrayElement
10 | ~m_array.MArray
11 | ~m_array.MArrayPointer
12 | ~m_array.MArraySlidingWindow
13 |
--------------------------------------------------------------------------------
/docs/source/reference/enums.rst:
--------------------------------------------------------------------------------
1 | Enums
2 | =====
3 |
4 | .. currentmodule:: manim_data_structures
5 |
6 | .. autosummary::
7 | :toctree: generated
8 |
9 | ~m_enum.MArrayDirection
10 | ~m_enum.MArrayElementComp
11 |
--------------------------------------------------------------------------------
/docs/source/reference/index.rst:
--------------------------------------------------------------------------------
1 | Reference Manual
2 | ================
3 |
4 | Contains a detailed documentation of all classes in the plugin.
5 |
6 | Module Index
7 | ------------
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 |
12 | variables
13 | arrays
14 | enums
15 |
--------------------------------------------------------------------------------
/docs/source/reference/variables.rst:
--------------------------------------------------------------------------------
1 | Variables
2 | =========
3 |
4 | .. currentmodule:: manim_data_structures
5 |
6 | .. autosummary::
7 | :toctree: generated
8 |
9 | ~m_variable.MVariable
10 |
--------------------------------------------------------------------------------
/docs/source/refsub.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: manim_data_structures
2 |
3 | .. Manim Data Structures substitutions
4 | .. |MArray| replace:: :py:class:`~m_array.MArray`
5 | .. |MArray.animate_elem| replace:: :py:meth:`MArray.animate_elem() `
6 | .. |MArray.animate_elem_square| replace:: :py:meth:`MArray.animate_elem_square() `
7 | .. |MArray.animate_elem_value| replace:: :py:meth:`MArray.animate_elem_value() `
8 | .. |MArray.animate_elem_index| replace:: :py:meth:`MArray.animate_elem_index() `
9 | .. |MArray.append_elem| replace:: :py:meth:`MArray.append_elem() `
10 | .. |MArray.remove_elem| replace:: :py:meth:`MArray.remove_elem() `
11 | .. |MArray.update_elem_value| replace:: :py:meth:`MArray.update_elem_value() `
12 | .. |MArray.update_elem_index| replace:: :py:meth:`MArray.update_elem_index() `
13 | .. |MArrayElement| replace:: :py:class:`~m_array.MArrayElement`
14 | .. |MArrayDirection| replace:: :py:class:`~m_enum.MArrayDirection`
15 | .. |MArrayElementComp| replace:: :py:class:`~m_enum.MArrayElementComp`
16 | .. |MArrayPointer| replace:: :py:class:`~m_array.MArrayPointer`
17 | .. |MArraySlidingWindow| replace:: :py:class:`~m_array.MArraySlidingWindow`
18 |
19 | .. Manim substitutions
20 | .. |Mobject.animate| replace:: :py:attr:`~manim.mobject.mobject.Mobject.animate`
21 | .. |Scene| replace:: :py:class:`~manim.scene.scene.Scene`
22 | .. |Scene.play| replace:: :py:meth:`Scene.play() `
23 | .. |Square| replace:: :py:class:`~manim.mobject.geometry.polygram.Square`
24 | .. |Text| replace:: :py:class:`~manim.mobject.text.text_mobject.Text`
25 | .. |Animation| replace:: :py:class:`~manim.animation.animation.Animation`
26 | .. |GrowFromCenter| replace:: :py:class:`~manim.animation.growing.GrowFromCenter`
27 |
28 | .. Python substitutions
29 | .. |list| replace:: :py:class:`list`
30 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "manim-data-structures"
3 | version = "0.1.7"
4 | description = "A Manim implementation for data structures"
5 | authors = ["Hammad Nasir "]
6 | readme = "README.md"
7 | packages = [{include = "manim_data_structures", from = "src"}]
8 | repository = "https://github.com/drageelr/manim-data-structures"
9 | documentation = "https://manim-data-structures.readthedocs.io/en/latest/"
10 |
11 | [tool.poetry.dependencies]
12 | python = ">=3.7,<3.11"
13 | manim = ">=0.16.0"
14 |
15 | [tool.poetry.dev-dependencies]
16 | Sphinx = "^5.3.0"
17 | furo = "^2022.9.29"
18 | pre-commit = "^2.20.0"
19 | isort = "5.10.1"
20 | flake8 = {version = "6.0.0", python = ">=3.8.1,<3.11"}
21 | flake8-builtins = "^2.0.1"
22 | flake8-bugbear = "^22.10.27"
23 | flake8-docstrings = "^1.6.0"
24 | flake8-rst-docstrings = "^0.3.0"
25 | flake8-simplify = "^0.19.3"
26 | flake8-comprehensions = "^3.10.1"
27 |
28 | [tool.poetry.dev-dependencies.black]
29 | version = ">=22.10.0"
30 | allow-prereleases = false
31 | python = ">=3.7"
32 | markers = "platform_python_implementation == 'CPython'"
33 |
34 | [tool.isort]
35 | # from https://black.readthedocs.io/en/stable/compatible_configs.html
36 | multi_line_output = 3
37 | include_trailing_comma = true
38 | force_grid_wrap = 0
39 | use_parentheses = true
40 | ensure_newline_before_comments = true
41 | line_length = 88
42 |
43 | [tool.poetry.urls]
44 | "Bug Tracker" = "https://github.com/drageelr/manim-data-structures/issues"
45 | "Changelog" = "https://github.com/drageelr/manim-data-structures/blob/main/CHANGELOG.md"
46 |
47 | [build-system]
48 | requires = ["poetry-core"]
49 | build-backend = "poetry.core.masonry.api"
50 |
51 | [tool.poetry.plugins."manim.plugins"]
52 | "manim_data_structures" = "manim_data_structures"
53 |
--------------------------------------------------------------------------------
/src/manim_data_structures/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = "0.1.7"
2 |
3 | from .m_array import *
4 | from .m_enum import *
5 | from .m_variable import *
6 |
7 | __all__ = [
8 | "MArrayElement",
9 | "MArray",
10 | "MArrayPointer",
11 | "MArraySlidingWindow",
12 | "MArrayDirection",
13 | "MArrayElementComp",
14 | "MVariable",
15 | ]
16 |
--------------------------------------------------------------------------------
/src/manim_data_structures/m_array.py:
--------------------------------------------------------------------------------
1 | """Contains classes to construct an array."""
2 |
3 | from copy import deepcopy
4 |
5 | import numpy as np
6 | from manim import *
7 |
8 | from .m_enum import MArrayDirection, MArrayElementComp
9 |
10 |
11 | class MArrayElement(VGroup):
12 | """A class that represents an array element.
13 |
14 | Parameters
15 | ----------
16 | scene
17 | Specifies the scene where the object is to be rendered.
18 | mob_square_args
19 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
20 | mob_value_args
21 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
22 | mob_index_args
23 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
24 | mob_label_args
25 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element label.
26 | index_pos
27 | Specifies the position of :attr:`__mob_index` w.r.t :attr:`__mob_square`
28 | index_gap
29 | Specifies the distance between :attr:`__mob_index` and :attr:`__mob_square`.
30 | label_pos
31 | Specifies the position of :attr:`__mob_label` w.r.t :attr:`__mob_square`.
32 | label_gap
33 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_square`.
34 | next_to_mob
35 | Specifies the placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
36 | next_to_dir
37 | Specifies the direction of placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
38 |
39 | Attributes
40 | ----------
41 | __scene : :class:`~manim.scene.scene.Scene`
42 | The scene where the object is to be rendered.
43 | __mob_square_props : :class:`dict`
44 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
45 | __mob_value_props : :class:`dict`
46 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
47 | __mob_index_props : :class:`dict`
48 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
49 | __mob_label_props : :class:`dict`
50 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element label.
51 | __index_pos : :class:`np.ndarray`
52 | The position of :attr:`__mob_index` w.r.t :attr:`__mob_square`
53 | __index_gap : :class:`float`
54 | The distance between :attr:`__mob_index` and :attr:`__mob_square`.
55 | __label_pos : :class:`np.ndarray`
56 | The position of :attr:`__mob_label` w.r.t :attr:`__mob_square`.
57 | __label_gap : :class:`float`
58 | The distance between :attr:`__mob_label` and :attr:`__mob_square`.
59 | __mob_square : :class:`~manim.mobject.geometry.polygram.Square`
60 | Represents the body of the element.
61 | __mob_value : :class:`~manim.mobject.text.text_mobject.Text`
62 | Represents the value of the element.
63 | __mob_index : :class:`~manim.mobject.text.text_mobject.Text`
64 | Represents the index of the element.
65 | __mob_label : :class:`~manim.mobject.text.text_mobject.Text`
66 | Represents the label of the element.
67 | """
68 |
69 | def __init_props(
70 | self,
71 | scene: Scene,
72 | index_pos: np.ndarray,
73 | index_gap: float,
74 | label_pos: np.ndarray,
75 | label_gap: float,
76 | ) -> None:
77 | """Initializes the attributes for the class.
78 |
79 | Parameters
80 | ----------
81 | scene
82 | Specifies the scene where the object is to be rendered.
83 | index_pos
84 | Specifies the position of :attr:`__mob_index` w.r.t :attr:`__mob_square`
85 | index_gap
86 | Specifies the distance between :attr:`__mob_index` and :attr:`__mob_square`.
87 | label_pos
88 | Specifies the position of :attr:`__mob_label` w.r.t :attr:`__mob_square`.
89 | label_gap
90 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_square`.
91 | """
92 |
93 | self.__mob_square_props: dict = {
94 | "color": BLUE_B,
95 | "fill_color": BLUE_D,
96 | "fill_opacity": 1,
97 | "side_length": 1,
98 | }
99 | self.__mob_value_props: dict = {"text": "", "color": WHITE, "weight": BOLD}
100 | self.__mob_index_props: dict = {"text": "", "color": BLUE_D, "font_size": 32}
101 | self.__mob_label_props: dict = {"text": "", "color": BLUE_A, "font_size": 38}
102 | self.__scene: Scene = scene
103 | self.__index_pos: np.ndarray = index_pos
104 | self.__index_gap: float = index_gap
105 | self.__label_pos: np.ndarray = label_pos
106 | self.__label_gap: float = label_gap
107 |
108 | def __update_props(
109 | self,
110 | mob_square_args: dict = {},
111 | mob_value_args: dict = {},
112 | mob_index_args: dict = {},
113 | mob_label_args: dict = {},
114 | ) -> None:
115 | """Updates the attributes of the class.
116 |
117 | Parameters
118 | ----------
119 | mob_square_args
120 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
121 | mob_value_args
122 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
123 | mob_index_args
124 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
125 | mob_label_args
126 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element label.
127 | """
128 |
129 | self.__mob_square_props.update(mob_square_args)
130 | self.__mob_value_props.update(mob_value_args)
131 | self.__mob_index_props.update(mob_index_args)
132 | self.__mob_label_props.update(mob_label_args)
133 |
134 | if type(self.__mob_value_props["text"]) != str:
135 | self.__mob_value_props["text"] = str(self.__mob_value_props["text"])
136 |
137 | if type(self.__mob_index_props["text"]) != str:
138 | self.__mob_index_props["text"] = str(self.__mob_index_props["text"])
139 |
140 | if type(self.__mob_label_props["text"]) != str:
141 | self.__mob_label_props["text"] = str(self.__mob_label_props["text"])
142 |
143 | def __init_mobs(
144 | self,
145 | init_square: bool = False,
146 | init_value: bool = False,
147 | init_index: bool = False,
148 | init_label: bool = False,
149 | next_to_mob: "MArrayElement" = None,
150 | next_to_dir: np.ndarray = RIGHT,
151 | ) -> None:
152 | """Initializes the mobjects for the class.
153 |
154 | Parameters
155 | ----------
156 | init_square
157 | If `True`, instantiates a :class:`~manim.mobject.geometry.polygram.Square` and assigns it to :attr:`__mob_square`.
158 | init_value
159 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_value`.
160 | init_index
161 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_index`.
162 | init_label
163 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_label`.
164 | next_to_mob
165 | Specifies placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
166 | next_to_dir
167 | Specifies direction of placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
168 | """
169 |
170 | if init_square:
171 | self.__mob_square: Square = Square(**self.__mob_square_props)
172 | if next_to_mob is not None:
173 | self.__mob_square.next_to(
174 | next_to_mob.fetch_mob_square(), next_to_dir, 0
175 | )
176 | self.add(self.__mob_square)
177 |
178 | if init_value:
179 | self.__mob_value: Text = Text(**self.__mob_value_props)
180 | self.__mob_value.next_to(self.__mob_square, np.array([0, 0, 0]), 0)
181 | self.add(self.__mob_value)
182 |
183 | if init_index:
184 | self.__mob_index: Text = Text(**self.__mob_index_props)
185 | self.__mob_index.next_to(
186 | self.__mob_square, self.__index_pos, self.__index_gap
187 | )
188 | self.add(self.__mob_index)
189 |
190 | if init_label:
191 | self.__mob_label: Text = Text(**self.__mob_label_props)
192 | self.__mob_label.next_to(
193 | self.__mob_square, self.__label_pos, self.__label_gap
194 | )
195 | self.add(self.__mob_label)
196 |
197 | def __deepcopy__(self, memo):
198 | """Deepcopy that excludes attributes specified in `exclude_list`."""
199 |
200 | exclude_list = ["_MArrayElement__scene"]
201 |
202 | cls = self.__class__
203 | result = cls.__new__(cls)
204 | memo[id(self)] = result
205 | for k, v in self.__dict__.items():
206 | if k not in exclude_list:
207 | setattr(result, k, deepcopy(v, memo))
208 | return result
209 |
210 | def __init__(
211 | self,
212 | scene: Scene,
213 | mob_square_args: dict = {},
214 | mob_value_args: dict = {},
215 | mob_index_args: dict = {},
216 | mob_label_args: dict = {},
217 | index_pos: np.ndarray = UP,
218 | index_gap: float = 0.25,
219 | label_pos: np.ndarray = LEFT,
220 | label_gap: float = 0.5,
221 | next_to_mob: "MArrayElement" = None,
222 | next_to_dir: np.ndarray = RIGHT,
223 | **kwargs
224 | ) -> None:
225 | """Initializes the class.
226 |
227 | Parameters
228 | ----------
229 | scene
230 | Specifies the scene where the object is to be rendered.
231 | mob_square_args
232 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
233 | mob_value_args
234 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
235 | mob_index_args
236 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
237 | mob_label_args
238 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element label.
239 | index_pos
240 | Specifies the position of :attr:`__mob_index` w.r.t :attr:`__mob_square`
241 | index_gap
242 | Specifies the distance between :attr:`__mob_index` and :attr:`__mob_square`.
243 | label_pos
244 | Specifies the position of :attr:`__mob_label` w.r.t :attr:`__mob_square`.
245 | label_gap
246 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_square`.
247 | next_to_mob
248 | Specifies the placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
249 | next_to_dir
250 | Specifies the direction of placement for :attr:`__mob_square` w.r.t another :class:`MArrayElement`.
251 | """
252 |
253 | super().__init__(**kwargs)
254 |
255 | # Initialize props
256 | self.__init_props(scene, index_pos, index_gap, label_pos, label_gap)
257 |
258 | # Update props
259 | self.__update_props(
260 | mob_square_args, mob_value_args, mob_index_args, mob_label_args
261 | )
262 |
263 | # Initialize mobjects
264 | self.__init_mobs(True, True, True, True, next_to_mob, next_to_dir)
265 |
266 | def fetch_mob_square(self) -> Square:
267 | """Fetches the square mobject.
268 |
269 | Returns
270 | -------
271 | :class:`~manim.mobject.geometry.polygram.Square`
272 | :attr:`__mob_square`.
273 | """
274 |
275 | return self.__mob_square
276 |
277 | def fetch_mob_value(self) -> Text:
278 | """Fetches the value mobject.
279 |
280 | Returns
281 | -------
282 | :class:`~manim.mobject.text.text_mobject.Text`
283 | :attr:`__mob_value`.
284 | """
285 |
286 | return self.__mob_value
287 |
288 | def fetch_mob_index(self) -> Text:
289 | """Fetches the index mobject.
290 |
291 | Returns
292 | -------
293 | :class:`~manim.mobject.text.text_mobject.Text`
294 | :attr:`__mob_index`.
295 | """
296 |
297 | return self.__mob_index
298 |
299 | def fetch_mob_label(self) -> Text:
300 | """Fetches the label mobject.
301 |
302 | Returns
303 | -------
304 | :class:`~manim.mobject.text.text_mobject.Text`
305 | :attr:`__mob_label`.
306 | """
307 |
308 | return self.__mob_label
309 |
310 | def fetch_mob(self, mob_target: MArrayElementComp) -> Mobject:
311 | """Fetches the mobject based on the specified enum.
312 |
313 | Parameters
314 | ----------
315 | mob_target
316 | Specifies the :class:`~manim.mobject.mobject.Mobject` to fetch.
317 |
318 | Returns
319 | -------
320 | :class:`~manim.mobject.mobject.Mobject`
321 | Mobject of the class.
322 | """
323 |
324 | if mob_target == MArrayElementComp.BODY:
325 | return self.fetch_mob_square()
326 | elif mob_target == MArrayElementComp.VALUE:
327 | return self.fetch_mob_value()
328 | elif mob_target == MArrayElementComp.INDEX:
329 | return self.fetch_mob_index()
330 | elif mob_target == MArrayElementComp.LABEL:
331 | return self.fetch_mob_label()
332 | else:
333 | return self
334 |
335 | def update_mob_value(
336 | self,
337 | mob_value_args: dict = {},
338 | update_anim: Animation = Write,
339 | update_anim_args: dict = {},
340 | play_anim: bool = True,
341 | play_anim_args: dict = {},
342 | ) -> Text:
343 | """Re-intializes the value mobject.
344 |
345 | Parameters
346 | ----------
347 | mob_value_args
348 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
349 | update_anim
350 | Animation to be applied to the updated :attr:`__mob_value`.
351 | update_anim_args
352 | Arguments for update :class:`~manim.animation.animation.Animation`.
353 | play_anim
354 | If `True`, plays the animation(s).
355 | play_anim_args
356 | Arguments for :py:meth:`Scene.play() `.
357 |
358 | Returns
359 | -------
360 | :class:`~manim.mobject.text.text_mobject.Text`
361 | Updated :attr:`__mob_value`.
362 | """
363 |
364 | # Update props of mob_value
365 | self.__update_props(mob_value_args=mob_value_args)
366 |
367 | # Remove current mob_value
368 | self.remove(self.__mob_value)
369 |
370 | # Initialize new mob_value
371 | self.__init_mobs(init_value=True)
372 |
373 | # Add new mob_value to group
374 | self.add(self.__mob_value)
375 |
376 | # Animate change
377 | if play_anim:
378 | self.__scene.play(
379 | update_anim(self.__mob_value, **update_anim_args), **play_anim_args
380 | )
381 |
382 | return self.__mob_value
383 |
384 | def update_mob_index(
385 | self,
386 | mob_index_args: dict = {},
387 | update_anim: Animation = Write,
388 | update_anim_args: dict = {},
389 | play_anim: bool = True,
390 | play_anim_args: dict = {},
391 | ) -> Text:
392 | """Re-intializes the index mobject.
393 |
394 | Parameters
395 | ----------
396 | mob_index_args
397 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
398 | update_anim
399 | Animation to be applied to the updated :attr:`__mob_index`.
400 | update_anim_args
401 | Arguments for update :class:`~manim.animation.animation.Animation`.
402 | play_anim
403 | If `True`, plays the animation(s).
404 | play_anim_args
405 | Arguments for :py:meth:`Scene.play() `.
406 |
407 | Returns
408 | -------
409 | :class:`~manim.mobject.text.text_mobject.Text`
410 | Updated :attr:`__mob_index`.
411 | """
412 |
413 | # Update props of mob_index
414 | self.__update_props(mob_index_args=mob_index_args)
415 |
416 | # Remove current mob_index
417 | self.remove(self.__mob_index)
418 |
419 | # Initialize new mob_index
420 | self.__init_mobs(init_index=True)
421 |
422 | # Add new mob_index to group
423 | self.add(self.__mob_index)
424 |
425 | # Animate change
426 | if play_anim:
427 | self.__scene.play(
428 | update_anim(self.__mob_index, **update_anim_args), **play_anim_args
429 | )
430 |
431 | return self.__mob_index
432 |
433 | def update_mob_label(
434 | self,
435 | mob_label_args: dict = {},
436 | update_anim: Animation = Write,
437 | update_anim_args: dict = {},
438 | play_anim: bool = True,
439 | play_anim_args: dict = {},
440 | ) -> Text:
441 | """Re-intializes the label mobject.
442 |
443 | Parameters
444 | ----------
445 | mob_label_args
446 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element label.
447 | update_anim
448 | Animation to be applied to the updated :attr:`__mob_label`.
449 | update_anim_args
450 | Arguments for update :class:`~manim.animation.animation.Animation`.
451 | play_anim
452 | If `True`, plays the animation(s).
453 | play_anim_args
454 | Arguments for :py:meth:`Scene.play() `.
455 |
456 | Returns
457 | -------
458 | :class:`~manim.mobject.text.text_mobject.Text`
459 | Updated :attr:`__mob_label`.
460 | """
461 |
462 | # Update props of mob_label
463 | self.__update_props(mob_label_args=mob_label_args)
464 |
465 | # Remove current mob_label
466 | self.remove(self.__mob_label)
467 |
468 | # Initialize new mob_label
469 | self.__init_mobs(init_label=True)
470 |
471 | # Add new mob_label to group
472 | self.add(self.__mob_label)
473 |
474 | # Animate change
475 | if play_anim:
476 | self.__scene.play(
477 | update_anim(self.__mob_label, **update_anim_args), **play_anim_args
478 | )
479 |
480 | return self.__mob_label
481 |
482 | def animate_mob_square(self) -> "_AnimationBuilder": # type: ignore
483 | """Invokes the animate property over square mobject.
484 |
485 | Returns
486 | -------
487 | :class:`_AnimationBuilder`
488 | Animate property of :attr:`__mob_square`.
489 | """
490 |
491 | return self.__mob_square.animate
492 |
493 | def animate_mob_value(self) -> "_AnimationBuilder": # type: ignore
494 | """Invokes the animate property over value mobject.
495 |
496 | Returns
497 | -------
498 | :class:`_AnimationBuilder`
499 | Animate property of :attr:`__mob_value`.
500 | """
501 |
502 | return self.__mob_value.animate
503 |
504 | def animate_mob_index(self) -> "_AnimationBuilder": # type: ignore
505 | """Invokes the animate property over index mobject.
506 |
507 | Returns
508 | -------
509 | :class:`_AnimationBuilder`
510 | Animate property of :attr:`__mob_index`.
511 | """
512 |
513 | return self.__mob_index.animate
514 |
515 | def animate_mob_label(self) -> "_AnimationBuilder": # type: ignore
516 | """Invokes the animate property over label mobject.
517 |
518 | Returns
519 | -------
520 | :class:`_AnimationBuilder`
521 | Animate property of :attr:`__mob_label`.
522 | """
523 |
524 | return self.__mob_label.animate
525 |
526 |
527 | class MArray(VGroup):
528 | """A class that represents an array.
529 |
530 | Parameters
531 | ----------
532 | scene
533 | Specifies the scene where the object is to be rendered.
534 | arr
535 | Specifies the array to represent.
536 | label
537 | Specifies the value of the array label.
538 | index_offset
539 | Specifies the difference between successive displayable indices.
540 | index_start
541 | Specifies the starting value of displayable index.
542 | index_hex_display
543 | If `True`, displays indices in hex.
544 | hide_index
545 | If `True`, doesn't display indices.
546 | arr_dir
547 | Specifies the growth direction of the array.
548 | arr_label_pos
549 | Specifies the position of :attr:`__mob_arr_label` w.r.t :attr:`__mob_arr`.
550 | arr_label_gap
551 | Specifies the distance between :attr:`__mob_arr_label` and :attr:`__mob_arr`.
552 | mob_arr_label_args
553 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the array label.
554 | mob_square_args
555 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
556 | mob_value_args
557 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
558 | mob_index_args
559 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
560 | **kwargs
561 | Forwarded to constructor of the parent.
562 |
563 | Attributes
564 | ----------
565 | __scene : :class:`~manim.scene.scene.Scene`
566 | The scene where the object is to be rendered.
567 | __arr : :class:`list`
568 | The array to represent.
569 | __label : :class:`str`
570 | The value of the array label.
571 | __index_offset : :class:`int`
572 | The difference between successive displayable indices.
573 | __index_start : :class:`int`
574 | The starting value of displayable index.
575 | __index_hex_display : :class:`bool`
576 | If `True`, displays indices in hex.
577 | __hide_index : :class:`bool`
578 | If `True`, doesn't display indices.
579 | __arr_dir : :class:`~.m_enum.MArrayDirection`
580 | The growth direction of the array.
581 | __arr_label_pos : :class:`~.m_enum.MArrayDirection`
582 | The position of :attr:`__mob_arr_label` w.r.t :attr:`__mob_arr`.
583 | __arr_label_gap : :class:`float`
584 | The distance between :attr:`__mob_arr_label` and :attr:`__mob_arr`.
585 | __mob_arr_label_props : :class:`dict`
586 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the array label.
587 | __mob_arr : :class:`~typing.List`\0[:class:`MArrayElement`]
588 | Represents the array.
589 | __mob_arr_label : :class:`~manim.mobject.text.text_mobject.Text`
590 | Represents the array label.
591 | """
592 |
593 | __dir_map = [
594 | {"arr": UP, "index": RIGHT},
595 | {"arr": DOWN, "index": RIGHT},
596 | {"arr": RIGHT, "index": UP},
597 | {"arr": LEFT, "index": UP},
598 | ]
599 | """Maps :class:`~.m_enum.MArrayDirection` to :class:`np.ndarray`."""
600 |
601 | def __sum_elem_len(self, index_start: int, index_end: int) -> int:
602 | """Sums the side_length of all elements' square mobject present in the array between the specified range.
603 |
604 | Parameters
605 | ----------
606 | index_start
607 | Starting index of the range (inclusive).
608 | index_end
609 | Ending index of the range (inclusive).
610 |
611 | Returns
612 | -------
613 | :class:`int`
614 | Sum of `side_length`\0s of all :class:`~manim.mobject.geometry.polygram.Square` present inside :attr:`__mob_arr` in the specified range.
615 | """
616 |
617 | if (
618 | index_start < 0
619 | or index_end < 0
620 | or index_start > len(self.__mob_arr)
621 | or index_end > len(self.__mob_arr)
622 | ):
623 | raise Exception("Index out of bounds!")
624 |
625 | total_len = 0
626 | for i in range(index_start, index_end + 1):
627 | total_len += self.__mob_arr[i].fetch_mob_square().side_length
628 | return total_len
629 |
630 | def __calc_label_pos_and_mob(self) -> typing.Tuple[Square, np.ndarray]:
631 | """Calculates the position of the array label relative to one of the element's square mobjects.
632 |
633 | Returns
634 | -------
635 | :class:`~manim.mobject.geometry.polygram.Square`
636 | Square mobject next to which the array label is positioned.
637 | :class:`np.ndarray`
638 | The relative position of the array label.
639 | """
640 |
641 | # Label position is parallel to array growth direction
642 | if np.array_equal(
643 | self.__dir_map[self.__arr_label_pos.value]["arr"],
644 | self.__dir_map[self.__arr_dir.value]["arr"],
645 | ):
646 | return (
647 | self.__mob_arr[-1].fetch_mob_square(),
648 | self.__dir_map[self.__arr_label_pos.value]["arr"],
649 | )
650 | elif np.array_equal(
651 | self.__dir_map[self.__arr_label_pos.value]["arr"],
652 | -self.__dir_map[self.__arr_dir.value]["arr"],
653 | ):
654 | return (
655 | self.__mob_arr[0].fetch_mob_square(),
656 | self.__dir_map[self.__arr_label_pos.value]["arr"],
657 | )
658 |
659 | # Label position is perpendicular to array growth direction
660 | else:
661 | middle_index = len_before = len_after = 0
662 | if len(self.__mob_arr) > 1:
663 | odd_indices = len(self.__mob_arr) % 2 == 1
664 | middle_index = int(len(self.__mob_arr) / 2)
665 | len_before = self.__sum_elem_len(0, middle_index - 1)
666 | len_after = self.__sum_elem_len(
667 | middle_index + 1 if odd_indices else middle_index,
668 | len(self.__mob_arr) - 1,
669 | )
670 | return (
671 | self.__mob_arr[middle_index].fetch_mob_square(),
672 | self.__dir_map[self.__arr_label_pos.value]["arr"]
673 | + self.__dir_map[self.__arr_dir.value]["arr"]
674 | * ((len_after - len_before) / 2),
675 | )
676 |
677 | def __calc_index(self, index: int) -> typing.Union[int, str]:
678 | """Calculates the displayable index of the specified element based on attributes set at initialization.
679 |
680 | Parameters
681 | ----------
682 | index
683 | Specifies the index of the element for which to compute the displayable index.
684 |
685 | Returns
686 | -------
687 | :data:`~typing.Union`\0[:class:`int`, :class:`str`]
688 | Displayable index.
689 | """
690 |
691 | return (
692 | ""
693 | if self.__hide_index
694 | else (
695 | self.__index_start + self.__index_offset * index
696 | if self.__index_hex_display is False
697 | else hex(self.__index_start + self.__index_offset * index)
698 | )
699 | )
700 |
701 | def __calc_index_pos(self) -> np.ndarray:
702 | """Calculates the index position of all elements based on attributes set at initialization.
703 |
704 | Returns
705 | -------
706 | :class:`np.ndarray`
707 | Index position.
708 | """
709 |
710 | return (
711 | self.__dir_map[self.__arr_dir.value]["index"]
712 | if not self.__switch_index_pos
713 | else self.__dir_map[self.__arr_dir.value]["index"] * -1
714 | )
715 |
716 | def __calc_label_shift_factor(self, mob: MArrayElement) -> float:
717 | """Calculates how much to shift the array label after insertion/removal of an element.
718 |
719 | Parameters
720 | ----------
721 | mob
722 | Specifies the element that is inserted/removed.
723 |
724 | Returns
725 | -------
726 | :class:`float`
727 | Factor by which to shift the :attr:`__mob_arr_label`.
728 | """
729 |
730 | if np.array_equal(
731 | self.__dir_map[self.__arr_label_pos.value]["arr"],
732 | self.__dir_map[self.__arr_dir.value]["arr"],
733 | ):
734 | return mob.fetch_mob_square().side_length
735 | elif not np.array_equal(
736 | self.__dir_map[self.__arr_label_pos.value]["arr"],
737 | -self.__dir_map[self.__arr_dir.value]["arr"],
738 | ):
739 | return mob.fetch_mob_square().side_length / 2
740 | return 0
741 |
742 | def __append_elem(
743 | self,
744 | value,
745 | shift_label: bool = True,
746 | append_anim: Animation = Write,
747 | append_anim_args: dict = {},
748 | append_anim_target: MArrayElementComp = None,
749 | mob_square_args: dict = {},
750 | mob_value_args: dict = {},
751 | mob_index_args: dict = {},
752 | ) -> typing.List[Animation]:
753 | """Creates and inserts a new element in the array.
754 |
755 | Parameters
756 | ----------
757 | value
758 | Specifies the value of the new element.
759 | shift_label
760 | If `True`, shifts the :attr:`__mob_arr_label` to center of the array.
761 | append_anim
762 | Animation to be applied to the new element.
763 | append_anim_args
764 | Arguments for append :class:`~manim.animation.animation.Animation`.
765 | append_anim_target
766 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the append :class:`~manim.animation.animation.Animation` is to be played.
767 | mob_square_args
768 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
769 | mob_value_args
770 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
771 | mob_index_args
772 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
773 |
774 | Returns
775 | -------
776 | :data:`typing.List`\0[:class:`~manim.animation.animation.Animation`]
777 | List of append animations.
778 | """
779 |
780 | mob_value_args["text"] = value
781 | mob_index_args["text"] = self.__calc_index(len(self.__mob_arr))
782 | self.__mob_arr.append(
783 | MArrayElement(
784 | scene=self.__scene,
785 | mob_square_args=mob_square_args,
786 | mob_value_args=mob_value_args,
787 | mob_index_args=mob_index_args,
788 | index_pos=self.__calc_index_pos(),
789 | next_to_mob=self.__mob_arr[-1] if len(self.__mob_arr) else None,
790 | next_to_dir=self.__dir_map[self.__arr_dir.value]["arr"],
791 | )
792 | )
793 | self.add(self.__mob_arr[-1])
794 |
795 | anim_list = [
796 | append_anim(
797 | self.__mob_arr[-1].fetch_mob(append_anim_target), **append_anim_args
798 | )
799 | ]
800 |
801 | if shift_label:
802 | label_shift_factor = self.__calc_label_shift_factor(self.__mob_arr[-1])
803 | anim_list.append(
804 | ApplyMethod(
805 | self.__mob_arr_label.shift,
806 | self.__dir_map[self.__arr_dir.value]["arr"] * label_shift_factor,
807 | )
808 | )
809 |
810 | return anim_list
811 |
812 | def __remove_elem(
813 | self,
814 | index: int,
815 | removal_anim: Animation = FadeOut,
816 | update_anim: Animation = Indicate,
817 | removal_anim_args: dict = {},
818 | update_anim_args: dict = {},
819 | removal_anim_target: MArrayElementComp = None,
820 | update_anim_target: MArrayElementComp = MArrayElementComp.INDEX,
821 | ) -> typing.Tuple[Succession, typing.Callable[[bool], typing.List[Animation]]]:
822 | """Removes the element from the array at the specified index.
823 |
824 | Parameters
825 | ----------
826 | index
827 | Specifies the index of the element to remove.
828 | removal_anim
829 | Animation to be applied to the element being removed.
830 | update_anim
831 | Animation to be applied on remaining elements.
832 | removal_anim_args
833 | Arguments for removal :class:`~manim.animation.animation.Animation`.
834 | update_anim_args
835 | Arguments for update :class:`~manim.animation.animation.Animation`.
836 | removal_anim_target
837 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the removal :class:`~manim.animation.animation.Animation` is to be played.
838 | update_anim_target
839 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the update :class:`~manim.animation.animation.Animation` is to be played.
840 |
841 | Returns
842 | -------
843 | :class:`~manim.animation.composition.Succession`
844 | Contains :class:`~manim.animation.animation.Animation` played for removal and shifting of element(s).
845 | :data:`~typing.Callable`\0[[:class:`bool`], :class:`~typing.List`\0[:class:`~manim.animation.animation.Animation`]]
846 | Method that updates the indices of element(s) after the removed element and returns a list of update :class:`~manim.animation.animation.Animation`\0(s).
847 | """
848 |
849 | if index < 0 or index > len(self.__mob_arr):
850 | raise Exception("Index out of bounds!")
851 |
852 | self.remove(self.__mob_arr[index])
853 | removed_mob = self.__mob_arr[index]
854 | self.__mob_arr = self.__mob_arr[0:index] + self.__mob_arr[index + 1 :]
855 |
856 | anims_shift = []
857 | for i in range(index, len(self.__mob_arr)):
858 | anims_shift.append(
859 | ApplyMethod(
860 | self.__mob_arr[i].shift,
861 | -(
862 | self.__dir_map[self.__arr_dir.value]["arr"]
863 | * removed_mob.fetch_mob_square().side_length
864 | ),
865 | )
866 | )
867 |
868 | label_shift_factor = self.__calc_label_shift_factor(removed_mob)
869 |
870 | if label_shift_factor != 0:
871 | anims_shift.append(
872 | ApplyMethod(
873 | self.__mob_arr_label.shift,
874 | -self.__dir_map[self.__arr_dir.value]["arr"] * label_shift_factor,
875 | )
876 | )
877 |
878 | def update_indices(
879 | play_anim: bool = True, play_anim_args: dict = {}
880 | ) -> typing.List[Animation]:
881 | """Updates the indices of :class:`MArrayElement`(s) that occur after the removal.
882 |
883 | Parameters
884 | ----------
885 | play_anim : :class:`bool`, default: `True`
886 | Specifies whether to play the update :class:`manim.Animation`.
887 | play_anim_args : :class:`dict, default: `{}`
888 | Arguments for :meth:`manim.Scene.play`.
889 |
890 | Returns
891 | -------
892 | List[:class:`manim.Animation`]
893 | Represents :class:`Animation` for indices update.
894 | """
895 |
896 | anims_index = []
897 | for i in range(index, len(self.__mob_arr)):
898 | self.__mob_arr[i].update_mob_index(
899 | mob_index_args={"text": self.__calc_index(i)}, play_anim=False
900 | )
901 | anims_index.append(
902 | update_anim(
903 | (self.__mob_arr[i].fetch_mob(update_anim_target)),
904 | **update_anim_args
905 | )
906 | )
907 |
908 | if play_anim:
909 | self.__scene.play(*anims_index, **play_anim_args)
910 |
911 | return anims_index
912 |
913 | return (
914 | Succession(
915 | removal_anim(
916 | removed_mob.fetch_mob(removal_anim_target), **removal_anim_args
917 | ),
918 | AnimationGroup(*anims_shift),
919 | ),
920 | update_indices,
921 | )
922 |
923 | def __init_props(
924 | self,
925 | scene: Scene,
926 | arr: list,
927 | label: str,
928 | index_offset: int,
929 | index_start: int,
930 | index_hex_display: bool,
931 | hide_index: bool,
932 | arr_dir: MArrayDirection,
933 | switch_index_pos: bool,
934 | arr_label_pos: MArrayDirection,
935 | arr_label_gap: float,
936 | ) -> None:
937 | """Initializes the attributes for the class.
938 |
939 | Parameters
940 | ----------
941 | scene
942 | Specifies the scene where the object is to be rendered.
943 | arr
944 | Specifies the array to represent.
945 | label
946 | Specifies the value of the array label.
947 | index_offset
948 | Specifies the difference between successive displayable indices.
949 | index_start
950 | Specifies the starting value of displayable index.
951 | index_hex_display
952 | If `True`, displays indices in hex.
953 | hide_index
954 | If `True`, doesn't display indices.
955 | arr_dir
956 | Specifies the growth direction of the array.
957 | arr_label_pos
958 | Specifies the position of :attr:`__mob_arr_label` w.r.t :attr:`__mob_arr`.
959 | arr_label_gap
960 | Specifies the distance between :attr:`__mob_arr_label` and :attr:`__mob_arr`.
961 | """
962 |
963 | self.__mob_arr_label_props: dict = {
964 | "text": "",
965 | "color": BLUE_A,
966 | "font_size": 38,
967 | }
968 | self.__scene: Scene = scene
969 | self.__arr: typing.List[Any] = arr
970 | self.__label: str = label
971 | self.__mob_arr: typing.List[MArrayElement] = []
972 | self.__index_offset: int = index_offset
973 | self.__index_start: int = index_start
974 | self.__index_hex_display: bool = index_hex_display
975 | self.__hide_index: int = hide_index
976 | self.__arr_dir: MArrayDirection = arr_dir
977 | self.__switch_index_pos: bool = switch_index_pos
978 | self.__arr_label_pos: MArrayDirection = arr_label_pos
979 | self.__arr_label_gap: float = arr_label_gap
980 |
981 | def __update_props(
982 | self,
983 | mob_arr_label_args: dict = {},
984 | ) -> None:
985 | """Updates the attributes of the class.
986 |
987 | Parameters
988 | ----------
989 | mob_arr_label_args
990 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the array label.
991 | """
992 |
993 | self.__mob_arr_label_props["text"] = self.__label
994 | self.__mob_arr_label_props.update(mob_arr_label_args)
995 |
996 | if type(self.__mob_arr_label_props["text"]) != str:
997 | self.__mob_arr_label_props["text"] = str(self.__mob_arr_label_props["text"])
998 |
999 | def __init_mobs(
1000 | self,
1001 | init_arr_label: bool = False,
1002 | ) -> None:
1003 | """Initializes the mobjects for the class.
1004 |
1005 | Parameters
1006 | ----------
1007 | init_arr_label
1008 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_arr_label`.
1009 | """
1010 |
1011 | if init_arr_label:
1012 | self.__mob_arr_label = Text(**self.__mob_arr_label_props)
1013 | if len(self.__mob_arr):
1014 | (next_to_mob, label_pos) = self.__calc_label_pos_and_mob()
1015 | self.__mob_arr_label.next_to(
1016 | next_to_mob, label_pos, self.__arr_label_gap
1017 | )
1018 | if len(self.__mob_arr) % 2 == 0:
1019 | self.__mob_arr_label.shift(
1020 | -self.__dir_map[self.__arr_dir.value]["arr"]
1021 | * (next_to_mob.side_length / 2)
1022 | )
1023 | self.add(self.__mob_arr_label)
1024 |
1025 | def __deepcopy__(self, memo):
1026 | """Deepcopy that excludes attributes specified in `exclude_list`."""
1027 |
1028 | exclude_list = ["_MArray__scene"]
1029 |
1030 | cls = self.__class__
1031 | result = cls.__new__(cls)
1032 | memo[id(self)] = result
1033 | for k, v in self.__dict__.items():
1034 | if k not in exclude_list:
1035 | setattr(result, k, deepcopy(v, memo))
1036 | return result
1037 |
1038 | def __init__(
1039 | self,
1040 | scene: Scene,
1041 | arr: list = [],
1042 | label: str = "",
1043 | index_offset: int = 1,
1044 | index_start: int = 0,
1045 | index_hex_display: bool = False,
1046 | hide_index: bool = False,
1047 | arr_dir: MArrayDirection = MArrayDirection.RIGHT,
1048 | switch_index_pos: bool = False,
1049 | arr_label_pos: MArrayDirection = MArrayDirection.LEFT,
1050 | arr_label_gap: float = 0.5,
1051 | mob_arr_label_args: dict = {},
1052 | mob_square_args: dict = {},
1053 | mob_value_args: dict = {},
1054 | mob_index_args: dict = {},
1055 | **kwargs
1056 | ) -> None:
1057 | """Initializes the class.
1058 |
1059 | Parameters
1060 | ----------
1061 | scene
1062 | Specifies the scene where the object is to be rendered.
1063 | arr
1064 | Specifies the array to represent.
1065 | label
1066 | Specifies the value of the array label.
1067 | index_offset
1068 | Specifies the difference between successive displayable indices.
1069 | index_start
1070 | Specifies the starting value of displayable index.
1071 | index_hex_display
1072 | If `True`, displays indices in hex.
1073 | hide_index
1074 | If `True`, doesn't display indices.
1075 | arr_dir
1076 | Specifies the growth direction of the array.
1077 | arr_label_pos
1078 | Specifies the position of :attr:`__mob_arr_label` w.r.t :attr:`__mob_arr`.
1079 | arr_label_gap
1080 | Specifies the distance between :attr:`__mob_arr_label` and :attr:`__mob_arr`.
1081 | mob_arr_label_args
1082 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the array label.
1083 | mob_square_args
1084 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
1085 | mob_value_args
1086 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
1087 | mob_index_args
1088 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
1089 | **kwargs
1090 | Forwarded to constructor of the parent.
1091 | """
1092 |
1093 | super().__init__(**kwargs)
1094 |
1095 | # Initialize props
1096 | self.__init_props(
1097 | scene,
1098 | arr,
1099 | label,
1100 | index_offset,
1101 | index_start,
1102 | index_hex_display,
1103 | hide_index,
1104 | arr_dir,
1105 | switch_index_pos,
1106 | arr_label_pos,
1107 | arr_label_gap,
1108 | )
1109 |
1110 | # Update props
1111 | self.__update_props(mob_arr_label_args)
1112 |
1113 | # Append elements to __mob_arr
1114 | for v in arr:
1115 | self.__append_elem(
1116 | v,
1117 | False,
1118 | mob_square_args=mob_square_args,
1119 | mob_value_args=mob_value_args,
1120 | mob_index_args=mob_index_args,
1121 | )
1122 |
1123 | # Initialize other mobjects (e.g. __arr_label)
1124 | self.__init_mobs(True)
1125 |
1126 | def fetch_arr(self) -> list:
1127 | """Fetches the original array.
1128 |
1129 | Returns
1130 | -------
1131 | :class:`list`
1132 | :attr:`__arr`.
1133 | """
1134 |
1135 | return self.__arr
1136 |
1137 | def fetch_mob_arr(self) -> typing.List[MArrayElement]:
1138 | """Fetches the mobject array.
1139 |
1140 | Returns
1141 | -------
1142 | :class:`~typing.List`
1143 | :attr:`__mob_arr`.
1144 | """
1145 |
1146 | return self.__mob_arr
1147 |
1148 | def fetch_mob_arr_label(self) -> Text:
1149 | """Fetches the label mobject of the array.
1150 |
1151 | Returns
1152 | -------
1153 | :class:`~manim.mobject.text.text_mobject.Text`
1154 | :attr:`__mob_arr_label`.
1155 | """
1156 |
1157 | return self.__mob_arr_label
1158 |
1159 | def fetch_arr_dir(self) -> MArrayDirection:
1160 | """Fetches the growth direction enum of the array.
1161 |
1162 | Returns
1163 | -------
1164 | :class:`~.m_enum.MArrayDirection`
1165 | :attr:`__arr_dir`.
1166 | """
1167 |
1168 | return self.__arr_dir
1169 |
1170 | def update_elem_value(
1171 | self,
1172 | index: int,
1173 | value,
1174 | mob_value_args: dict = {},
1175 | update_anim: Animation = Write,
1176 | update_anim_args: dict = {},
1177 | play_anim: bool = True,
1178 | play_anim_args: dict = {},
1179 | ) -> Text:
1180 | """Updates the elements value.
1181 |
1182 | Parameters
1183 | ----------
1184 | index
1185 | Specifies the index of element whose value to update.
1186 | value
1187 | New value to be assigned to the element.
1188 | mob_value_args
1189 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
1190 | update_anim
1191 | Animation to be applied to the updated element.
1192 | update_anim_args
1193 | Arguments for update :class:`~manim.animation.animation.Animation`.
1194 | play_anim
1195 | If `True`, plays the animation(s).
1196 | play_anim_args
1197 | Arguments for :py:meth:`Scene.play() `.
1198 |
1199 | Returns
1200 | -------
1201 | :class:`~manim.mobject.text.text_mobject.Text`
1202 | Updated element's value mobject.
1203 | """
1204 |
1205 | if index < 0 or index > len(self.__mob_arr):
1206 | raise Exception("Index out of bounds!")
1207 |
1208 | self.__arr[index] = value
1209 | mob_value_args["text"] = value
1210 | return self.__mob_arr[index].update_mob_value(
1211 | mob_value_args, update_anim, update_anim_args, play_anim, play_anim_args
1212 | )
1213 |
1214 | def update_elem_index(
1215 | self,
1216 | index: int,
1217 | value,
1218 | mob_index_args: dict = {},
1219 | update_anim: Animation = Write,
1220 | update_anim_args: dict = {},
1221 | play_anim: bool = True,
1222 | play_anim_args: dict = {},
1223 | ) -> Text:
1224 | """Updates the elements index.
1225 |
1226 | Parameters
1227 | ----------
1228 | index
1229 | Specifies the index of element whose index to update.
1230 | value
1231 | New value to be assigned to the index of the element.
1232 | mob_index_args
1233 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
1234 | update_anim
1235 | Animation to be applied to the updated element.
1236 | update_anim_args
1237 | Arguments for update :class:`~manim.animation.animation.Animation`.
1238 | play_anim
1239 | If `True`, plays the animation(s).
1240 | play_anim_args
1241 | Arguments for :py:meth:`Scene.play() `.
1242 |
1243 | Returns
1244 | -------
1245 | :class:`~manim.mobject.text.text_mobject.Text`
1246 | Updated element's index mobject.
1247 | """
1248 |
1249 | if index < 0 or index > len(self.__mob_arr):
1250 | raise Exception("Index out of bounds!")
1251 |
1252 | mob_index_args["text"] = value
1253 | return self.__mob_arr[index].update_mob_index(
1254 | mob_index_args, update_anim, update_anim_args, play_anim, play_anim_args
1255 | )
1256 |
1257 | def update_mob_arr_label(
1258 | self,
1259 | label: str,
1260 | mob_arr_label_args: dict = {},
1261 | update_anim: Animation = Write,
1262 | update_anim_args: dict = {},
1263 | play_anim: bool = True,
1264 | play_anim_args: dict = {},
1265 | ) -> Text:
1266 | """Updates the array label.
1267 |
1268 | Parameters
1269 | ----------
1270 | label
1271 | New value to be assigned to the array label.
1272 | mob_label_args
1273 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the array label.
1274 | update_anim
1275 | Animation to be applied to the updated array label.
1276 | update_anim_args
1277 | Arguments for update :class:`~manim.animation.animation.Animation`.
1278 | play_anim
1279 | If `True`, plays the animation(s).
1280 | play_anim_args
1281 | Arguments for :py:meth:`Scene.play() `.
1282 |
1283 | Returns
1284 | -------
1285 | :class:`~manim.mobject.text.text_mobject.Text`
1286 | Updated :attr:`__mob_arr_label`.
1287 | """
1288 |
1289 | self.__label = label
1290 |
1291 | # Update props of mob_label
1292 | self.__update_props(mob_arr_label_args=mob_arr_label_args)
1293 |
1294 | # Remove current mob_label
1295 | self.remove(self.__mob_arr_label)
1296 |
1297 | # Initialize new mob_label
1298 | self.__init_mobs(init_arr_label=True)
1299 |
1300 | # Add new mob_label to group
1301 | self.add(self.__mob_arr_label)
1302 |
1303 | # Animate change
1304 | if play_anim:
1305 | self.__scene.play(
1306 | update_anim(self.__mob_arr_label, **update_anim_args), **play_anim_args
1307 | )
1308 |
1309 | return self.__mob_arr_label
1310 |
1311 | def animate_elem(self, index: int) -> "_AnimationBuilder": # type: ignore
1312 | """Invokes the animate property over element mobject specified.
1313 |
1314 | Parameters
1315 | ----------
1316 | index
1317 | Specifies the index of the element to animate.
1318 |
1319 | Returns
1320 | -------
1321 | :class:`_AnimationBuilder`
1322 | Animate property of :class:`MArrayElement`.
1323 | """
1324 |
1325 | if index < 0 or index > len(self.__mob_arr):
1326 | raise Exception("Index out of bounds!")
1327 |
1328 | return self.__mob_arr[index].animate
1329 |
1330 | def animate_elem_square(self, index: int) -> "_AnimationBuilder": # type: ignore
1331 | """Invokes the animate property over square mobject of the specified element.
1332 |
1333 | Parameters
1334 | ----------
1335 | index
1336 | Specifies the index of the element who's square mobject to animate.
1337 |
1338 | Returns
1339 | -------
1340 | :class:`_AnimationBuilder`
1341 | Animate property of :class:`~manim.mobject.geometry.polygram.Square`.
1342 | """
1343 |
1344 | if index < 0 or index > len(self.__mob_arr):
1345 | raise Exception("Index out of bounds!")
1346 |
1347 | return self.__mob_arr[index].animate_mob_square()
1348 |
1349 | def animate_elem_value(self, index: int) -> "_AnimationBuilder": # type: ignore
1350 | """Invokes the animate property over value mobject of the specified element.
1351 |
1352 | Parameters
1353 | ----------
1354 | index
1355 | Specifies the index of the element who's value mobject animate.
1356 |
1357 | Returns
1358 | -------
1359 | :class:`_AnimationBuilder`
1360 | Animate property of :class:`~manim.mobject.text.text_mobject.Text`.
1361 | """
1362 |
1363 | if index < 0 or index > len(self.__mob_arr):
1364 | raise Exception("Index out of bounds!")
1365 |
1366 | return self.__mob_arr[index].animate_mob_value()
1367 |
1368 | def animate_elem_index(self, index: int) -> "_AnimationBuilder": # type: ignore
1369 | """Invokes the animate property over index mobject of the specified element.
1370 |
1371 | Parameters
1372 | ----------
1373 | index
1374 | Specifies the index of the element who's index mobject animate.
1375 |
1376 | Returns
1377 | -------
1378 | :class:`_AnimationBuilder`
1379 | Animate property of :class:`~manim.mobject.text.text_mobject.Text`.
1380 | """
1381 |
1382 | if index < 0 or index > len(self.__mob_arr):
1383 | raise Exception("Index out of bounds!")
1384 |
1385 | return self.__mob_arr[index].animate_mob_index()
1386 |
1387 | def append_elem(
1388 | self,
1389 | value: Any,
1390 | append_anim: Animation = Write,
1391 | append_anim_args: dict = {},
1392 | append_anim_target: MArrayElementComp = None,
1393 | mob_square_args: dict = {},
1394 | mob_value_args: dict = {},
1395 | mob_index_args: dict = {},
1396 | play_anim: bool = True,
1397 | play_anim_args: dict = {},
1398 | ) -> typing.List[Animation]:
1399 | """Creates and inserts a new element in the array.
1400 |
1401 | Parameters
1402 | ----------
1403 | value
1404 | Specifies the value of the new element.
1405 | append_anim
1406 | Animation to be applied to the new element.
1407 | append_anim_args
1408 | Arguments for append :class:`~manim.animation.animation.Animation`.
1409 | append_anim_target
1410 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the append :class:`~manim.animation.animation.Animation` is to be played.
1411 | mob_square_args
1412 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the element body.
1413 | mob_value_args
1414 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element value.
1415 | mob_index_args
1416 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the element index.
1417 | play_anim
1418 | If `True`, plays the animation(s).
1419 | play_anim_args
1420 | Arguments for :py:meth:`Scene.play() `.
1421 |
1422 | Returns
1423 | -------
1424 | :class:`typing.List`\0[:class:`~manim.animation.animation.Animation`]
1425 | List of append animations.
1426 | """
1427 |
1428 | self.__arr.append(value)
1429 |
1430 | anim_list = self.__append_elem(
1431 | value,
1432 | mob_square_args=mob_square_args,
1433 | mob_value_args=mob_value_args,
1434 | mob_index_args=mob_index_args,
1435 | append_anim=append_anim,
1436 | append_anim_args=append_anim_args,
1437 | append_anim_target=append_anim_target,
1438 | )
1439 |
1440 | if play_anim:
1441 | self.__scene.play(*anim_list, **play_anim_args)
1442 |
1443 | return anim_list
1444 |
1445 | def remove_elem(
1446 | self,
1447 | index: int,
1448 | removal_anim: Animation = FadeOut,
1449 | update_anim: Animation = Indicate,
1450 | removal_anim_args: dict = {},
1451 | update_anim_args: dict = {},
1452 | removal_anim_target: MArrayElementComp = None,
1453 | update_anim_target: MArrayElementComp = MArrayElementComp.INDEX,
1454 | play_anim: bool = True,
1455 | play_anim_args: dict = {},
1456 | ) -> typing.Tuple[Succession, typing.Callable[[bool], typing.List[Animation]]]:
1457 | """Removes the element from the array at the specified index.
1458 |
1459 | Parameters
1460 | ----------
1461 | index
1462 | Specifies the index of the element to remove.
1463 | removal_anim
1464 | Animation to be applied to the element being removed.
1465 | update_anim
1466 | Animation to be applied on remaining elements.
1467 | removal_anim_args
1468 | Arguments for removal :class:`~manim.animation.animation.Animation`.
1469 | update_anim_args
1470 | Arguments for update :class:`~manim.animation.animation.Animation`.
1471 | removal_anim_target
1472 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the removal :class:`~manim.animation.animation.Animation` is to be played.
1473 | update_anim_target
1474 | Specifies the target :class:`~manim.mobject.mobject.Mobject` of the :class:`MArrayElement` on which the update :class:`~manim.animation.animation.Animation` is to be played.
1475 | play_anim
1476 | If `True`, plays the animation(s).
1477 | play_anim_args
1478 | Arguments for :py:meth:`Scene.play() `.
1479 |
1480 | Returns
1481 | -------
1482 | :class:`~manim.animation.composition.Succession`
1483 | Contains :class:`~manim.animation.animation.Animation` played for removal and shifting of element(s).
1484 | :data:`~typing.Callable`\0[[:class:`bool`], :class:`~typing.List`\0[:class:`~manim.animation.animation.Animation`]]
1485 | Method that updates the indices of element(s) after the removed element and returns a list of update :class:`~manim.animation.animation.Animation`\0(s).
1486 | """
1487 |
1488 | if index < 0 or index > len(self.__mob_arr):
1489 | raise Exception("Index out of bounds!")
1490 |
1491 | self.__arr = self.__arr[0:index] + self.__arr[index + 1 :]
1492 |
1493 | (remove_anim, update_indices) = self.__remove_elem(
1494 | index,
1495 | removal_anim,
1496 | update_anim,
1497 | removal_anim_args,
1498 | update_anim_args,
1499 | removal_anim_target,
1500 | update_anim_target,
1501 | )
1502 |
1503 | if play_anim:
1504 | self.__scene.play(remove_anim, **play_anim_args)
1505 | update_indices(play_anim_args=play_anim_args)
1506 |
1507 | return (remove_anim, update_indices)
1508 |
1509 |
1510 | class MArrayPointer(VGroup):
1511 | """A class that represents a pointer.
1512 |
1513 | Parameters
1514 | ----------
1515 | scene
1516 | Specifies the scene where the object is to be rendered.
1517 | arr
1518 | Specifies the array to which the pointer is to be attached.
1519 | index
1520 | Specifies the index of the element to which the pointer is to be attached.
1521 | label
1522 | Specifies the value of the pointer label.
1523 | arrow_len
1524 | Specifies the length of :attr:`__mob_arrow`.
1525 | arrow_gap
1526 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__arr`.
1527 | label_gap
1528 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__mob_label`.
1529 | pointer_pos
1530 | Specifies the position of the pointer w.r.t to :attr:`__arr`.
1531 | mob_arrow_args
1532 | Arguments for :class:`~manim.mobject.geometry.line.Arrow` that represents the pointer arrow.
1533 | mob_label_args
1534 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the pointer label.
1535 | **kwargs
1536 | Forwarded to constructor of the parent.
1537 |
1538 | Attributes
1539 | ----------
1540 | __scene : :class:`~manim.scene.scene.Scene`
1541 | The scene where the object is to be rendered.
1542 | __arr : :class:`~typing.List`\0[:class:`MArrayElement`]
1543 | The array to which the pointer is attached to.
1544 | __index : :class:`int`
1545 | The index of the element to which the pointer is attached to.
1546 | __label : :class:`str`
1547 | The value of the pointer label.
1548 | __arrow_len : :class:`float`
1549 | The length of :attr:`__mob_arrow`.
1550 | __arrow_gap : :class:`float`
1551 | The distance between :attr:`__mob_arrow` and :attr:`__arr`.
1552 | __label_gap : :class:`float`
1553 | The distance between :attr:`__mob_arrow` and :attr:`__mob_label`.
1554 | __pointer_pos : :class:`.m_enum.MArrayDirection`
1555 | The position of the pointer w.r.t to :attr:`__arr`.
1556 | __mob_arrow_props : :class:`dict`
1557 | Arguments for :class:`~manim.mobject.geometry.line.Arrow` that represents the pointer arrow.
1558 | __mob_label_props : :class:`dict`
1559 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the pointer label.
1560 | __mob_arrow : :class:`~manim.mobject.geometry.line.Arrow`
1561 | Represents the arrow of the element.
1562 | __mob_label : :class:`~manim.mobject.text.text_mobject.Text`
1563 | Represents the label of the element.
1564 | __updater_pos : :data:`typing.Callable`\0[[], None]
1565 | The updater function that keeps the pointer intact with the array.
1566 | """
1567 |
1568 | __dir_map = [
1569 | {"np": UP, "dir": MArrayDirection.UP},
1570 | {"np": DOWN, "dir": MArrayDirection.DOWN},
1571 | {"np": RIGHT, "dir": MArrayDirection.RIGHT},
1572 | {"np": LEFT, "dir": MArrayDirection.LEFT},
1573 | ]
1574 | """Maps :class:`~.m_enum.MArrayDirection` to :class:`np.ndarray`."""
1575 |
1576 | def __calc_arrow_pos(self) -> np.ndarray:
1577 | """Calculates direction vector for the arrow mobject.
1578 |
1579 | Returns
1580 | -------
1581 | :class:`np.ndarray`
1582 | Position vector for :attr:`__mob_arrow`.
1583 | """
1584 |
1585 | arr_dir_np = self.__dir_map[self.__arr.fetch_arr_dir().value]["np"]
1586 | arrow_pos_np = np.copy(self.__dir_map[self.__pointer_pos.value]["np"])
1587 |
1588 | # If array's direction and pointer's direction are not perpendicular to each other
1589 | if np.dot(arr_dir_np, arrow_pos_np):
1590 | # swap the x and y values of arrow_pos_np
1591 | arrow_pos_np[0], arrow_pos_np[1] = arrow_pos_np[1], arrow_pos_np[0]
1592 | # update the __pointer_pos accordingly
1593 | self.__pointer_pos = self.__dir_map[
1594 | (self.__pointer_pos.value + 2) % len(self.__dir_map)
1595 | ]["dir"]
1596 |
1597 | return arrow_pos_np
1598 |
1599 | def __add_updater(self) -> None:
1600 | """Attaches the position updater function with the pointer."""
1601 |
1602 | def updater_pos(mob: Mobject) -> None:
1603 | self.__init_pos()
1604 |
1605 | self.__updater_pos = updater_pos
1606 |
1607 | self.add_updater(self.__updater_pos)
1608 |
1609 | def __remove_updater(self) -> None:
1610 | """Removes the attached position updater function from the pointer."""
1611 |
1612 | self.remove_updater(self.__updater_pos)
1613 |
1614 | def __calc_shift_np(self, new_index: int) -> np.ndarray:
1615 | """Calculates how much the pointer should shift by to point to the new index.
1616 |
1617 | Parameters
1618 | ----------
1619 | new_index
1620 | Specifies the prospective index of element to which the pointer is to be attached.
1621 |
1622 | Returns
1623 | -------
1624 | :class:`np.ndarray`
1625 | A vector that represents how much the pointer should shift.
1626 | """
1627 |
1628 | to_lesser_index = False
1629 | index_start = self.__index
1630 | index_end = new_index
1631 | if index_start > index_end:
1632 | index_start, index_end = index_end, index_start
1633 | to_lesser_index = True
1634 |
1635 | return (
1636 | (
1637 | self.__arr._MArray__sum_elem_len(index_start, index_end)
1638 | - (
1639 | self.__arr.fetch_mob_arr()[self.__index]
1640 | .fetch_mob_square()
1641 | .side_length
1642 | )
1643 | )
1644 | * self.__dir_map[self.__arr.fetch_arr_dir().value]["np"]
1645 | * (-1 if to_lesser_index else 1)
1646 | )
1647 |
1648 | def __init_props(
1649 | self,
1650 | scene: Scene,
1651 | arr: MArray,
1652 | index: int,
1653 | label: str,
1654 | arrow_len: float,
1655 | arrow_gap: float,
1656 | label_gap: float,
1657 | pointer_pos: MArrayDirection,
1658 | ) -> None:
1659 | """Initializes the attributes for the class.
1660 |
1661 | Parameters
1662 | ----------
1663 | scene
1664 | Specifies the scene where the object is to be rendered.
1665 | arr
1666 | Specifies the array to which the pointer is to be attached.
1667 | index
1668 | Specifies the index of the element to which the pointer is to be attached.
1669 | label
1670 | Specifies the value of the pointer label.
1671 | arrow_len
1672 | Specifies the length of :attr:`__mob_arrow`.
1673 | arrow_gap
1674 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__arr`.
1675 | label_gap
1676 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__mob_label`.
1677 | pointer_pos
1678 | Specifies the position of the pointer w.r.t to :attr:`__arr`.
1679 | """
1680 |
1681 | self.__mob_arrow_props: dict = {"color": GOLD_D}
1682 | self.__mob_label_props: dict = {"text": label, "color": GOLD_A, "font_size": 38}
1683 | self.__scene: Scene = scene
1684 | self.__arr: MArray = arr
1685 | if index >= len(self.__arr.fetch_mob_arr()) or index < 0:
1686 | raise Exception("Index out of bounds!")
1687 | self.__index: int = index
1688 | self.__label: str = label
1689 | self.__arrow_len: float = arrow_len
1690 | self.__arrow_gap: float = arrow_gap
1691 | self.__label_gap: float = label_gap
1692 | self.__pointer_pos: MArrayDirection = pointer_pos
1693 |
1694 | def __update_props(
1695 | self, mob_arrow_args: dict = {}, mob_label_args: dict = {}
1696 | ) -> None:
1697 | """Updates the attributes of the class.
1698 |
1699 | Parameters
1700 | ----------
1701 | mob_arrow_args
1702 | Arguments for :class:`~manim.mobject.geometry.line.Arrow` that represents the pointer arrow.
1703 | mob_label_args
1704 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the pointer label.
1705 | """
1706 |
1707 | self.__mob_arrow_props.update(mob_arrow_args)
1708 | self.__mob_label_props["text"] = self.__label
1709 | self.__mob_label_props.update(mob_label_args)
1710 |
1711 | if type(self.__mob_label_props["text"]) != str:
1712 | self.__mob_label_props["text"] = str(self.__mob_label_props["text"])
1713 |
1714 | def __init_mobs(self, init_arrow: bool = False, init_label: bool = False) -> None:
1715 | """Initializes the mobjects for the class.
1716 |
1717 | Parameters
1718 | ----------
1719 | init_arrow
1720 | If `True`, instantiates a :class:`~manim.mobject.geometry.line.Arrow` and assigns it to :attr:`__mob_arrow`.
1721 | init_label
1722 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_label`.
1723 | """
1724 |
1725 | if init_arrow:
1726 | arrow_pos_np = self.__calc_arrow_pos()
1727 | self.__mob_arrow = Arrow(
1728 | start=(-arrow_pos_np + (arrow_pos_np * self.__arrow_len)),
1729 | end=-arrow_pos_np,
1730 | **self.__mob_arrow_props
1731 | )
1732 | self.__mob_arrow.next_to(
1733 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square(),
1734 | arrow_pos_np,
1735 | self.__arrow_gap,
1736 | )
1737 | self.add(self.__mob_arrow)
1738 |
1739 | if init_label:
1740 | self.__mob_label = Text(**self.__mob_label_props)
1741 | self.__mob_label.next_to(
1742 | self.__mob_arrow,
1743 | self.__dir_map[self.__pointer_pos.value]["np"],
1744 | self.__label_gap,
1745 | )
1746 | self.add(self.__mob_label)
1747 |
1748 | def __init_pos(self) -> None:
1749 | """Initializes the position of the object"""
1750 |
1751 | arrow_pos_np = self.__calc_arrow_pos()
1752 | self.next_to(
1753 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square(),
1754 | arrow_pos_np,
1755 | self.__arrow_gap,
1756 | )
1757 |
1758 | def __deepcopy__(self, memo):
1759 | """Deepcopy that excludes attributes specified in `exclude_list`."""
1760 |
1761 | exclude_list = ["_MArrayPointer__scene", "_MArrayPointer__arr"]
1762 |
1763 | cls = self.__class__
1764 | result = cls.__new__(cls)
1765 | memo[id(self)] = result
1766 | for k, v in self.__dict__.items():
1767 | if k not in exclude_list:
1768 | setattr(result, k, deepcopy(v, memo))
1769 | return result
1770 |
1771 | def __init__(
1772 | self,
1773 | scene: Scene,
1774 | arr: MArray,
1775 | index: int = 0,
1776 | label: str = "",
1777 | arrow_len: float = 1,
1778 | arrow_gap: float = 0.25,
1779 | label_gap: float = 0.25,
1780 | pointer_pos: MArrayDirection = MArrayDirection.DOWN,
1781 | mob_arrow_args: dict = {},
1782 | mob_label_args: dict = {},
1783 | **kwargs
1784 | ) -> None:
1785 | """Initializes the class.
1786 |
1787 | Parameters
1788 | ----------
1789 | scene
1790 | Specifies the scene where the object is to be rendered.
1791 | arr
1792 | Specifies the array to which the pointer is to be attached.
1793 | index
1794 | Specifies the index of the element to which the pointer is to be attached.
1795 | label
1796 | Specifies the value of the pointer label.
1797 | arrow_len
1798 | Specifies the length of :attr:`__mob_arrow`.
1799 | arrow_gap
1800 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__arr`.
1801 | label_gap
1802 | Specifies the distance between :attr:`__mob_arrow` and :attr:`__mob_label`.
1803 | pointer_pos
1804 | Specifies the position of the pointer w.r.t to :attr:`__arr`.
1805 | mob_arrow_args
1806 | Arguments for :class:`~manim.mobject.geometry.line.Arrow` that represents the pointer arrow.
1807 | mob_label_args
1808 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the pointer label.
1809 | **kwargs
1810 | Forwarded to constructor of the parent.
1811 | """
1812 |
1813 | super().__init__(**kwargs)
1814 |
1815 | # Initialize props
1816 | self.__init_props(
1817 | scene, arr, index, label, arrow_len, arrow_gap, label_gap, pointer_pos
1818 | )
1819 |
1820 | # Update props
1821 | self.__update_props(mob_arrow_args, mob_label_args)
1822 |
1823 | # Initialize mobjects
1824 | self.__init_mobs(True, True)
1825 |
1826 | # Add updater
1827 | self.__add_updater()
1828 |
1829 | def fetch_mob_arrow(self) -> Arrow:
1830 | """Fetches the arrow mobject of the pointer.
1831 |
1832 | Returns
1833 | -------
1834 | :class:`~manim.mobject.geometry.line.Arrow`
1835 | :attr:`__mob_arrow`.
1836 | """
1837 |
1838 | return self.__mob_arrow
1839 |
1840 | def fetch_mob_label(self) -> Text:
1841 | """Fetches the label mobject of the pointer.
1842 |
1843 | Returns
1844 | -------
1845 | :class:`~manim.mobject.text.text_mobject.Text`
1846 | :attr:`__mob_label`.
1847 | """
1848 |
1849 | return self.__mob_label
1850 |
1851 | def fetch_index(self) -> int:
1852 | """Fetches the index that the pointer is attached to.
1853 |
1854 | Returns
1855 | -------
1856 | :class:`int`
1857 | :attr:`__index`.
1858 | """
1859 |
1860 | return self.__index
1861 |
1862 | def update_mob_label(
1863 | self,
1864 | label: str,
1865 | mob_label_args: dict = {},
1866 | update_anim: Animation = Write,
1867 | update_anim_args: dict = {},
1868 | play_anim: bool = True,
1869 | play_anim_args: dict = {},
1870 | ) -> Text:
1871 | """Updates the pointer label.
1872 |
1873 | Parameters
1874 | ----------
1875 | label
1876 | New value to be assigned to the pointer label.
1877 | mob_label_args
1878 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the pointer label.
1879 | update_anim
1880 | Animation to be applied to the updated pointer label.
1881 | update_anim_args
1882 | Arguments for update :class:`~manim.animation.animation.Animation`.
1883 | play_anim
1884 | If `True`, plays the animation(s).
1885 | play_anim_args
1886 | Arguments for :py:meth:`Scene.play() `.
1887 |
1888 | Returns
1889 | -------
1890 | :class:`~manim.mobject.text.text_mobject.Text`
1891 | Updated :attr:`__mob_label`.
1892 | """
1893 |
1894 | self.__label = label
1895 |
1896 | # Update props of mob_label
1897 | self.__update_props(mob_label_args=mob_label_args)
1898 |
1899 | # Remove current mob_label
1900 | self.remove(self.__mob_label)
1901 |
1902 | # Initialize new mob_label
1903 | self.__init_mobs(init_label=True)
1904 |
1905 | # Add new mob_label to group
1906 | self.add(self.__mob_label)
1907 |
1908 | # Animate change
1909 | if play_anim:
1910 | self.__scene.play(
1911 | update_anim(self.__mob_label, **update_anim_args), **play_anim_args
1912 | )
1913 |
1914 | return self.__mob_label
1915 |
1916 | def animate_mob_arrow(self) -> "_AnimationBuilder": # type: ignore
1917 | """Invokes the animate property over arrow mobject.
1918 |
1919 | Returns
1920 | -------
1921 | :class:`_AnimationBuilder`
1922 | Animate property of :attr:`__mob_arrow`.
1923 | """
1924 |
1925 | return self.__mob_arrow.animate
1926 |
1927 | def animate_mob_label(self) -> "_AnimationBuilder": # type: ignore
1928 | """Invokes the animate property over label mobject.
1929 |
1930 | Returns
1931 | -------
1932 | :class:`_AnimationBuilder`
1933 | Animate property of :attr:`__mob_label`.
1934 | """
1935 |
1936 | return self.__mob_label.animate
1937 |
1938 | def shift_to_elem(
1939 | self, index: int, play_anim: bool = True, play_anim_args: dict = {}
1940 | ) -> ApplyMethod:
1941 | """Shifts pointer to the specified element.
1942 |
1943 | Parameters
1944 | ----------
1945 | index
1946 | Specifies the index of the element to which the pointer is to be shifted.
1947 | play_anim
1948 | If `True`, plays the animation(s).
1949 | play_anim_args
1950 | Arguments for :py:meth:`Scene.play() `.
1951 |
1952 | Returns
1953 | -------
1954 | :class:`~manim.animation.transform.ApplyMethod`
1955 | Shift animation.
1956 | """
1957 |
1958 | if index < 0 or index > len(self.__arr.fetch_mob_arr()):
1959 | raise Exception("Index out of bounds!")
1960 |
1961 | shift_anim = ApplyMethod(
1962 | self.shift, self.__calc_shift_np(index), suspend_mobject_updating=True
1963 | )
1964 | self.__index = index
1965 |
1966 | if play_anim:
1967 | self.__scene.play(shift_anim, **play_anim_args)
1968 |
1969 | return shift_anim
1970 |
1971 | def attach_to_elem(self, index: int) -> None:
1972 | """Attaches pointer to the specified element.
1973 |
1974 | Parameters
1975 | ----------
1976 | index
1977 | Specifies the index of the element to which the pointer is to be attached.
1978 | """
1979 |
1980 | if index < 0 or index > len(self.__arr.fetch_mob_arr()):
1981 | raise Exception("Index out of bounds!")
1982 |
1983 | self.__index = index
1984 | self.__init_pos()
1985 |
1986 |
1987 | class MArraySlidingWindow(VGroup):
1988 | """A class that represents a sliding window
1989 |
1990 | Parameters
1991 | ----------
1992 | scene
1993 | Specifies the scene where the object is to be rendered.
1994 | arr
1995 | Specifies the array to which the sliding window is to be attached.
1996 | index
1997 | Specifies the index of the element to which the sliding window is to be attached.
1998 | size
1999 | Specifies the number of elements the sliding window should enclose.
2000 | label
2001 | Specifies the value of the sliding window label.
2002 | label_gap
2003 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_window`.
2004 | label_pos
2005 | Specifies the position of the pointer w.r.t to :attr:`__mob_window`.
2006 | mob_window_args
2007 | Arguments for :class:`~manim.mobject.geometry.polygram.Rectangle` that represents the window.
2008 | mob_label_args
2009 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the window label.
2010 | **kwargs
2011 | Forwarded to constructor of the parent.
2012 |
2013 | Attributes
2014 | ----------
2015 | __scene : :class:`~manim.scene.scene.Scene`
2016 | The scene where the object is to be rendered.
2017 | __arr : :class:`~typing.List`\0[:class:`MArrayElement`]
2018 | The array to which the sliding window is to be attached.
2019 | __index : :class:`int`
2020 | The index of the element to which the sliding window is to be attached.
2021 | __size : :class:`int`
2022 | The number of elements the sliding window should enclose.
2023 | __label : :class:`str`
2024 | The value of the sliding window label.
2025 | __label_gap : :class:`float`
2026 | The distance between :attr:`__mob_label` and :attr:`__mob_window`.
2027 | __label_pos : :class:`.m_enum.MArrayDirection`
2028 | The position of the pointer w.r.t to :attr:`__mob_window`.
2029 | __mob_window_props : :class:`dict`
2030 | Arguments for :class:`~manim.mobject.geometry.polygram.Rectangle` that represents the window.
2031 | __mob_label_props : :class:`dict`
2032 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the window label.
2033 | __mob_window : :class:`~manim.mobject.geometry.polygram.Rectangle`
2034 | Represents the window of the sliding window.
2035 | __mob_label : :class:`~manim.mobject.text.text_mobject.Text`
2036 | Represents the label of the sliding window.
2037 | __updater_pos : :data:`typing.Callable`\0[[], None]
2038 | The updater function that keeps the sliding window intact with the array.
2039 | """
2040 |
2041 | __dir_map = [
2042 | {"np": UP, "dir": MArrayDirection.UP},
2043 | {"np": DOWN, "dir": MArrayDirection.DOWN},
2044 | {"np": RIGHT, "dir": MArrayDirection.RIGHT},
2045 | {"np": LEFT, "dir": MArrayDirection.LEFT},
2046 | ]
2047 | """Maps :class:`~.m_enum.MArrayDirection` to :class:`np.ndarray`."""
2048 |
2049 | def __calc_window_dim(self) -> typing.Tuple[float, float]:
2050 | """Calculates dimensions of window mobject.
2051 |
2052 | Returns
2053 | -------
2054 | :class:`float`
2055 | Height of :attr:`__mob_window`.
2056 | :class:`float`
2057 | Width of :attr:`__mob_window`.
2058 | """
2059 |
2060 | height = self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square().side_length
2061 | width = self.__arr._MArray__sum_elem_len(
2062 | self.__index, self.__index + self.__size - 1
2063 | )
2064 |
2065 | if self.__arr.fetch_arr_dir() in (MArrayDirection.UP, MArrayDirection.DOWN):
2066 | height, width = width, height
2067 |
2068 | return (height, width)
2069 |
2070 | def __calc_window_pos_np(self) -> typing.Tuple[np.ndarray, np.ndarray]:
2071 | """Calculates position vector and align vector for the window mobject.
2072 |
2073 | Returns
2074 | -------
2075 | :class:`np.ndarray`
2076 | Position vector for :attr:`__mob_window`
2077 | :class:`np.ndarray`
2078 | Align vector for :attr:`__mob_window`
2079 | """
2080 |
2081 | point_np = (
2082 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square().get_left()
2083 | )
2084 | align_np = LEFT
2085 |
2086 | arr_dir = self.__arr.fetch_arr_dir()
2087 | if arr_dir == MArrayDirection.LEFT:
2088 | point_np = (
2089 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square().get_right()
2090 | )
2091 | align_np = RIGHT
2092 | elif arr_dir == MArrayDirection.UP:
2093 | point_np = (
2094 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square().get_bottom()
2095 | )
2096 | align_np = DOWN
2097 | elif arr_dir == MArrayDirection.DOWN:
2098 | point_np = (
2099 | self.__arr.fetch_mob_arr()[self.__index].fetch_mob_square().get_top()
2100 | )
2101 | align_np = UP
2102 |
2103 | return (point_np, align_np)
2104 |
2105 | def __calc_label_pos_np(self) -> np.ndarray:
2106 | """Calculates position vector for the label mobject.
2107 |
2108 | Returns
2109 | -------
2110 | :class:`np.ndarray`
2111 | Position vector for :attr:`__mob_label`
2112 | """
2113 |
2114 | arr_dir = self.__arr.fetch_arr_dir()
2115 | # Label position is parallel to array growth direction
2116 | if np.array_equal(
2117 | self.__dir_map[self.__label_pos.value]["np"],
2118 | self.__dir_map[arr_dir.value]["np"],
2119 | ) or np.array_equal(
2120 | self.__dir_map[self.__label_pos.value]["np"],
2121 | -self.__dir_map[arr_dir.value]["np"],
2122 | ):
2123 | return self.__dir_map[(self.__label_pos.value + 2) % len(self.__dir_map)][
2124 | "np"
2125 | ]
2126 |
2127 | # Label position is perpendicular to array growth direction
2128 | else:
2129 | return self.__dir_map[self.__label_pos.value]["np"]
2130 |
2131 | def __pos_mobs(self, pos_window: bool = False, pos_label: bool = False) -> None:
2132 | """Positions mobjects of the class.
2133 |
2134 | Parameters
2135 | ----------
2136 | pos_window
2137 | If `True`, correctly positions :attr:`__mob_window`.
2138 | pos_label
2139 | If `True`, correctly positions :attr:`__mob_label`.
2140 | """
2141 |
2142 | if pos_window:
2143 | point_np, align_np = self.__calc_window_pos_np()
2144 | self.__mob_window.move_to(point_np, align_np)
2145 |
2146 | if pos_label:
2147 | self.__mob_label.next_to(
2148 | self.__mob_window,
2149 | self.__calc_label_pos_np(),
2150 | self.__label_gap,
2151 | )
2152 |
2153 | def __add_updater(self) -> None:
2154 | """Attaches the position updater function with the pointer."""
2155 |
2156 | def updater_pos(mob: Mobject) -> None:
2157 | self.__init_pos()
2158 |
2159 | self.__updater_pos = updater_pos
2160 |
2161 | self.add_updater(self.__updater_pos)
2162 |
2163 | def __remove_updater(self) -> None:
2164 | """Removes the attached position updater function from the pointer."""
2165 |
2166 | self.remove_updater(self.__updater_pos)
2167 |
2168 | def __init_props(
2169 | self,
2170 | scene: Scene,
2171 | arr: MArray,
2172 | index: int,
2173 | size: int,
2174 | label: str,
2175 | label_gap: float,
2176 | label_pos: MArrayDirection,
2177 | ) -> None:
2178 | """Initializes the attributes for the class.
2179 |
2180 | Parameters
2181 | ----------
2182 | scene
2183 | Specifies the scene where the object is to be rendered.
2184 | arr
2185 | Specifies the array to which the sliding window is to be attached.
2186 | index
2187 | Specifies the index of the element to which the sliding window is to be attached.
2188 | size
2189 | Specifies the number of elements the sliding window should enclose.
2190 | label
2191 | Specifies the value of the sliding window label.
2192 | label_gap
2193 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_window`.
2194 | label_pos
2195 | Specifies the position of the pointer w.r.t to :attr:`__mob_window`.
2196 | """
2197 |
2198 | self.__mob_window_props: dict = {"color": RED_D, "stroke_width": 10}
2199 | self.__mob_label_props: dict = {"text": label, "color": RED_A, "font_size": 38}
2200 | self.__scene: Scene = scene
2201 | self.__arr: MArray = arr
2202 | if index >= len(self.__arr.fetch_mob_arr()) or index < 0:
2203 | raise Exception("Index out of bounds!")
2204 | self.__index: int = index
2205 | if size < 1 or index + size > len(self.__arr.fetch_mob_arr()):
2206 | raise Exception("Invalid window size!")
2207 | self.__size: int = size
2208 | self.__label: str = label
2209 | self.__label_gap: float = label_gap
2210 | self.__label_pos: MArrayDirection = label_pos
2211 |
2212 | def __update_props(
2213 | self, mob_window_args: dict = {}, mob_label_args: dict = {}
2214 | ) -> None:
2215 | """Updates the attributes of the class.
2216 |
2217 | Parameters
2218 | ----------
2219 | mob_window_args
2220 | Arguments for :class:`~manim.mobject.geometry.polygram.Rectangle` that represents the window.
2221 | mob_label_args
2222 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the window label.
2223 | """
2224 |
2225 | self.__mob_window_props.update(mob_window_args)
2226 | self.__mob_label_props["text"] = self.__label
2227 | self.__mob_label_props.update(mob_label_args)
2228 |
2229 | if type(self.__mob_label_props["text"]) != str:
2230 | self.__mob_label_props["text"] = str(self.__mob_label_props["text"])
2231 |
2232 | def __init_mobs(self, init_window: bool = False, init_label: bool = False) -> None:
2233 | """Initializes the mobjects for the class.
2234 |
2235 | Parameters
2236 | ----------
2237 | init_arrow
2238 | If `True`, instantiates a :class:`~manim.mobject.geometry.polygram.Rectangle` and assigns it to :attr:`__mob_window`.
2239 | init_label
2240 | If `True`, instantiates a :class:`~manim.mobject.text.text_mobject.Text` and assigns it to :attr:`__mob_label`.
2241 | """
2242 |
2243 | if init_window:
2244 | height, width = self.__calc_window_dim()
2245 | self.__mob_window = Rectangle(
2246 | height=height, width=width, **self.__mob_window_props
2247 | )
2248 | self.__pos_mobs(pos_window=True)
2249 | self.add(self.__mob_window)
2250 |
2251 | if init_label:
2252 | self.__mob_label = Text(**self.__mob_label_props)
2253 | self.__pos_mobs(pos_label=True)
2254 | self.add(self.__mob_label)
2255 |
2256 | def __init_pos(self) -> None:
2257 | """Initializes the position of the object"""
2258 |
2259 | self.__pos_mobs(True, True)
2260 |
2261 | def __deepcopy__(self, memo):
2262 | """Deepcopy that excludes attributes specified in `exclude_list`."""
2263 |
2264 | exclude_list = ["_MArraySlidingWindow__scene", "_MArraySlidingWindow__arr"]
2265 |
2266 | cls = self.__class__
2267 | result = cls.__new__(cls)
2268 | memo[id(self)] = result
2269 | for k, v in self.__dict__.items():
2270 | if k not in exclude_list:
2271 | setattr(result, k, deepcopy(v, memo))
2272 | return result
2273 |
2274 | def __init__(
2275 | self,
2276 | scene: Scene,
2277 | arr: MArray,
2278 | index: int = 0,
2279 | size: int = 1,
2280 | label: str = "",
2281 | label_gap: float = 0.5,
2282 | label_pos: MArrayDirection = MArrayDirection.DOWN,
2283 | mob_window_args: dict = {},
2284 | mob_label_args: dict = {},
2285 | **kwargs
2286 | ) -> None:
2287 | """Initializes the class.
2288 |
2289 | Parameters
2290 | ----------
2291 | scene
2292 | Specifies the scene where the object is to be rendered.
2293 | arr
2294 | Specifies the array to which the sliding window is to be attached.
2295 | index
2296 | Specifies the index of the element to which the sliding window is to be attached.
2297 | size
2298 | Specifies the number of elements the sliding window should enclose.
2299 | label
2300 | Specifies the value of the sliding window label.
2301 | label_gap
2302 | Specifies the distance between :attr:`__mob_label` and :attr:`__mob_window`.
2303 | label_pos
2304 | Specifies the position of the pointer w.r.t to :attr:`__mob_window`.
2305 | mob_window_args
2306 | Arguments for :class:`~manim.mobject.geometry.polygram.Rectangle` that represents the window.
2307 | mob_label_args
2308 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the window label.
2309 | **kwargs
2310 | Forwarded to constructor of the parent.
2311 | """
2312 |
2313 | super().__init__(**kwargs)
2314 |
2315 | # Initialize props
2316 | self.__init_props(scene, arr, index, size, label, label_gap, label_pos)
2317 |
2318 | # Update props
2319 | self.__update_props(mob_window_args, mob_label_args)
2320 |
2321 | # Initialize mobjects
2322 | self.__init_mobs(True, True)
2323 |
2324 | # Add updater
2325 | self.__add_updater()
2326 |
2327 | def fetch_mob_window(self) -> Rectangle:
2328 | """Fetches the window mobject of the sliding window.
2329 |
2330 | Returns
2331 | -------
2332 | :class:`~manim.mobject.geometry.polygram.Rectangle`
2333 | :attr:`__mob_window`.
2334 | """
2335 |
2336 | return self.__mob_window
2337 |
2338 | def fetch_mob_label(self) -> Text:
2339 | """Fetches the label mobject of the sliding window.
2340 |
2341 | Returns
2342 | -------
2343 | :class:`~manim.mobject.text.text_mobject.Text`
2344 | :attr:`__mob_label`.
2345 | """
2346 |
2347 | return self.__mob_label
2348 |
2349 | def update_mob_label(
2350 | self,
2351 | label: str,
2352 | mob_label_args: dict = {},
2353 | update_anim: Animation = Write,
2354 | update_anim_args: dict = {},
2355 | play_anim: bool = True,
2356 | play_anim_args: dict = {},
2357 | ) -> Text:
2358 | """Updates the window label.
2359 |
2360 | Parameters
2361 | ----------
2362 | label
2363 | New value to be assigned to the window label.
2364 | mob_label_args
2365 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the window label.
2366 | update_anim
2367 | Animation to be applied to the updated window label.
2368 | update_anim_args
2369 | Arguments for update :class:`~manim.animation.animation.Animation`.
2370 | play_anim
2371 | If `True`, plays the animation(s).
2372 | play_anim_args
2373 | Arguments for :py:meth:`Scene.play() `.
2374 |
2375 | Returns
2376 | -------
2377 | :class:`~manim.mobject.text.text_mobject.Text`
2378 | Updated :attr:`__mob_label`.
2379 | """
2380 |
2381 | self.__label = label
2382 |
2383 | # Update props of mob_label
2384 | self.__update_props(mob_label_args=mob_label_args)
2385 |
2386 | # Remove current mob_label
2387 | self.remove(self.__mob_label)
2388 |
2389 | # Initialize new mob_label
2390 | self.__init_mobs(init_label=True)
2391 |
2392 | # Add new mob_label to group
2393 | self.add(self.__mob_label)
2394 |
2395 | # Animate change
2396 | if play_anim:
2397 | self.__scene.play(
2398 | update_anim(self.__mob_label, **update_anim_args), **play_anim_args
2399 | )
2400 |
2401 | return self.__mob_label
2402 |
2403 | def animate_mob_window(self) -> "_AnimationBuilder": # type: ignore
2404 | """Invokes the animate property over window mobject.
2405 |
2406 | Returns
2407 | -------
2408 | :class:`_AnimationBuilder`
2409 | Animate property of :attr:`__mob_window`.
2410 | """
2411 |
2412 | return self.__mob_window.animate
2413 |
2414 | def animate_mob_label(self) -> "_AnimationBuilder": # type: ignore
2415 | """Invokes the animate property over label mobject.
2416 |
2417 | Returns
2418 | -------
2419 | :class:`_AnimationBuilder`
2420 | Animate property of :attr:`__mob_label`.
2421 | """
2422 |
2423 | return self.__mob_label.animate
2424 |
2425 | def shift_to_elem(
2426 | self, index: int, play_anim: bool = True, play_anim_args: dict = {}
2427 | ) -> ApplyFunction:
2428 | """Shifts sliding window to the specified element.
2429 |
2430 | Parameters
2431 | ----------
2432 | index
2433 | Specifies the index of the element to which the sliding window is to be shifted.
2434 | play_anim
2435 | If `True`, plays the animation(s).
2436 | play_anim_args
2437 | Arguments for :py:meth:`Scene.play() `.
2438 |
2439 | Returns
2440 | -------
2441 | :class:`~manim.animation.transform.ApplyFunction`
2442 | Shift animation.
2443 | """
2444 |
2445 | if index >= len(self.__arr.fetch_mob_arr()) or index < 0:
2446 | raise Exception("Index out of bounds!")
2447 |
2448 | if self.__size < 1 or index + self.__size > len(self.__arr.fetch_mob_arr()):
2449 | raise Exception("Invalid window size!")
2450 |
2451 | self.__index = index
2452 | return self.resize_window(self.__size, play_anim, play_anim_args)
2453 |
2454 | def attach_to_elem(self, index: int) -> None:
2455 | """Attaches pointer to the specified element.
2456 |
2457 | Parameters
2458 | ----------
2459 | index
2460 | Specifies the index of the element to which the sliding window is to be attached.
2461 | """
2462 |
2463 | if index >= len(self.__arr.fetch_mob_arr()) or index < 0:
2464 | raise Exception("Index out of bounds!")
2465 |
2466 | if self.__size < 1 or index + self.__size > len(self.__arr.fetch_mob_arr()):
2467 | raise Exception("Invalid window size!")
2468 |
2469 | self.__index = index
2470 | self.__init_pos()
2471 |
2472 | def resize_window(
2473 | self, size: int, play_anim: bool = True, play_anim_args: dict = {}
2474 | ) -> ApplyFunction:
2475 | """Expands or shrinks the window according to the specified size.
2476 |
2477 | Parameters
2478 | ----------
2479 | size
2480 | Specifies the number of elements the sliding window should enclose.
2481 | play_anim
2482 | If `True`, plays the animation(s).
2483 | play_anim_args
2484 | Arguments for :py:meth:`Scene.play() `.
2485 |
2486 | Returns
2487 | -------
2488 | :class:`~manim.animation.transform.ApplyFunction`
2489 | Resize animation.
2490 | """
2491 |
2492 | if size < 1 or self.__index + size > len(self.__arr.fetch_mob_arr()):
2493 | raise Exception("Invalid window size!")
2494 |
2495 | self.__size = size
2496 |
2497 | # Variables for resize_and_shift method
2498 | arr_dir = self.__arr.fetch_arr_dir()
2499 | height, width = self.__calc_window_dim()
2500 | window_pos_np, window_align_np = self.__calc_window_pos_np()
2501 | label_pos_np = self.__calc_label_pos_np()
2502 |
2503 | def resize_and_shift(mob: MArraySlidingWindow) -> MArraySlidingWindow:
2504 | """Resizes and shifts the sliding window
2505 |
2506 | Returns
2507 | -------
2508 | :class:`MArraySlidingWindow`
2509 | Represents the modified mobject.
2510 | """
2511 |
2512 | if arr_dir in (MArrayDirection.UP, MArrayDirection.DOWN):
2513 | mob.__mob_window.stretch_to_fit_height(height)
2514 | else:
2515 | mob.__mob_window.stretch_to_fit_width(width)
2516 | mob.__mob_window.move_to(window_pos_np, window_align_np)
2517 | mob.__mob_label.next_to(mob.__mob_window, label_pos_np, mob.__label_gap)
2518 | return mob
2519 |
2520 | resize_anim = ApplyFunction(
2521 | resize_and_shift, self, suspend_mobject_updating=True
2522 | )
2523 |
2524 | if play_anim:
2525 | self.__scene.play(resize_anim, **play_anim_args)
2526 |
2527 | return resize_anim
2528 |
--------------------------------------------------------------------------------
/src/manim_data_structures/m_enum.py:
--------------------------------------------------------------------------------
1 | """Contains enums used throughout the package."""
2 |
3 | from enum import Enum
4 |
5 |
6 | class MArrayElementComp(Enum):
7 | """Refers to individual component :class:`~manim.mobject.mobject.Mobject`\0s of :class:`~.m_array.MArrayElement`."""
8 |
9 | BODY = 0
10 | """:class:`~manim.mobject.geometry.polygram.Square` that represents the body."""
11 |
12 | VALUE = 1
13 | """:class:`~manim.mobject.text.text_mobject.Text` that represents the value."""
14 |
15 | INDEX = 2
16 | """:class:`~manim.mobject.text.text_mobject.Text` that represents the index."""
17 |
18 | LABEL = 3
19 | """:class:`~manim.mobject.text.text_mobject.Text` that represents the label."""
20 |
21 |
22 | class MArrayDirection(Enum):
23 | """Serves as the direction for :class:`~.m_array.MArray`."""
24 |
25 | UP = 0
26 | """Upward direction."""
27 |
28 | DOWN = 1
29 | """Downward direction."""
30 |
31 | RIGHT = 2
32 | """Rightward direction."""
33 |
34 | LEFT = 3
35 | """Leftward direction."""
36 |
--------------------------------------------------------------------------------
/src/manim_data_structures/m_variable.py:
--------------------------------------------------------------------------------
1 | """Contains classes to construct variable."""
2 |
3 | from manim import *
4 |
5 | from .m_array import MArrayElement
6 |
7 |
8 | class MVariable(MArrayElement):
9 | """A class that represents a variable.
10 |
11 | Parameters
12 | ----------
13 | scene
14 | Specifies the scene where the object is to be rendered.
15 | value
16 | Specifies the value of the variable.
17 | index
18 | Specifies the index of the variable.
19 | label
20 | Specifies the label of the variable.
21 | mob_square_args
22 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the variable body.
23 | mob_value_args
24 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable value.
25 | mob_index_args
26 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable index.
27 | mob_label_args
28 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable label.
29 | **kwargs
30 | Forwarded to constructor of the parent.
31 |
32 | Attributes
33 | ----------
34 | __value : Any
35 | The value of the variable.
36 | __index : :data:`~typing.Union`\0[:class:`str`, :class:`int`]
37 | The value of the index.
38 | __label : :class:`str`
39 | The value of the label.
40 | """
41 |
42 | def __init__(
43 | self,
44 | scene: Scene,
45 | value: Any = "",
46 | index: typing.Union[str, int] = "",
47 | label: str = "",
48 | mob_square_args: dict = {},
49 | mob_value_args: dict = {},
50 | mob_index_args: dict = {},
51 | mob_label_args: dict = {},
52 | **kwargs
53 | ) -> None:
54 | """Initializes the class.
55 |
56 | Parameters
57 | ----------
58 | scene
59 | Specifies the scene where the object is to be rendered.
60 | value
61 | Specifies the value of the variable.
62 | index
63 | Specifies the index of the variable.
64 | label
65 | Specifies the label of the variable.
66 | mob_square_args
67 | Arguments for :class:`~manim.mobject.geometry.polygram.Square` that represents the variable body.
68 | mob_value_args
69 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable value.
70 | mob_index_args
71 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable index.
72 | mob_label_args
73 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable label.
74 | **kwargs
75 | Forwarded to constructor of the parent.
76 | """
77 |
78 | self.__value: Any = value
79 | self.__index: typing.Union[str, int] = index
80 | self.__label: str = label
81 |
82 | mob_value_args["text"] = value
83 | mob_index_args["text"] = index
84 | mob_label_args["text"] = label
85 |
86 | super().__init__(
87 | scene=scene,
88 | mob_square_args=mob_square_args,
89 | mob_value_args=mob_value_args,
90 | mob_index_args=mob_index_args,
91 | mob_label_args=mob_label_args,
92 | **kwargs
93 | )
94 |
95 | def fetch_value(self) -> Any:
96 | """Fetches the value of the variable.
97 |
98 | Returns
99 | -------
100 | Any
101 | :attr:`__value`.
102 | """
103 |
104 | return self.__value
105 |
106 | def fetch_index(self) -> typing.Union[str, int]:
107 | """Fetches the index of the variable.
108 |
109 | Returns
110 | -------
111 | :data:`~typing.Union`\0[:class:`str`, :class:`int`]
112 | :attr:`__index`.
113 | """
114 |
115 | return self.__index
116 |
117 | def fetch_label(self) -> str:
118 | """Fetches the label of the variable.
119 |
120 | Returns
121 | -------
122 | :class:`str`
123 | :attr:`__label`.
124 | """
125 |
126 | return self.__label
127 |
128 | def update_value(
129 | self,
130 | value: Any,
131 | mob_value_args: dict = {},
132 | update_anim: Animation = Indicate,
133 | update_anim_args: dict = {},
134 | play_anim: bool = True,
135 | play_anim_args: dict = {},
136 | ) -> Text:
137 | """Updates the value of the variable.
138 |
139 | Parameters
140 | ----------
141 | value
142 | New value to be assigned to the variable.
143 | mob_value_args
144 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable value.
145 | update_anim
146 | Animation to be applied to the updated :class:`~manim.mobject.text.text_mobject.Text`.
147 | update_anim_args
148 | Arguments for the update :class:`~manim.animation.animation.Animation`.
149 | play_anim
150 | Specifies whether to play the :class:`~manim.animation.animation.Animation`.
151 | play_anim_args
152 | Arguments for :py:meth:`Scene.play() `.
153 |
154 | Returns
155 | -------
156 | :class:`~manim.mobject.text.text_mobject.Text`
157 | Updated :attr:`__value`.
158 | """
159 |
160 | self.__value = value
161 | mob_value_args["text"] = value
162 | return self.update_mob_value(
163 | mob_value_args, update_anim, update_anim_args, play_anim, play_anim_args
164 | )
165 |
166 | def update_index(
167 | self,
168 | index: typing.Union[str, int],
169 | mob_index_args: dict = {},
170 | update_anim: Animation = Indicate,
171 | update_anim_args: dict = {},
172 | play_anim: bool = True,
173 | play_anim_args: dict = {},
174 | ) -> Text:
175 | """Updates the index of the variable.
176 |
177 | Parameters
178 | ----------
179 | index
180 | New index to be assigned to the variable.
181 | mob_index_args
182 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the variable index.
183 | update_anim
184 | Animation to be applied to the updated :class:`~manim.mobject.text.text_mobject.Text`.
185 | update_anim_args
186 | Arguments for the update :class:`~manim.animation.animation.Animation`.
187 | play_anim
188 | Specifies whether to play the :class:`~manim.animation.animation.Animation`.
189 | play_anim_args
190 | Arguments for :py:meth:`Scene.play() `.
191 |
192 | Returns
193 | -------
194 | :class:`~manim.mobject.text.text_mobject.Text`
195 | Updated :attr:`__index`.
196 | """
197 |
198 | self.__index = index
199 | mob_index_args["text"] = index
200 | return self.update_mob_index(
201 | mob_index_args, update_anim, update_anim_args, play_anim, play_anim_args
202 | )
203 |
204 | def update_label(
205 | self,
206 | label: str,
207 | mob_label_args: dict = {},
208 | update_anim: Animation = Indicate,
209 | update_anim_args: dict = {},
210 | play_anim: bool = True,
211 | play_anim_args: dict = {},
212 | ) -> Text:
213 | """Updates the label of the variable.
214 |
215 | Parameters
216 | ----------
217 | label
218 | New label to be assigned to the variable.
219 | mob_value_args
220 | Arguments for :class:`~manim.mobject.text.text_mobject.Text` that represents the label value.
221 | update_anim
222 | Animation to be applied to the updated :class:`~manim.mobject.text.text_mobject.Text`.
223 | update_anim_args
224 | Arguments for the update :class:`~manim.animation.animation.Animation`.
225 | play_anim
226 | Specifies whether to play the :class:`~manim.animation.animation.Animation`.
227 | play_anim_args
228 | Arguments for :py:meth:`Scene.play() `.
229 |
230 | Returns
231 | -------
232 | :class:`~manim.mobject.text.text_mobject.Text`
233 | Updated :attr:`__label`.
234 | """
235 |
236 | self.__value = label
237 | mob_label_args["text"] = label
238 | return self.update_mob_label(
239 | mob_label_args, update_anim, update_anim_args, play_anim, play_anim_args
240 | )
241 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drageelr/manim-data-structures/1465eefab154c4016b41e918b585e83132372782/tests/__init__.py
--------------------------------------------------------------------------------