├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE │ ├── bug_fix.md │ └── documentation.md └── workflows │ ├── comp_ver.sh │ └── publish-package.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── _static │ ├── custom.css │ ├── favicon.ico │ ├── logo-color-no-bg.svg │ └── logo-white-no-bg.svg │ ├── _templates │ └── autosummary │ │ └── class.rst │ ├── conf.py │ ├── example.rst │ ├── guides │ ├── arrays.rst │ └── index.rst │ ├── index.rst │ ├── reference │ ├── arrays.rst │ ├── enums.rst │ ├── index.rst │ └── variables.rst │ └── refsub.rst ├── poetry.lock ├── pyproject.toml ├── src └── manim_data_structures │ ├── __init__.py │ ├── m_array.py │ ├── m_enum.py │ └── m_variable.py └── tests └── __init__.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = 3 | .vscode, 4 | .git, 5 | dist, 6 | docs/build, 7 | *.__pycache__, 8 | max-complexity = 15 9 | max-line-length = 88 10 | statistics = True 11 | # Prevents some flake8-rst-docstrings errors 12 | rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc,py:meth,data 13 | rst-directives = manim, SEEALSO, seealso 14 | docstring-convention=numpy 15 | 16 | select = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W 17 | 18 | # General Compatibility 19 | extend-ignore = E203, W503, D202, D212, D213, D404 20 | 21 | # Misc 22 | F401, F403, F405, F841, E501, E731, E402, F811, F821, 23 | 24 | # Plug-in: flake8-builtins 25 | A001, A002, A003, 26 | 27 | # Plug-in: flake8-bugbear 28 | B006, B007, B008, B009, B010, B903, B950, 29 | 30 | # Plug-in: flake8-simplify 31 | SIM105, SIM106, SIM119, 32 | 33 | # Plug-in: flake8-comprehensions 34 | C901 35 | 36 | # Plug-in: flake8-pytest-style 37 | PT001, PT004, PT006, PT011, PT018, PT022, PT023, 38 | 39 | # Plug-in: flake8-docstrings 40 | D100, D101, D102, D103, D104, D105, D106, D107, 41 | D200, D202, D204, D205, D209, 42 | D301, 43 | D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414, 44 | 45 | # Plug-in: flake8-rst-docstrings 46 | RST201, RST203, RST210, RST212, RST213, RST215, 47 | RST301, RST303, 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description of the bug 11 | 12 | 13 | 14 | ## Expected behavior 15 | 16 | 17 | 18 | ## Steps to reproduce 19 | 20 | 21 |
Code for reproducing the problem 22 | 23 | ```py 24 | Paste your code here. 25 | ``` 26 | 27 |
28 | 29 | 30 | ## Additional media files 31 | 32 | 33 |
Images/GIFs 34 | 35 | 36 | 37 |
38 | 39 | 40 | ## Logs 41 |
Terminal output 42 | 43 | 44 | ``` 45 | PASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR 46 | ``` 47 | 48 | 49 | 50 |
51 | 52 | 53 | ## System specifications 54 | 55 |
System Details 56 | 57 | - OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)): 58 | - RAM: 59 | - Python version (`python/py/python3 --version`): 60 | - Installed modules (provide output from `pip list`): 61 | ``` 62 | PASTE HERE 63 | ``` 64 |
65 | 66 |
LaTeX details 67 | 68 | + LaTeX distribution (e.g. TeX Live 2020): 69 | + Installed LaTeX packages: 70 | 71 |
72 | 73 |
FFMPEG 74 | 75 | Output of `ffmpeg -version`: 76 | 77 | ``` 78 | PASTE HERE 79 | ``` 80 |
81 | 82 | ## Additional comments 83 | 84 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description of the proposed feature 11 | 12 | 13 | 14 | ## How can the proposed feature be used? 15 | 16 | 17 | 18 | ## Additional comments 19 | 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Overview: What does this pull request change? 4 | 5 | 6 | 7 | 8 | 9 | ## Motivation and Explanation: Why and how do your changes improve the library? 10 | 11 | 12 | 13 | ## Further Information and Comments 14 | 15 | 16 | 17 | 18 | 19 | ## Reviewer Checklist 20 | - [ ] The PR title is descriptive enough for the changelog, and the PR is labeled correctly 21 | - [ ] If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/bug_fix.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Changelog 9 | 11 | 12 | 13 | 14 | ## Summary of Changes 15 | 16 | 17 | ## Checklist 18 | - [ ] I have read the [Contributing Guidelines](https://github.com/drageelr/manim-data-structures/blob/main/CONTRIBUTING.md) 19 | - [ ] I have written a descriptive PR title (see top of PR template for examples) 20 | 21 | 22 | ## Reviewer Checklist 23 | - [ ] The PR title is descriptive enough 24 | - [ ] The PR is labeled appropriately 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Changelog 9 | 11 | 12 | 13 | 14 | ## Summary of Changes 15 | 16 | 17 | ## Checklist 18 | - [ ] I have read the [Contributing Guidelines](https://github.com/drageelr/manim-data-structures/blob/main/CONTRIBUTING.md) 19 | - [ ] I have written a descriptive PR title (see top of PR template for examples) 20 | 21 | 22 | ## Reviewer Checklist 23 | - [ ] The PR title is descriptive enough 24 | - [ ] The PR is labeled appropriately 25 | -------------------------------------------------------------------------------- /.github/workflows/comp_ver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | vercomp () { 3 | if [[ $1 == $2 ]] 4 | then 5 | return 0 6 | fi 7 | local IFS=. 8 | local i ver1=($1) ver2=($2) 9 | # fill empty fields in ver1 with zeros 10 | for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) 11 | do 12 | ver1[i]=0 13 | done 14 | for ((i=0; i<${#ver1[@]}; i++)) 15 | do 16 | if [[ -z ${ver2[i]} ]] 17 | then 18 | # fill empty fields in ver2 with zeros 19 | ver2[i]=0 20 | fi 21 | if ((10#${ver1[i]} > 10#${ver2[i]})) 22 | then 23 | return 1 24 | fi 25 | if ((10#${ver1[i]} < 10#${ver2[i]})) 26 | then 27 | return 2 28 | fi 29 | done 30 | return 0 31 | } 32 | 33 | testvercomp () { 34 | vercomp $1 $2 35 | case $? in 36 | 0) op='=';; 37 | 1) op='>';; 38 | 2) op='<';; 39 | esac 40 | if [[ $op != $3 ]] 41 | then 42 | echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'" && exit 1 43 | else 44 | echo "Pass: '$1 $op $2'" 45 | fi 46 | } 47 | 48 | if [[ $# == 2 ]] 49 | then 50 | testvercomp $1 $2 '>' 51 | else 52 | echo "Requires two args and " 53 | fi 54 | -------------------------------------------------------------------------------- /.github/workflows/publish-package.yml: -------------------------------------------------------------------------------- 1 | name: PYPI 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-20.04 8 | 9 | steps: 10 | - name: Checkout Repo 11 | uses: actions/checkout@v3 12 | - name: Set Up Python 13 | uses: actions/setup-python@v3 14 | with: 15 | python-version: '3.10' 16 | - name: Install Dependencies 17 | run: | 18 | sudo apt update 19 | sudo apt install -y build-essential python3-dev libcairo2-dev libpango1.0-dev ffmpeg 20 | - name: Install PyPI Package 21 | run: pip install --timeout=1000 manim-data-structures 22 | - name: Fetch PyPI Package Version 23 | id: mds_pypi_ver 24 | run: "echo MDS_PYPI_VER=$(pip show manim-data-structures | grep 'Version: ' | sed 's/^.*: //') >> $GITHUB_ENV" 25 | - name: Uninstall PyPI Package 26 | run: pip uninstall -y manim-data-structures 27 | - name: Install Poetry 28 | uses: abatilo/actions-poetry@v2 29 | with: 30 | poetry-version: '1.2.2' 31 | - name: Install Repo Package 32 | run: | 33 | poetry install 34 | pip install . 35 | - name: Fetch Repo Package Version 36 | id: mds_repo_ver 37 | run: "echo MDS_REPO_VER=$(pip show manim-data-structures | grep 'Version: ' | sed 's/^.*: //') >> $GITHUB_ENV" 38 | - name: Check Version 39 | run: | 40 | chmod +x .github/workflows/comp_ver.sh 41 | .github/workflows/comp_ver.sh "${{ env.MDS_REPO_VER }}" "${{ env.MDS_PYPI_VER }}" 42 | - name: Build Package 43 | run: poetry build 44 | - name: Create Release 45 | uses: ncipollo/release-action@v1 46 | with: 47 | artifacts: ${{ format('dist/manim_data_structures-{0}*', env.MDS_REPO_VER) }} 48 | name: ${{ format('Manim Data Structures v{0}', env.MDS_REPO_VER) }} 49 | tag: ${{ env.MDS_REPO_VER }} 50 | - name: Publish to PYPI 51 | run: | 52 | poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }} --local 53 | poetry publish 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/build 2 | dist 3 | *.DS_Store 4 | __pycache__ 5 | env 6 | playground 7 | docs/source/media 8 | generated 9 | .vscode 10 | rendering_times.csv 11 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_stages: [commit, push] 2 | fail_fast: false 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.4.0 6 | hooks: 7 | - id: check-ast 8 | name: Validate Python 9 | - id: trailing-whitespace 10 | - id: mixed-line-ending 11 | - id: end-of-file-fixer 12 | - id: check-toml 13 | - repo: https://github.com/pycqa/isort 14 | rev: 5.10.1 15 | hooks: 16 | - id: isort 17 | name: isort (python) 18 | - repo: https://github.com/psf/black 19 | rev: 22.10.0 20 | hooks: 21 | - id: black 22 | - repo: https://github.com/PyCQA/flake8 23 | rev: 6.0.0 24 | hooks: 25 | - id: flake8 26 | additional_dependencies: 27 | [ 28 | flake8-bugbear==22.10.27, 29 | flake8-builtins==2.0.1, 30 | flake8-comprehensions==3.10.1, 31 | flake8-docstrings==1.6.0, 32 | flake8-rst-docstrings==0.3.0, 33 | flake8-simplify==0.19.3, 34 | ] 35 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | # You can also specify other tool versions: 14 | # nodejs: "16" 15 | # rust: "1.55" 16 | # golang: "1.17" 17 | apt_packages: 18 | - libcairo2-dev 19 | - libpango1.0-dev 20 | - ffmpeg 21 | 22 | # Build documentation in the docs/ directory with Sphinx 23 | sphinx: 24 | configuration: docs/source/conf.py 25 | 26 | # If using Sphinx, optionally build your docs in additional formats such as PDF 27 | # formats: 28 | # - pdf 29 | 30 | # Optionally declare the Python requirements required to build your docs 31 | python: 32 | install: 33 | - requirements: docs/requirements.txt 34 | - method: pip 35 | path: . 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.1.7] - 2023-01-09 9 | 10 | ### PRS 11 | 12 | - [#9](https://github.com/drageelr/manim-data-structures/pull/9) 13 | - `MArraySlidingWindow` added. 14 | 15 | - [#8](https://github.com/drageelr/manim-data-structures/pull/8) 16 | - Sphinx extensions added (intersphinx, napolean, viewcode, autodoc_typehints). 17 | - Substitution reference file added `refsub.rst` and utilized in Animating Arrays guide. 18 | - Docstrings of all classes updated. 19 | 20 | ## [0.1.6] - 2022-12-26 21 | 22 | ### PRS 23 | 24 | - [#5](https://github.com/drageelr/manim-data-structures/pull/5) 25 | - `MArrayElement` & `MArray` & `MVariable`play animations by themselves. 26 | - `MArrayPointer` added. 27 | 28 | ## [0.1.5] - 2022-12-10 29 | 30 | ### PRs 31 | 32 | - [#1](https://github.com/drageelr/manim-data-structures/pull/1): 33 | - `MVariable` added. 34 | - `MArray.remove_elem()` added. 35 | - `MArray.append_elem()` changed. 36 | - `MArray` label and fetch method added. 37 | - Generic `MArrayElement` sub-mobjects fetch method added. 38 | - `MArrayElementComp` enum added. 39 | - Changed `array.py` to `m_array.py`. 40 | - Documentation updated. 41 | 42 | ## [0.1.4] - 2022-11-27 43 | 44 | ### Added 45 | 46 | - [`MArray`](https://github.com/drageelr/manim-data-structures/blob/251d6ff130243e4408ef6a9453cc7ad27f62d372/src/manim_data_structures/array.py#L292) class can now grow in any of the four directions; Up, Down, Right & Left. 47 | - [`MArray`](https://github.com/drageelr/manim-data-structures/blob/251d6ff130243e4408ef6a9453cc7ad27f62d372/src/manim_data_structures/array.py#L292) class has hidden indices now. 48 | 49 | ## [0.1.3] - 2022-11-25 50 | 51 | ### Changed 52 | 53 | - [`MArrayElement`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L6) method `fetch_mob_text` changed to [`fetch_mob_value`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L147). 54 | - [`MArrayElement`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L6) method `animate_mob_text` changed to [`animate_mob_value`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L220). 55 | 56 | ## [0.1.2] - 2022-11-25 57 | 58 | ### Added 59 | 60 | - Added doc strings to [`MArrayElement`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L6) class. 61 | - Added doc strings to [`MArray`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L243) class. 62 | 63 | ## [0.1.1] - 2022-11-24 64 | 65 | ### Changed 66 | 67 | - Minimum python version requirement changed from `3.11` to `3.7`. 68 | 69 | ## [0.1.0] - 2022-11-24 70 | 71 | ### Added 72 | 73 | - [`MArrayElement`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L6) class to represent an array element. 74 | - [`MArray`](https://github.com/drageelr/manim-data-structures/blob/1854335f2311c3157f19e6d328165013fc64cbf6/src/manim_data_structures/array.py#L243) class to represent an array. 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Setup 4 | 5 | ### Install git 6 | For instructions see https://git-scm.com/. 7 | 8 | ### Fork the project 9 | Go to https://github.com/drageelr/manim-data-structures and click the "fork" button. 10 | 11 | ### Clone your fork 12 | ```bash 13 | git clone https://github.com//manim-data-structures.git 14 | ``` 15 | Once your fork is cloned, change the directory to enter the project folder: 16 | ```bash 17 | cd manim-data-structures 18 | ``` 19 | 20 | ### Add upstream repository 21 | ```bash 22 | git remote add upstream https://github.com/drageelr/manim-data-structures.git 23 | ``` 24 | Now, `git remote -v` should show two remotes: 25 | * `origin`: Your forked repository. 26 | * `upstream`: The Manim Data Structures repository 27 | 28 | ### Install dependencies 29 | * Install [Poetry](https://python-poetry.org/) by following the instructions on this [link](https://python-poetry.org/docs/master/#installing-with-the-official-installer). 30 | * Run `poetry install` inside the fork directory to install all dependencies. This command also creates a virtual environment which you can later enter by running `poetry shell` from within the forked directory. 31 | * Install pre-commit by running `poetry run pre-commit install`. This ensures that each commit is properly formatted against the linters `black`, `flake8` and `isort`. 32 | 33 | ## Development 34 | 35 | ### Fetch the latest code from upstream 36 | ```bash 37 | git checkout dev 38 | git pull upstream dev 39 | git push origin dev 40 | ``` 41 | 42 | ### Initiate a PR 43 | Once you have finalized your contribution, navigate to this [link](https://github.com/drageelr/manim-data-structures/pulls) to create a new pull request and submit it. 44 | 45 | ### Closing note 46 | Once your PR is approved, it will be merged into the `dev` branch and eventually your contribution will make it through to the next release. 47 | 48 | Thanks for contributing 😁! 49 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hammad Nasir 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Light Mode Logo 4 | 5 |
6 |
7 |

8 | PyPI Latest Release 9 | MIT License 10 | Code style: black 11 | Documentation Status 12 | Downloads 13 | 14 |
15 |
16 | A plugin that contains common data structures to create Manimations. 17 |

18 | 19 | ## Installation 20 | To install, simply run the following command: 21 | ``` 22 | pip install manim-data-structures 23 | ``` 24 | 25 | ## Importing 26 | Simply use the following line of code to import the package: 27 | ```python 28 | from manim_data_structures import * 29 | ``` 30 | 31 | ## Usage 32 | ### Code 33 | ```python 34 | class MainScene(Scene): 35 | def construct(self): 36 | # Create an array 37 | arr = MArray([8, 7, 6, 5, 4]) 38 | self.play(Create(arr)) 39 | 40 | # Animate array 41 | self.play(arr.animate.shift(UP * 2.5 + LEFT * 5)) 42 | 43 | # Animate array element 44 | self.play(arr.animate_elem(3).shift(DOWN * 0.5)) 45 | 46 | # Animate array element mobjects 47 | self.play(arr.animate_elem_square(0).set_fill(BLACK), arr.animate_elem_value(0).rotate(PI / 2).set_fill(RED), arr.animate_elem_index(0).rotate(PI / 2)) 48 | 49 | # Display array with hex values 50 | arr2 = MArray([0, 2, 4, 6, 8], index_hex_display=True, index_offset=4) 51 | self.play(Create(arr2)) 52 | self.play(arr2.animate.shift(DOWN * 2.5 + LEFT * 5)) 53 | 54 | # Create customized array 55 | arr3 = MArray([1, 1, 2], mob_square_args={'color': GRAY_A, 'fill_color': RED_E, 'side_length': 0.5}, mob_value_args={'color': GOLD_A, 'font_size': 28}, mob_index_args={'color': RED_E, 'font_size': 22}) 56 | self.play(Create(arr3)) 57 | 58 | # Append element 59 | self.play(Write(arr2.append_elem(10))) 60 | 61 | # Append customized element 62 | self.play(Write(arr2.append_elem(12, mob_square_args={'fill_color': BLACK}))) 63 | 64 | # Update value of element 65 | self.play(Write(arr2.update_elem_value(3, 0, mob_value_args={'color': RED})), arr2.animate_elem_square(3).set_fill(WHITE)) 66 | 67 | self.wait() 68 | ``` 69 | 70 | ### Output 71 | 72 | 73 | https://user-images.githubusercontent.com/56049229/203757924-6f3aed6d-e870-468f-a269-a572350355b1.mp4 74 | 75 | 76 | ## Other Links 77 | 78 | - [Official Documentation](https://manim-data-structures.readthedocs.io/en/latest/) 79 | - [Changelog](https://github.com/drageelr/manim-data-structures/blob/main/CHANGELOG.md) 80 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | manim 2 | furo 3 | sphinx-autodoc-typehints 4 | -------------------------------------------------------------------------------- /docs/source/_static/custom.css: -------------------------------------------------------------------------------- 1 | @media (prefers-color-scheme: dark) { 2 | span.nc { 3 | text-decoration: none !important; 4 | } 5 | } 6 | 7 | .admonition-manim-example { 8 | padding: 0; 9 | display: flex; 10 | flex-direction: column; 11 | } 12 | 13 | .admonition-manim-example p.admonition-title { 14 | font-weight: 600; 15 | font-size: 0.925rem; 16 | margin: 0; 17 | } 18 | 19 | .admonition-manim-example .highlight-python { 20 | margin: 0; 21 | } 22 | 23 | .admonition-manim-example .highlight { 24 | border-radius: 0; 25 | } 26 | 27 | .admonition-manim-example .highlight pre { 28 | font-size: 15px; 29 | } 30 | 31 | .manim-video { 32 | width: 100%; 33 | padding: 8px 0; 34 | outline: 0; 35 | } 36 | 37 | .admonition-manim-example .manim-video { 38 | padding: 0; 39 | } 40 | 41 | .admonition-manim-example img { 42 | margin-bottom: 0; 43 | } 44 | 45 | .admonition-manim-example p:last-child { 46 | margin-top: 0; 47 | padding-left: 0.5rem; 48 | padding-bottom: 0.15rem; 49 | font-size: 15px; 50 | } 51 | 52 | .admonition-manim-example .copybtn { 53 | margin-right: 6px; 54 | font-size: 18px; 55 | } 56 | 57 | .admonition-manim-example .copybtn:hover { 58 | cursor: pointer; 59 | } 60 | 61 | p.rubric{ 62 | text-transform: capitalize; 63 | font-size: 1.25rem; 64 | font-weight: bold; 65 | } 66 | 67 | .sig-param{ 68 | color: var(--color-content-foreground); 69 | } 70 | 71 | dl.c .field-list dt, dl.cpp .field-list dt, dl.js .field-list dt, dl.py .field-list dt { 72 | text-transform: capitalize; 73 | font-weight: bold; 74 | font-size: var(--font-size--normal); 75 | } 76 | 77 | h4, h5, h6{ 78 | text-transform: none; 79 | } 80 | 81 | /* yikes-ish attempt at bugfix for navbar on some browsers */ 82 | .sidebar-tree a.internal.reference { 83 | display: table-cell; 84 | } 85 | -------------------------------------------------------------------------------- /docs/source/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drageelr/manim-data-structures/1465eefab154c4016b41e918b585e83132372782/docs/source/_static/favicon.ico -------------------------------------------------------------------------------- /docs/source/_static/logo-color-no-bg.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/source/_static/logo-white-no-bg.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ name | escape | underline}} 2 | 3 | Qualified name: ``{{ fullname | escape }}`` 4 | 5 | .. currentmodule:: {{ module }} 6 | 7 | .. autoclass:: {{ name }} 8 | :show-inheritance: 9 | :members: 10 | 11 | {% block methods %} 12 | {%- if methods %} 13 | .. rubric:: {{ _('Methods') }} 14 | 15 | .. autosummary:: 16 | :nosignatures: 17 | {% for item in methods if item != '__init__' and item not in inherited_members %} 18 | ~{{ name }}.{{ item }} 19 | {%- endfor %} 20 | {%- endif %} 21 | {%- endblock %} 22 | 23 | {% block attributes %} 24 | {%- if attributes %} 25 | .. rubric:: {{ _('Inherited Attributes') }} 26 | 27 | .. autosummary:: 28 | {% for item in attributes if item in inherited_members %} 29 | ~{{ name }}.{{ item }} 30 | {%- endfor %} 31 | {%- endif %} 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import os 7 | import sys 8 | from pathlib import Path 9 | 10 | import manim_data_structures 11 | 12 | # -- Project information ----------------------------------------------------- 13 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 14 | 15 | project = "Manim Data Structures" 16 | copyright = "2022, Hammad Nasir (aka DrageelR)" 17 | author = "Hammad Nasir (aka DrageelR)" 18 | release = manim_data_structures.__version__ 19 | 20 | # -- General configuration --------------------------------------------------- 21 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 22 | 23 | extensions = [ 24 | "sphinx.ext.duration", 25 | "sphinx.ext.autodoc", 26 | "sphinx.ext.autosummary", 27 | "sphinx.ext.intersphinx", 28 | "sphinx.ext.viewcode", 29 | "manim.utils.docbuild.manim_directive", 30 | "sphinx.ext.napoleon", 31 | "sphinx_autodoc_typehints", 32 | ] 33 | 34 | templates_path = ["_templates"] 35 | exclude_patterns = [] 36 | 37 | # displays shorter function names that are documented via autodoc - sphinx.ext.autosummary 38 | add_module_names = False 39 | 40 | # displays type hint defaults - sphinx_autodoc_typehints 41 | typehints_defaults = "comma" 42 | 43 | # allows external documentation to be referred - sphinx.ext.intersphinx 44 | intersphinx_mapping = { 45 | "python": ("https://docs.python.org/3", None), 46 | "manim": ("https://docs.manim.community/en/stable/", None), 47 | } 48 | 49 | # -- Options for HTML output ------------------------------------------------- 50 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 51 | 52 | html_theme = "furo" 53 | html_favicon = str(Path("_static/favicon.ico")) 54 | html_static_path = ["_static"] 55 | html_title = f"Manim Data Structures v{manim_data_structures.__version__}" 56 | html_css_files = ["custom.css"] 57 | 58 | html_theme_options = { 59 | "source_repository": "https://github.com/ManimCommunity/manim/", 60 | "source_branch": "main", 61 | "source_directory": "docs/source/", 62 | "top_of_page_button": None, 63 | "light_logo": "logo-color-no-bg.svg", 64 | "dark_logo": "logo-white-no-bg.svg", 65 | } 66 | -------------------------------------------------------------------------------- /docs/source/example.rst: -------------------------------------------------------------------------------- 1 | .. include:: ./refsub.rst 2 | 3 | Example Gallery 4 | =============== 5 | 6 | Find Pair Sum In Sorted MArray 7 | ------------------------------ 8 | 9 | The code snippet below uses the famous two pointer technique to find the pair sum ``17`` in the sorted array ``[2, 3, 5, 8, 9, 10, 11]``. 10 | 11 | .. manim:: PairSumExample 12 | :quality: low 13 | 14 | from manim_data_structures import * 15 | 16 | class PairSumExample(Scene): 17 | def isPairSumAnim(self, arr, n, val): 18 | p_i = MArrayPointer(self, arr, 0, 'i', mob_arrow_args={'color': GREEN}, mob_label_args={'color': GREEN}) 19 | p_j = MArrayPointer(self, arr, n - 1, 'j', mob_arrow_args={'color': YELLOW}, mob_label_args={'color': YELLOW}) 20 | pair_sum = MVariable(self, 0, label='Sum') 21 | pair_sum.shift(DOWN * 2) 22 | 23 | self.play(Create(pair_sum)) 24 | self.play(Create(p_i), Create(p_j)) 25 | 26 | while (p_i.fetch_index() < p_j.fetch_index()): 27 | pair_sum.update_value(arr.fetch_arr()[p_i.fetch_index()] + arr.fetch_arr()[p_j.fetch_index()]) 28 | 29 | if (pair_sum.fetch_value() == val): 30 | self.play(pair_sum.fetch_mob_square().animate.set(fill_color=GREEN)) 31 | return True 32 | elif(pair_sum.fetch_value() < val): 33 | p_i.shift_to_elem(p_i.fetch_index() + 1) 34 | else: 35 | p_j.shift_to_elem(p_j.fetch_index() - 1) 36 | 37 | self.play(pair_sum.fetch_mob_square().aniamte.set(fill_color=RED)) 38 | return False 39 | 40 | def construct(self): 41 | arr = MArray(self, [2, 3, 5, 8, 9, 10, 11], label='Array') 42 | arr.shift(UP + LEFT * 2) 43 | self.add(arr) 44 | self.isPairSumAnim(arr, 7, 17) 45 | self.wait(1) 46 | 47 | Maxmimum Sum of K Consecutive Integers in MArray 48 | ------------------------------------------------ 49 | 50 | The code snippet below uses the sliding window technique to find the maximum sum of ``k = 4`` consecutive elements in the array ``[1, 4, 2, 10, 2, 3, 1, 0, 20]`` 51 | 52 | .. manim:: PairSumExample 53 | :quality: low 54 | 55 | from manim_data_structures import * 56 | 57 | class PairSumExample(Scene): 58 | def maxSumAnim(self, marr: MArray, k): 59 | arr = marr.fetch_arr() 60 | n = len(arr) 61 | 62 | window = MArraySlidingWindow(self, marr, 0, k, 'Window') 63 | var_window_sum = MVariable(self, sum(arr[:k]), label='Window Sum') 64 | var_max_sum = MVariable(self, var_window_sum.fetch_value(), label='Max Sum') 65 | var_window_sum.shift(DOWN) 66 | var_max_sum.shift(DOWN * 2.5) 67 | 68 | self.play(Create(window)) 69 | self.play(Create(var_window_sum), Create(var_max_sum)) 70 | 71 | for i in range(n - k): 72 | window.shift_to_elem(i + 1) 73 | var_window_sum.update_value(var_window_sum.fetch_value() - arr[i] + arr[i + k]) 74 | if var_window_sum.fetch_value() > var_max_sum.fetch_value(): 75 | var_max_sum.update_value(var_window_sum.fetch_value()) 76 | 77 | 78 | self.play(var_max_sum.fetch_mob_square().animate.set(fill_color=GREEN)) 79 | return var_max_sum.fetch_value() 80 | 81 | def construct(self): 82 | arr = MArray(self, [1, 4, 2, 10, 2, 3, 1, 0, 20], label='Array') 83 | arr.shift(UP * 1.5 + LEFT * 4) 84 | self.add(arr) 85 | self.maxSumAnim(arr, 4) 86 | self.wait(1) 87 | -------------------------------------------------------------------------------- /docs/source/guides/arrays.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../refsub.rst 2 | 3 | Animating Arrays 4 | ================ 5 | 6 | Manim Array - MArray 7 | -------------------- 8 | 9 | The most basic data structure this package provides is the |MArray| (short for Manim Array 😄). To create a |MArray| simply create an instance by passing a python |list|. 10 | 11 | .. code-block:: python 12 | :linenos: 13 | 14 | class MyScene(Scene): 15 | def construct(self): 16 | arr = MArray(self, [1, 2, 3]) 17 | self.play(Create(arr)) 18 | self.wait(1) 19 | 20 | .. raw:: html 21 | 22 |
23 | 24 | .. manim:: MyScene 25 | :hide_source: 26 | :quality: low 27 | 28 | from manim_data_structures import * 29 | 30 | class MyScene(Scene): 31 | def construct(self): 32 | arr = MArray(self, [1, 2, 3]) 33 | self.play(Create(arr)) 34 | self.wait(1) 35 | 36 | Animating MArray 37 | ~~~~~~~~~~~~~~~~ 38 | 39 | To animate the |MArray|, simply invoke the |Mobject.animate| property as shown below: 40 | 41 | .. code-block:: python 42 | :linenos: 43 | 44 | self.play(arr.animate.shift(UP * 2 + LEFT * 5)) 45 | 46 | .. raw:: html 47 | 48 |
49 | 50 | .. manim:: MyScene 51 | :hide_source: 52 | :quality: low 53 | 54 | from manim_data_structures import * 55 | 56 | class MyScene(Scene): 57 | def construct(self): 58 | arr = MArray(self, [1, 2, 3]) 59 | self.play(Create(arr)) 60 | self.play(arr.animate.shift(UP * 2 + LEFT * 5)) 61 | self.wait(1) 62 | 63 | Moreover, you can also use the |MArray.animate_elem| method to animate a single element of the |MArray| as well: 64 | 65 | .. code-block:: python 66 | :linenos: 67 | 68 | self.play(arr.animate_elem(1).shift(DOWN)) 69 | 70 | .. raw:: html 71 | 72 |
73 | 74 | .. manim:: MyScene 75 | :hide_source: 76 | :quality: low 77 | 78 | from manim_data_structures import * 79 | 80 | class MyScene(Scene): 81 | def construct(self): 82 | arr = MArray(self, [1, 2, 3]) 83 | self.play(Create(arr)) 84 | self.play(arr.animate_elem(1).shift(DOWN)) 85 | self.wait(1) 86 | 87 | Lastly, you can also animate the body, value and the index of any element using the |MArray.animate_elem_square|, |MArray.animate_elem_value| and |MArray.animate_elem_index| respectively. 88 | 89 | .. code-block:: python 90 | :linenos: 91 | 92 | self.play( 93 | arr.animate_elem_square(1).set_fill(BLACK), 94 | arr.animate_elem_value(1).set_fill(RED), 95 | arr.animate_elem_index(1).rotate(PI / 2) 96 | ) 97 | 98 | .. raw:: html 99 | 100 |
101 | 102 | .. manim:: MyScene 103 | :hide_source: 104 | :quality: low 105 | 106 | from manim_data_structures import * 107 | 108 | class MyScene(Scene): 109 | def construct(self): 110 | arr = MArray(self, [1, 2, 3]) 111 | self.play(Create(arr)) 112 | self.play( 113 | arr.animate_elem_square(1).set_fill(BLACK), 114 | arr.animate_elem_value(1).set_fill(RED), 115 | arr.animate_elem_index(1).rotate(PI / 2) 116 | ) 117 | self.wait(1) 118 | 119 | Customizing MArray 120 | ~~~~~~~~~~~~~~~~~~ 121 | 122 | The |MArray| also allows you to alter the way your array looks. While creating your array pass arguments to |Square| (used to represent the element body) and |Text| (used to represent the element value and index) mobjects. 123 | 124 | .. code-block:: python 125 | :linenos: 126 | 127 | arr = MArray( 128 | self, 129 | [1, 2, 3], 130 | mob_square_args={'fill_color': RED_D}, 131 | mob_value_args={'color': BLACK}, 132 | mob_index_args={'color': GOLD_A} 133 | ) 134 | 135 | .. raw:: html 136 | 137 |
138 | 139 | .. manim:: MyScene 140 | :hide_source: 141 | :quality: low 142 | 143 | from manim_data_structures import * 144 | 145 | class MyScene(Scene): 146 | def construct(self): 147 | arr = MArray( 148 | self, 149 | [1, 2, 3], 150 | mob_square_args={'fill_color': RED_D}, 151 | mob_value_args={'color': BLACK}, 152 | mob_index_args={'color': GOLD_A} 153 | ) 154 | self.play(Create(arr)) 155 | self.wait(1) 156 | 157 | Growth Direction 158 | ^^^^^^^^^^^^^^^^ 159 | 160 | Furthermore, you can also create |MArray| that grows in different directions (e.g. up, down, right and left etc.). 161 | 162 | To do this, simply pass your preferred direction enum from |MArrayDirection| as the ``arr_dir`` argument to the constructor. The code snippet below generates four different arrays in each direction. 163 | 164 | .. code-block:: python 165 | :linenos: 166 | 167 | class MyScene(Scene): 168 | def construct(self): 169 | arr_up = MArray(self, [1, 2], arr_dir=MArrayDirection.UP) 170 | arr_right = MArray(self, [3, 4], arr_dir=MArrayDirection.RIGHT) 171 | arr_down = MArray(self, [5, 6], arr_dir=MArrayDirection.DOWN) 172 | arr_left = MArray(self, [7, 8], arr_dir=MArrayDirection.LEFT) 173 | 174 | self.play(Create(arr_up)) 175 | self.play(arr_up.animate.shift(UP * 2)) 176 | self.play(Create(arr_right)) 177 | self.play(arr_right.animate.shift(RIGHT * 2)) 178 | self.play(Create(arr_down)) 179 | self.play(arr_down.animate.shift(DOWN * 2)) 180 | self.play(Create(arr_left)) 181 | self.play(arr_left.animate.shift(LEFT * 2)) 182 | 183 | self.wait(1) 184 | 185 | .. raw:: html 186 | 187 |
188 | 189 | .. manim:: MyScene 190 | :hide_source: 191 | :quality: low 192 | 193 | from manim_data_structures import * 194 | 195 | class MyScene(Scene): 196 | def construct(self): 197 | arr_up = MArray(self, [1, 2], arr_dir=MArrayDirection.UP) 198 | arr_right = MArray(self, [3, 4], arr_dir=MArrayDirection.RIGHT) 199 | arr_down = MArray(self, [5, 6], arr_dir=MArrayDirection.DOWN) 200 | arr_left = MArray(self, [7, 8], arr_dir=MArrayDirection.LEFT) 201 | 202 | self.play(Create(arr_up)) 203 | self.play(arr_up.animate.shift(UP * 2)) 204 | self.play(Create(arr_right)) 205 | self.play(arr_right.animate.shift(RIGHT * 2)) 206 | self.play(Create(arr_down)) 207 | self.play(arr_down.animate.shift(DOWN * 2)) 208 | self.play(Create(arr_left)) 209 | self.play(arr_left.animate.shift(LEFT * 2)) 210 | 211 | self.wait(1) 212 | 213 | Array Label 214 | ^^^^^^^^^^^ 215 | 216 | For an |MArray|, you can also a label with the array via specifying the ``label`` argument. 217 | 218 | Similar to how we specify the growth direction using |MArrayDirection| enum, we can dictate the position of the label. 219 | 220 | .. code-block:: python 221 | :linenos: 222 | 223 | class MyScene(Scene): 224 | def construct(self): 225 | arr_label_left = MArray(self, [1, 2, 3], label='Arr') 226 | arr_label_right = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.RIGHT) 227 | arr_label_down = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.DOWN) 228 | arr_label_up = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.UP, arr_label_gap=0.75) 229 | 230 | self.play(Create(arr_label_left)) 231 | self.play(arr_label_left.animate.shift(UP * 2 + LEFT * 4)) 232 | self.play(Create(arr_label_right)) 233 | self.play(arr_label_right.animate.shift(DOWN * 2 + LEFT * 4)) 234 | self.play(Create(arr_label_down)) 235 | self.play(arr_label_down.animate.shift(UP * 2 + RIGHT)) 236 | self.play(Create(arr_label_up)) 237 | self.play(arr_label_up.animate.shift(DOWN * 2 + RIGHT)) 238 | 239 | self.wait(1) 240 | 241 | .. raw:: html 242 | 243 |
244 | 245 | .. manim:: MyScene 246 | :hide_source: 247 | :quality: low 248 | 249 | from manim_data_structures import * 250 | 251 | class MyScene(Scene): 252 | def construct(self): 253 | arr_label_left = MArray(self, [1, 2, 3], label='Arr') 254 | arr_label_right = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.RIGHT) 255 | arr_label_down = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.DOWN) 256 | arr_label_up = MArray(self, [1, 2, 3], label='Arr', arr_label_pos=MArrayDirection.UP, arr_label_gap=0.75) 257 | 258 | self.play(Create(arr_label_left)) 259 | self.play(arr_label_left.animate.shift(UP * 2 + LEFT * 4)) 260 | self.play(Create(arr_label_right)) 261 | self.play(arr_label_right.animate.shift(DOWN * 2 + LEFT * 4)) 262 | self.play(Create(arr_label_down)) 263 | self.play(arr_label_down.animate.shift(UP * 2 + RIGHT)) 264 | self.play(Create(arr_label_up)) 265 | self.play(arr_label_up.animate.shift(DOWN * 2 + RIGHT)) 266 | 267 | self.wait(1) 268 | 269 | .. note:: 270 | 271 | The ``arr_label_gap`` argument specifies the distance between the |MArrayElement| 's |Square| and the array label itself. 272 | 273 | Hex Indices 274 | ^^^^^^^^^^^ 275 | 276 | Lets say you want to show a 4-byte integer array with its addresses. You can simply achieve this by using ``index_hex_display`` and ``index_offset`` arguments of the |MArray| constructor. 277 | 278 | .. code-block:: python 279 | :linenos: 280 | 281 | class MyScene(Scene): 282 | def construct(self): 283 | arr = MArray( 284 | self, 285 | [1, 2, 3, 4], 286 | index_hex_display=True, 287 | index_offset=4 288 | ) 289 | self.play(Create(arr)) 290 | self.wait(1) 291 | 292 | .. raw:: html 293 | 294 |
295 | 296 | .. manim:: MyScene 297 | :hide_source: 298 | :quality: low 299 | 300 | from manim_data_structures import * 301 | 302 | class MyScene(Scene): 303 | def construct(self): 304 | arr = MArray( 305 | self, 306 | [1, 2, 3, 4], 307 | index_hex_display=True, 308 | index_offset=4 309 | ) 310 | self.play(Create(arr)) 311 | self.wait(1) 312 | 313 | Hide Indices 314 | ^^^^^^^^^^^^ 315 | 316 | Or if you don't want to show the indices at all, simply pass ``True`` as the ``hide_index`` argument to the constructor 317 | 318 | .. code-block:: python 319 | :linenos: 320 | 321 | class MyScene(Scene): 322 | def construct(self): 323 | arr = MArray( 324 | self, 325 | [1, 2, 3, 4], 326 | hide_index=True 327 | ) 328 | self.play(Create(arr)) 329 | self.wait(1) 330 | 331 | .. raw:: html 332 | 333 |
334 | 335 | .. manim:: MyScene 336 | :hide_source: 337 | :quality: low 338 | 339 | from manim_data_structures import * 340 | 341 | class MyScene(Scene): 342 | def construct(self): 343 | arr = MArray( 344 | self, 345 | [1, 2, 3, 4], 346 | hide_index=True 347 | ) 348 | self.play(Create(arr)) 349 | self.wait(1) 350 | 351 | Misc Functions 352 | ~~~~~~~~~~~~~~ 353 | 354 | The |MArray| provides some auxiliary methods which this secion will discuss. 355 | 356 | Append Element 357 | ^^^^^^^^^^^^^^ 358 | 359 | For an existing array, you can also append an element simply by invoking the |MArray.append_elem| method. 360 | 361 | .. code-block:: python 362 | :linenos: 363 | 364 | class MyScene(Scene): 365 | def construct(self): 366 | arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN) 367 | self.add(arr) 368 | self.wait(1) 369 | arr.append_elem(4) 370 | self.wait(1) 371 | 372 | .. raw:: html 373 | 374 |
375 | 376 | .. manim:: MyScene 377 | :hide_source: 378 | :quality: low 379 | 380 | from manim_data_structures import * 381 | 382 | class MyScene(Scene): 383 | def construct(self): 384 | arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN) 385 | self.add(arr) 386 | self.wait(1) 387 | arr.append_elem(4) 388 | self.wait(1) 389 | 390 | .. note:: 391 | 392 | You can also pass ``mob_*_args`` to this method to customize the inserted element. 393 | 394 | Moreover, you can also specify the animation that is played for the inserted element via the ``append_anim`` argument. The code snippet below passes the |GrowFromCenter| animation to the |MArray.append_elem| method: 395 | 396 | .. code-block:: python 397 | :linenos: 398 | 399 | arr.append_elem(4, append_anim=GrowFromCenter) 400 | 401 | .. raw:: html 402 | 403 |
404 | 405 | .. manim:: MyScene 406 | :hide_source: 407 | :quality: low 408 | 409 | from manim_data_structures import * 410 | 411 | class MyScene(Scene): 412 | def construct(self): 413 | arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN) 414 | self.add(arr) 415 | self.wait(1) 416 | arr.append_elem(4, append_anim=GrowFromCenter) 417 | self.wait(1) 418 | 419 | .. note:: 420 | 421 | You can also specify arguments to the passed animation via the ``append_anim_args`` parameter and also set the target of the animation using the ``append_anim_target`` parameter that takes in |MArrayElementComp| enum. 422 | 423 | Did you notice that in both snippets, we didn't pass any animation to our |Scene| but the append animation still played? This is thanks to the ``self`` that we pass as the first argument to our |MArray| constructor, which is basically a reference to the current |Scene|. 424 | 425 | However, if you'd like to play the animation yourself, we have got you covered! The |MArrayElement| method returns a list of |Animation| that you can pass to the |Scene.play| method as follows: 426 | 427 | .. code-block:: python 428 | :linenos: 429 | 430 | self.play(*arr.append_elem(4, play_anim=False)) 431 | 432 | Remove Element 433 | ^^^^^^^^^^^^^^ 434 | 435 | To remove an element simply invoke the |MArray.remove_elem| method with the index of element you wish to remove. 436 | 437 | .. code-block:: python 438 | :linenos: 439 | 440 | arr.remove_elem(1) 441 | 442 | .. raw:: html 443 | 444 |
445 | 446 | .. manim:: MyScene 447 | :hide_source: 448 | :quality: low 449 | 450 | from manim_data_structures import * 451 | 452 | class MyScene(Scene): 453 | def construct(self): 454 | arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN) 455 | self.add(arr) 456 | self.wait(1) 457 | arr.remove_elem(1) 458 | self.wait(1) 459 | 460 | Similar to how you were able to pass the append animation to the |MArray.append_elem| function, you can specify two animations for the |MArray.remove_elem| method: 461 | 462 | 1. Element removal animation via the ``removal_anim`` parameter. 463 | 2. Indices update animation via the ``update_anim`` parameter. 464 | 465 | The code snippet below provides an example: 466 | 467 | .. code-block:: python 468 | :linenos: 469 | 470 | arr.remove_elem(1, removal_anim=ShowPassingFlash , update_anim=Write) 471 | 472 | .. raw:: html 473 | 474 |
475 | 476 | .. manim:: MyScene 477 | :hide_source: 478 | :quality: low 479 | 480 | from manim_data_structures import * 481 | 482 | class MyScene(Scene): 483 | def construct(self): 484 | arr = MArray(self, [1, 2, 3], label='Array', arr_label_pos=MArrayDirection.DOWN) 485 | self.add(arr) 486 | self.wait(1) 487 | arr.remove_elem(1, removal_anim=ShowPassingFlash , update_anim=Write) 488 | self.wait(1) 489 | 490 | .. note:: 491 | 492 | You can also specify arguments to the passed animation via the ``*_anim_args`` parameter and also set the target of the animation using the ``*_anim_target`` parameter. 493 | 494 | Lastly, as the |MArray.append_elem| returns a list of |Animation|, the |MArray.remove_elem| returns two objects; a removal animation and a function that udpates the indices of the remaining elements and returns their animations. Hence, you can animate this as follows: 495 | 496 | .. code-block:: python 497 | :linenos: 498 | 499 | (remove_anim, update_indices) = arr.remove_elem(1, removal_anim=ShowPassingFlash , update_anim=Write, play_anim=False) 500 | self.play(remove_anim) # Play removal animation first 501 | self.play(*update_indices(play_anim=False)) # Then play the update_indices animation 502 | 503 | Update Element 504 | ^^^^^^^^^^^^^^ 505 | 506 | You can also update the value and the index of an existing array using the |MArray.update_elem_value| and |MArray.update_elem_index| methods respectively. 507 | 508 | .. code-block:: python 509 | :linenos: 510 | 511 | class MyScene(Scene): 512 | def construct(self): 513 | arr = MArray(self, [1, 2, 3]) 514 | self.add(arr) 515 | self.wait(1) 516 | arr.update_elem_value(1, 20) 517 | arr.update_elem_index(1, -2) 518 | self.wait(1) 519 | 520 | .. raw:: html 521 | 522 |
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 --------------------------------------------------------------------------------