mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Flake8 Changes + Fixing Warnings (#1968)
* Warning Removal * Flake Stuff * HotFix * Docs Fix * I'm Dumb * Docs Fix 2 * Fixing Github Requests * Fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * quick fix * Add Deprecation Warning * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Weird Pre Commit Stuff * Quick Fix * Quick Fix * Fix * Flake Fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
c11b649e9a
commit
94821c10d8
217 changed files with 2246 additions and 1435 deletions
|
|
@ -1,4 +1,4 @@
|
|||
[codespell]
|
||||
exclude-file=.codespell_ignorelines
|
||||
check-hidden=True
|
||||
ignore-words-list = sherif,
|
||||
ignore-words-list = sherif
|
||||
|
|
|
|||
29
.flake8
29
.flake8
|
|
@ -1,20 +1,35 @@
|
|||
[flake8]
|
||||
# Exclude the grpc generated code
|
||||
exclude = ./.*,manim/grpc/gen/*
|
||||
max-complexity = 35
|
||||
max-line-length = 211
|
||||
max-complexity = 15
|
||||
max-line-length = 88
|
||||
statistics = True
|
||||
# Prevents some flake8-rst-docstrings errors
|
||||
rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc
|
||||
rst-directives = manim, SEEALSO, seealso
|
||||
# Adds some more bugbear checks
|
||||
select = B9
|
||||
|
||||
# Black Compatibility
|
||||
extend-ignore = E203, W503,
|
||||
|
||||
# Unused imports, wildcard imports, and unused variables
|
||||
F401, F403, F405, F841,
|
||||
F401, F403, F405, F841, E501,
|
||||
|
||||
# Plug-in: flake8-builtins
|
||||
A001, A002, A003,
|
||||
|
||||
# Plug-in: flake8-bugbear
|
||||
B006, B007, B008, B009, B010, B011, B015,
|
||||
B006, B008, B009, B010,
|
||||
|
||||
# Plug-in: flake8-simplify
|
||||
SIM105, SIM106, SIM119,
|
||||
|
||||
# Plug-in: flake8-comprehensions
|
||||
C408,
|
||||
|
||||
# Plug-in: flake8-pytest-style
|
||||
PT001, PT004, PT006, PT011, PT018, PT022, PT023,
|
||||
|
||||
# Plug-in: flake8-docstrings
|
||||
D100, D101, D102, D103, D104, D105, D106, D107,
|
||||
|
|
@ -23,5 +38,7 @@ extend-ignore = E203, W503,
|
|||
D400, D401, D402, D403, D412, D414,
|
||||
|
||||
# Plug-in: flake8-rst-docstrings
|
||||
RST201, RST203, RST205, RST210, RST212, RST213, RST215,
|
||||
RST301, RST303, RST304,
|
||||
RST201, RST203, RST210, RST212, RST213, RST215,
|
||||
RST301,
|
||||
|
||||
# I believe B009, B010, and F841 can be removed but I don't want to break things
|
||||
|
|
|
|||
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -8,4 +8,3 @@
|
|||
*.wav binary
|
||||
|
||||
manim/grpc/gen/** linguist-generated=true
|
||||
|
||||
|
|
|
|||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -10,7 +10,7 @@
|
|||
<!-- Optional for bugfixes, small enhancements, and documentation-related PRs. Otherwise, please give a short reasoning for your changes. -->
|
||||
|
||||
## Links to added or changed documentation pages
|
||||
<!-- Please add links to the affected documentation pages (edit the description after opening the PR). The link to the documentation for your PR is https://manimce--####.org.readthedocs.build/en/####/, where #### represents the PR number. -->
|
||||
<!-- Please add links to the affected documentation pages (edit the description after opening the PR). The link to the documentation for your PR is https://manimce--####.org.readthedocs.build/en/####/, where #### represents the PR number. -->
|
||||
|
||||
|
||||
## Further Information and Comments
|
||||
|
|
|
|||
2
.github/PULL_REQUEST_TEMPLATE/bugfix.md
vendored
2
.github/PULL_REQUEST_TEMPLATE/bugfix.md
vendored
|
|
@ -5,7 +5,7 @@ Before filling in the details, ensure:
|
|||
- Added gradient support and documentation for SVG files
|
||||
-->
|
||||
|
||||
## Changelog
|
||||
## Changelog
|
||||
<!-- Optional: more descriptive changelog entry than just the title for the upcoming
|
||||
release. Write RST between the following start and end comments.-->
|
||||
<!--changelog-start-->
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Before filling in the details, ensure:
|
|||
-->
|
||||
## Summary of Changes
|
||||
|
||||
## Changelog
|
||||
## Changelog
|
||||
<!-- Optional: more descriptive changelog entry than just the title for the upcoming
|
||||
release. Write RST between the following start and end comments.-->
|
||||
<!--changelog-start-->
|
||||
|
|
|
|||
|
|
@ -4,16 +4,13 @@ repos:
|
|||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: check-ast
|
||||
name: Validate Python
|
||||
- id: trailing-whitespace
|
||||
- id: mixed-line-ending
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.8b0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.11.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==20.8b1]
|
||||
- id: end-of-file-fixer
|
||||
- id: check-toml
|
||||
name: Validate Poetry
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.9.3
|
||||
hooks:
|
||||
|
|
@ -25,11 +22,44 @@ repos:
|
|||
- id: isort
|
||||
name: isort (pyi)
|
||||
types: [pyi]
|
||||
- repo: https://github.com/asottile/add-trailing-comma
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
- id: add-trailing-comma
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.25.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
name: Update code to new python versions
|
||||
args: [--py37-plus]
|
||||
exclude: ^manim/grpc/gen/
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
name: Precision flake ignores
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.8b0
|
||||
hooks:
|
||||
- id: black
|
||||
exclude: ^manim/grpc/gen/
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.11.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==20.8b1]
|
||||
- repo: https://github.com/asottile/yesqa
|
||||
rev: v1.2.3
|
||||
hooks:
|
||||
- id: yesqa
|
||||
name: Remove unneeded flake ignores
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [flake8-builtins==1.5.3, flake8-bugbear==21.4.3, flake8-docstrings==1.6.0, flake8-rst-docstrings==0.2.3]
|
||||
additional_dependencies: [flake8-builtins==1.5.3, flake8-bugbear==21.4.3,
|
||||
flake8-docstrings==1.6.0, flake8-rst-docstrings==0.2.3,
|
||||
flake8-pytest-style==1.5.0, flake8-simplify==0.14.1, flake8-comprehensions==3.6.1]
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# YAML 1.2
|
||||
---
|
||||
authors:
|
||||
authors:
|
||||
-
|
||||
name: "The Manim Community Developers"
|
||||
cff-version: "1.1.0"
|
||||
|
|
@ -10,4 +10,4 @@ message: "We acknowledge the importance of good software to support research, an
|
|||
title: Manim – Mathematical Animation Framework
|
||||
url: "https://www.manim.community/"
|
||||
version: "v0.10.0"
|
||||
...
|
||||
...
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ Some team members may have a conflict of interest and may be excluded from discu
|
|||
|
||||
Once the team has approved the behavioral modification plans and consequences, they will communicate the recommended response to the Manim Community moderators. The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report.
|
||||
|
||||
Moderators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week.
|
||||
Moderators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week.
|
||||
|
||||
In cases where the moderators disagree on the suggested resolution for a report, the Manim Community Code of Conduct team may choose to notify the Manim Community Moderators.
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ We acknowledge the importance of good software to support research, and we note
|
|||
that research becomes more valuable when it is communicated effectively. To
|
||||
demonstrate the value of Manim, we ask that you cite Manim in your work.
|
||||
Currently, the best way to cite Manim is to go to our
|
||||
[repository page](https://github.com/ManimCommunity/manim) (if you aren't already) and
|
||||
[repository page](https://github.com/ManimCommunity/manim) (if you aren't already) and
|
||||
click the "cite this repository" button on the right sidebar. This will generate
|
||||
a citation in your preferred format, and will also integrate well with citation managers.
|
||||
|
||||
|
|
|
|||
|
|
@ -13,4 +13,3 @@ Multi-platform builds are possible by running
|
|||
docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag manimcommunity/manim:TAG -f docker/Dockerfile .
|
||||
```
|
||||
from the root directory of the repository.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ TEXMFSYSCONFIG /usr/local/texlive/texmf-config
|
|||
TEXMFSYSVAR /usr/local/texlive/texmf-var
|
||||
TEXMFVAR ~/.texlive/texmf-var
|
||||
option_doc 0
|
||||
option_src 0
|
||||
option_src 0
|
||||
|
|
|
|||
|
|
@ -44,16 +44,16 @@ window.addEventListener("load", function () {
|
|||
.node text {
|
||||
fill: ${colors.text};
|
||||
}
|
||||
|
||||
|
||||
.node polygon {
|
||||
fill: ${colors.box};
|
||||
}
|
||||
|
||||
|
||||
.edge polygon {
|
||||
fill: ${colors.edge};
|
||||
stroke: ${colors.edge};
|
||||
}
|
||||
|
||||
|
||||
.edge path {
|
||||
stroke: ${colors.edge};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,4 +115,4 @@ Other Changes
|
|||
#. Cleanup 3b1b Specific Files
|
||||
#. Rename package from manimlib to manim
|
||||
#. Move all imports to :code:`__init__`, so :code:`from manim import *` replaces :code:`from manimlib.imports import *`
|
||||
#. Global dir variable handling has been removed. Instead :code:`initialize_directories`, if needed, overrides the values from the cfg files at runtime.
|
||||
#. Global dir variable handling has been removed. Instead :code:`initialize_directories`, if needed, overrides the values from the cfg files at runtime.
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ Breaking changes
|
|||
----------------
|
||||
|
||||
* `#1843 <https://github.com/ManimCommunity/manim/pull/1843>`__: Dropped redundant OpenGL files and add metaclass support for :class:`~.Surface`
|
||||
- ``OpenGL<x>`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed.
|
||||
- ``OpenGL<x>`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed.
|
||||
- ``ParametricSurface`` has been renamed to :class:`~.Surface`
|
||||
|
||||
Deprecated classes and functions
|
||||
|
|
@ -280,5 +280,3 @@ New releases
|
|||
------------
|
||||
|
||||
* `#1989 <https://github.com/ManimCommunity/manim/pull/1989>`__: Prepare new release v0.10.0
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -90,4 +90,3 @@ Other changes
|
|||
- Change several ``str.format()`` to ``f``-strings (:pr:`867`)
|
||||
- Update javascript renderer (:pr:`830`)
|
||||
- Bump version number to 0.2.0, update changelog (:pr:`894`)
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ Fixed bugs
|
|||
* `#1134 <https://github.com/ManimCommunity/manim/pull/1134>`__: Fixed the `-a` flag.
|
||||
The ``-a`` / ``--write-all`` flag was broken. When used, it would cause Manim to crash just after beginning to render the second scene.
|
||||
|
||||
* `#1115 <https://github.com/ManimCommunity/manim/pull/1115>`__: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support
|
||||
* `#1115 <https://github.com/ManimCommunity/manim/pull/1115>`__: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support
|
||||
Fixed undefined variables and converted :class:`Mobject` to :class:`OpenGLMobject`. Also, fixed assert statement in :class:`ApplyMethod`.
|
||||
|
||||
* `#1092 <https://github.com/ManimCommunity/manim/pull/1092>`__: Refactored coordinate_systems.py, fixed bugs, added :class:`~.NumberPlane` test
|
||||
|
|
@ -297,11 +297,10 @@ Code quality improvements and similar refactors
|
|||
|
||||
* `#1019 <https://github.com/ManimCommunity/manim/pull/1019>`__: Refactored :meth:`~.Scene.play`
|
||||
- Removed the _**three**_ decorators of :meth:`~.Scene.play`, in particular: caching logic and file writer logic are now included within :meth:`~.Scene.play` (it wasn't possible before, because `scene.wait` and `scene.play` were two different things).
|
||||
- Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame).
|
||||
- Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`.
|
||||
- Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame).
|
||||
- Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`.
|
||||
- Now when calling play without animation, it raises `ValueError` instead of just a warning.
|
||||
- Fixed :pr:`874` by modifying `renderer.update_skipping_status`
|
||||
- `renderer` starts the animation with `scene.begin_animations` (`scene.compile_animation_data` used to do this)
|
||||
- The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later.
|
||||
- The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later.
|
||||
- Added a bunch of cool tests thanks to mocks, and thanks to the new syntax `scene.render`
|
||||
|
||||
|
|
|
|||
|
|
@ -473,4 +473,3 @@ New releases
|
|||
------------
|
||||
|
||||
* `#1434 <https://github.com/ManimCommunity/manim/pull/1434>`__: Prepare v0.6.0
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ New features
|
|||
* `#1559 <https://github.com/ManimCommunity/manim/pull/1559>`__: Update VGroup to support item assignment (#1530)
|
||||
Support indexed item-assignment for VGroup
|
||||
|
||||
* `#1518 <https://github.com/ManimCommunity/manim/pull/1518>`__: Allow fading multiple Mobjects in one Animation
|
||||
* `#1518 <https://github.com/ManimCommunity/manim/pull/1518>`__: Allow fading multiple Mobjects in one Animation
|
||||
|
||||
|
||||
* `#1422 <https://github.com/ManimCommunity/manim/pull/1422>`__: Added :func:`~.override_animation` decorator
|
||||
|
|
@ -190,7 +190,7 @@ Enhancements
|
|||
|
||||
|
||||
* `#1567 <https://github.com/ManimCommunity/manim/pull/1567>`__: Compatibility Fixes with ManimPango v0.3.0
|
||||
- ManimPango v0.3.0+ is required for Manim now.
|
||||
- ManimPango v0.3.0+ is required for Manim now.
|
||||
- Show errors from Pango when Markup isn't correct
|
||||
|
||||
* `#1512 <https://github.com/ManimCommunity/manim/pull/1512>`__: OpenGL compatibility via metaclass: graph
|
||||
|
|
@ -244,7 +244,7 @@ Fixed bugs
|
|||
* `#1560 <https://github.com/ManimCommunity/manim/pull/1560>`__: Declare ``*.npz`` ``*.wav`` ``*.png`` as binary in ``.gitattributes``
|
||||
|
||||
|
||||
* `#1211 <https://github.com/ManimCommunity/manim/pull/1211>`__: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene
|
||||
* `#1211 <https://github.com/ManimCommunity/manim/pull/1211>`__: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene
|
||||
Refactored internal scene-caching mechanism and fixed bug when an inconsistent hash was produced when copying a mobject.
|
||||
|
||||
* `#1527 <https://github.com/ManimCommunity/manim/pull/1527>`__: Improved handling of substring isolation within sqrt, and fixed a bug with transform_mismatch for the matching shape transforms
|
||||
|
|
@ -342,7 +342,7 @@ Changes to our development infrastructure
|
|||
* `#1499 <https://github.com/ManimCommunity/manim/pull/1499>`__: Updated Discord links in the docs to point towards a standardized redirect
|
||||
|
||||
|
||||
* `#1461 <https://github.com/ManimCommunity/manim/pull/1461>`__: Build the docs - Logging
|
||||
* `#1461 <https://github.com/ManimCommunity/manim/pull/1461>`__: Build the docs - Logging
|
||||
|
||||
|
||||
* `#1481 <https://github.com/ManimCommunity/manim/pull/1481>`__: pyproject.toml: poetry_core -> poetry-core
|
||||
|
|
@ -397,5 +397,3 @@ New releases
|
|||
------------
|
||||
|
||||
* `#1601 <https://github.com/ManimCommunity/manim/pull/1601>`__: Preparation for v0.7.0: added changelog and bumped version number
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -332,5 +332,3 @@ New releases
|
|||
------------
|
||||
|
||||
* `#1738 <https://github.com/ManimCommunity/manim/pull/1738>`__: Preparation for v0.8.0: added changelog and bumped version number
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -278,5 +278,3 @@ New releases
|
|||
------------
|
||||
|
||||
* `#1850 <https://github.com/ManimCommunity/manim/pull/1850>`__: Bump version number to ``v0.9.0`` and generate changelog
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,11 @@ inheritance_graph_attrs = dict(
|
|||
)
|
||||
|
||||
inheritance_node_attrs = dict(
|
||||
penwidth=0, shape="box", width=0.05, height=0.05, margin=0.05
|
||||
penwidth=0,
|
||||
shape="box",
|
||||
width=0.05,
|
||||
height=0.05,
|
||||
margin=0.05,
|
||||
)
|
||||
|
||||
inheritance_edge_attrs = dict(
|
||||
|
|
|
|||
|
|
@ -40,22 +40,22 @@ For first-time contributors
|
|||
.. code-block:: shell
|
||||
|
||||
git remote add upstream https://github.com/ManimCommunity/manim.git
|
||||
|
||||
|
||||
#. Now, ``git remote -v`` should show two remote repositories named:
|
||||
|
||||
|
||||
- ``origin``, your forked repository
|
||||
- ``upstream`` the ManimCommunity repository
|
||||
|
||||
#. Install Manim:
|
||||
|
||||
- Follow the steps in our :doc:`installation instructions
|
||||
- Follow the steps in our :doc:`installation instructions
|
||||
<../installation>` to install **Manim's dependencies**,
|
||||
primarily ``ffmpeg`` and ``LaTeX``.
|
||||
|
||||
|
||||
- We recommend using `Poetry <https://python-poetry.org>`__ to manage your
|
||||
developer installation of Manim. Poetry is a tool for dependency
|
||||
management and packaging in Python. It allows you to declare the libraries
|
||||
your project depends on, and it will manage (install / update) them
|
||||
your project depends on, and it will manage (install / update) them
|
||||
for you. In addition, Poetry provides a simple interface for
|
||||
managing virtual environments.
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ For first-time contributors
|
|||
your cloned repository. Poetry will then install Manim, as well
|
||||
as create and enter a virtual environment. You can always re-enter
|
||||
that environment by running ``poetry shell``.
|
||||
|
||||
|
||||
- In case you decided against Poetry, you can install Manim via pip
|
||||
by running ``python3 -m pip install .``. Note that due to our
|
||||
development infrastructure being based on Poetry, we currently
|
||||
|
|
@ -83,7 +83,7 @@ For first-time contributors
|
|||
.. code-block:: shell
|
||||
|
||||
poetry run pre-commit install
|
||||
|
||||
|
||||
This will ensure during development that each of your commits is properly
|
||||
formatted against our linter and formatters, ``black``, ``flake8``,
|
||||
``isort`` and ``codespell``.
|
||||
|
|
@ -118,7 +118,7 @@ Develop your contribution
|
|||
``git add .``, or add specific files with
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
||||
git add <file/directory>
|
||||
|
||||
and commit these changes to your local history with ``git commit``. If you
|
||||
|
|
@ -126,7 +126,7 @@ Develop your contribution
|
|||
hooks fail.
|
||||
|
||||
.. tip::
|
||||
|
||||
|
||||
When crafting commit messages, it is highly recommended that
|
||||
you adhere to `these guidelines <https://www.conventionalcommits.org/en/v1.0.0/>`_.
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ sticks to our coding conventions.
|
|||
and `flake8 <https://flake8.pycqa.org/en/latest/>`_. The GitHub pipeline
|
||||
makes sure that the (Python) files changed in your pull request
|
||||
also adhere to this code style. If this step of the pipeline fails,
|
||||
fix your code formatting automatically by running ``black <file or directory>`` and ``isort <file or directory>``.
|
||||
fix your code formatting automatically by running ``black <file or directory>`` and ``isort <file or directory>``.
|
||||
To fix code style problems, run ``flake8 <file or directory>`` for a style report, and then fix the problems
|
||||
manually that were detected by ``flake8``.
|
||||
|
||||
|
|
@ -267,7 +267,7 @@ Further useful guidelines
|
|||
to them in your new issue (even if the old ones are closed).
|
||||
|
||||
#. When submitting a code review, it is highly recommended that you adhere to
|
||||
`these general guidelines <https://conventionalcomments.org/>`_.
|
||||
`these general guidelines <https://conventionalcomments.org/>`_.
|
||||
|
||||
#. If you find stale or inactive issues that seem to be irrelevant, please post
|
||||
a comment saying 'This issue should be closed', and a community developer
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ Example:
|
|||
d: "SomeClassFromFarAway",
|
||||
test: Optional[int] = 45
|
||||
) -> "EpicClassInThisFile": # typings are optional for now
|
||||
"""My cool function. Builds and modifies an :class:`EpicClassInThisFile` instance with the given
|
||||
"""My cool function. Builds and modifies an :class:`EpicClassInThisFile` instance with the given
|
||||
parameters.
|
||||
|
||||
Parameters
|
||||
|
|
|
|||
|
|
@ -2,23 +2,23 @@
|
|||
Adding Examples
|
||||
===============
|
||||
|
||||
This is a page for adding examples to the documentation.
|
||||
This is a page for adding examples to the documentation.
|
||||
Here are some guidelines you should follow before you publish your examples.
|
||||
|
||||
Guidelines for examples
|
||||
-----------------------
|
||||
|
||||
Everybody is welcome to contribute examples to the documentation. Since straightforward
|
||||
Everybody is welcome to contribute examples to the documentation. Since straightforward
|
||||
examples are a great resource for quickly learning manim, here are some guidelines.
|
||||
|
||||
What makes a great example
|
||||
--------------------------
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
As soon as a new version of manim is released, the documentation will be a snapshot of that
|
||||
As soon as a new version of manim is released, the documentation will be a snapshot of that
|
||||
version. Examples contributed after the release will only be shown in the latest documentation.
|
||||
|
||||
|
||||
* Examples should be ready to copy and paste for use.
|
||||
|
||||
* Examples should be brief yet still easy to understand.
|
||||
|
|
@ -47,7 +47,7 @@ How examples are structured
|
|||
Writing examples
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
When you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in
|
||||
When you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in
|
||||
``rst`` format and use the manim directive (see :mod:`~.manim_directive` ), ``.. manim::``. Every example is in its own block, and looks like this:
|
||||
|
||||
.. code:: rst
|
||||
|
|
@ -64,8 +64,8 @@ When you want to add/edit examples, they can be found in the ``docs/source/`` di
|
|||
self.add(t)
|
||||
self.wait(1)
|
||||
|
||||
In the building process of the docs, all ``rst`` files are scanned, and the
|
||||
manim directive (``.. manim::``) blocks are identified as scenes that will be run
|
||||
In the building process of the docs, all ``rst`` files are scanned, and the
|
||||
manim directive (``.. manim::``) blocks are identified as scenes that will be run
|
||||
by the current version of manim.
|
||||
Here is the syntax:
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ has the same name: ``class Formula1(Scene)``.
|
|||
Sometimes, when you reload an example in your browser, it has still the old
|
||||
website somewhere in its cache. If this is the case, delete the website cache,
|
||||
or open a new incognito tab in your browser, then the latest docs
|
||||
should be shown.
|
||||
should be shown.
|
||||
**Only for locally built documentation:** If this still doesn't work, you may need
|
||||
to delete the contents of ``docs/source/references`` before rebuilding
|
||||
the documentation.
|
||||
the documentation.
|
||||
|
|
|
|||
|
|
@ -134,4 +134,4 @@ Example: ``List[Optional[:class:`str`]]`` for a list that returns
|
|||
elements that are either a ``str`` or ``None``;
|
||||
``Tuple[:class:`str`, :class:`int`]`` for a tuple of type
|
||||
``(str, int)``; ``Tuple[:class:`int`, ...]`` for a tuple of variable
|
||||
length with only integers.
|
||||
length with only integers.
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@ feature has been broken and/or been unintentionally modified.
|
|||
How Manim tests
|
||||
---------------
|
||||
|
||||
Manim uses pytest as its testing framework.
|
||||
To start the testing process, go to the root directory of the project and run pytest in your terminal.
|
||||
Manim uses pytest as its testing framework.
|
||||
To start the testing process, go to the root directory of the project and run pytest in your terminal.
|
||||
Any errors that occur during testing will be displayed in the terminal.
|
||||
|
||||
Some useful pytest flags:
|
||||
Some useful pytest flags:
|
||||
|
||||
- ``-x`` will make pytest stop at the first failure it encounters
|
||||
|
||||
|
||||
- ``-s`` will make pytest display all the print messages (including those during scene generation, like DEBUG messages)
|
||||
|
||||
|
||||
- ``--skip_slow`` will skip the (arbitrarily) slow tests
|
||||
|
||||
- ``--show_diff`` will show a visual comparison in case a unit test is failing.
|
||||
|
||||
|
||||
|
||||
How it Works
|
||||
~~~~~~~~~~~~
|
||||
|
|
@ -129,7 +129,7 @@ The Main Directories
|
|||
- ``test_graphical_units/``:
|
||||
|
||||
Contains graphical tests.
|
||||
|
||||
|
||||
- ``test_scene_rendering/``:
|
||||
|
||||
For tests that need to render a scene in some way, such as tests for CLI
|
||||
|
|
@ -169,7 +169,7 @@ For example, to test the ``Circle`` VMobject which resides in
|
|||
The name of the module is indicated by the variable __module_test__, that **must** be declared in any graphical test file. The module name is used to store the graphical control data.
|
||||
|
||||
.. important::
|
||||
You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a
|
||||
You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a
|
||||
parameter named ``scene`` that will be used like ``self`` in a standard ``construct`` method.
|
||||
|
||||
Here's an example in ``test_geometry.py``:
|
||||
|
|
@ -196,7 +196,7 @@ The decorator can be used with or without parentheses. **By default, the test on
|
|||
circle = Circle()
|
||||
scene.play(Animation(circle))
|
||||
|
||||
You can also specify, when needed, which base scene you need (ThreeDScene, for example) :
|
||||
You can also specify, when needed, which base scene you need (ThreeDScene, for example) :
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
|
@ -211,16 +211,16 @@ Note that tests name must follow the syntax ``test_<thing_to_test>``, otherwise
|
|||
|
||||
.. warning::
|
||||
If you run pytest now, you will get a ``FileNotFound`` error. This is because
|
||||
you have not created control data for your test.
|
||||
you have not created control data for your test.
|
||||
|
||||
To create the control data for your test, you have to use the flag ``--set_test`` along with pytest.
|
||||
For the example above, it would be
|
||||
To create the control data for your test, you have to use the flag ``--set_test`` along with pytest.
|
||||
For the example above, it would be
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_geometry.py::test_circle --set_test -s
|
||||
|
||||
(``-s`` is here to see manim logs, so you can see what's going on).
|
||||
(``-s`` is here to see manim logs, so you can see what's going on).
|
||||
|
||||
Please make sure to add the control data to git as soon as it is produced with ``git add <your-control-data.npz>``.
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ To test videos generated, we use the decorator
|
|||
out, err, exit_code = capture(command)
|
||||
assert exit_code == 0, err
|
||||
|
||||
.. note:: ``assert exit*\ code == 0, err`` is used in case of the command fails
|
||||
.. note:: ``assert exit*\ code == 0, err`` is used in case of the command fails
|
||||
to run. The decorator takes two arguments: json name and the path
|
||||
to where the video should be generated, starting from the ``media/`` dir.
|
||||
|
||||
|
|
|
|||
|
|
@ -75,13 +75,13 @@ When adding type hints to manim, there are some guidelines that should be follow
|
|||
|
||||
.. note::
|
||||
As a helper for tool for typesets, you can use `typestring-parser
|
||||
<https://github.com/Dominik1123/typestring-parser>`_
|
||||
<https://github.com/Dominik1123/typestring-parser>`_
|
||||
which can be accessed by first installing it via ``pip`` - ``pip install typestring-parser`` and
|
||||
then using ``from typestring_parser import parse``.
|
||||
|
||||
.. doctest::
|
||||
:options: +SKIP
|
||||
|
||||
|
||||
>>> from typestring_parser import parse
|
||||
>>> parse("int")
|
||||
<class 'int'>
|
||||
|
|
@ -100,4 +100,4 @@ Missing Sections for typehints are:
|
|||
* Where to find the alias
|
||||
* When to use Object and when to use "Object".
|
||||
* The use of a TypeVar on the type hints for copy().
|
||||
* The definition and use of Protocols (like Sized, or Sequence, or Iterable...)
|
||||
* The definition and use of Protocols (like Sized, or Sequence, or Iterable...)
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ Plotting with Manim
|
|||
x_range=[0, 10], y_range=[0, 100, 10], axis_config={"include_tip": False}
|
||||
)
|
||||
labels = ax.get_axis_labels(x_label="x", y_label="f(x)")
|
||||
|
||||
|
||||
t = ValueTracker(0)
|
||||
|
||||
def func(x):
|
||||
|
|
@ -570,7 +570,7 @@ Special Camera Settings
|
|||
.. manim:: ThreeDSurfacePlot
|
||||
:save_last_frame:
|
||||
:ref_classes: ThreeDScene Surface
|
||||
|
||||
|
||||
class ThreeDSurfacePlot(ThreeDScene):
|
||||
def construct(self):
|
||||
resolution_fa = 42
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Otherwise, if you intend to use Manim to work on an animation project,
|
|||
we recommend installing the library locally (either to your system's
|
||||
Python, or via Docker).
|
||||
|
||||
.. warning::
|
||||
.. warning::
|
||||
|
||||
Note that there are several different versions of Manim. The
|
||||
instructions on this website are **only** for the *community edition*.
|
||||
|
|
@ -21,7 +21,7 @@ Python, or via Docker).
|
|||
|
||||
#. :ref:`Installing Manim to your system's Python <local-installation>`
|
||||
#. :ref:`Using Manim via Docker <docker-installation>`
|
||||
#. :ref:`Interactive Jupyter notebooks via Binder / Google Colab
|
||||
#. :ref:`Interactive Jupyter notebooks via Binder / Google Colab
|
||||
<interactive-online>`
|
||||
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ operating system specific instructions for you to follow.
|
|||
follow the steps on the following pages carefully, but in case
|
||||
you hit a wall we are happy to help: either `join our Discord
|
||||
<https://www.manim.community/discord/>`__, or start a new
|
||||
Discussion `directly on GitHub
|
||||
Discussion `directly on GitHub
|
||||
<https://github.com/ManimCommunity/manim/discussions>`__.
|
||||
|
||||
.. toctree::
|
||||
|
|
@ -59,12 +59,12 @@ Once Manim is installed locally, you can proceed to our
|
|||
through rendering a first simple scene.
|
||||
|
||||
As mentioned above, do not worry if there are errors or other
|
||||
problems: consult our :doc:`troubleshooting
|
||||
problems: consult our :doc:`troubleshooting
|
||||
guide <installation/troubleshooting>` for help, or get in touch
|
||||
with the community via `GitHub discussions
|
||||
<https://github.com/ManimCommunity/manim/discussions>`__ or
|
||||
with the community via `GitHub discussions
|
||||
<https://github.com/ManimCommunity/manim/discussions>`__ or
|
||||
`Discord <https://www.manim.community/discord/>`__.
|
||||
|
||||
|
||||
|
||||
|
||||
.. _docker-installation:
|
||||
|
|
@ -108,6 +108,3 @@ In order to change code in the library, it is recommended to
|
|||
install Manim in a different way. Please follow the instructions
|
||||
in our :doc:`contribution guide <contributing>` if you are
|
||||
interested in that.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,19 +2,19 @@ Docker
|
|||
======
|
||||
|
||||
The community maintains a docker image, which can be found
|
||||
`on DockerHub <https://hub.docker.com/r/manimcommunity/manim>`__.
|
||||
`on DockerHub <https://hub.docker.com/r/manimcommunity/manim>`__.
|
||||
For our image ``manimcommunity/manim``, there are the following tags:
|
||||
|
||||
- ``latest``: the most recent version corresponding
|
||||
- ``latest``: the most recent version corresponding
|
||||
to `the main branch <https://github.com/ManimCommunity/manim>`__,
|
||||
- ``stable``: the latest released version (according to
|
||||
- ``stable``: the latest released version (according to
|
||||
`the releases page <https://github.com/ManimCommunity/manim/releases>`__),
|
||||
- ``vX.Y.Z``: any particular released version (according to
|
||||
- ``vX.Y.Z``: any particular released version (according to
|
||||
`the releases page <https://github.com/ManimCommunity/manim/releases>`__).
|
||||
|
||||
.. note::
|
||||
|
||||
When using Manim's CLI within a Docker container, some flags like
|
||||
When using Manim's CLI within a Docker container, some flags like
|
||||
``-p`` (preview file) and ``-f`` (show output file in the file browser)
|
||||
are not supported.
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ Basic usage of the Docker container
|
|||
-----------------------------------
|
||||
|
||||
Assuming that you can access the docker installation on your system
|
||||
from a terminal (bash / PowerShell) via ``docker``, you can
|
||||
from a terminal (bash / PowerShell) via ``docker``, you can
|
||||
render a scene ``CircleToSquare`` in a file `test_scenes.py`
|
||||
with the following command.
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ modify to your liking. First, run
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
docker run -it --name my-manim-container -v "/full/path/to/your/directory:/manim" manimcommunity/manim /bin/bash
|
||||
docker run -it --name my-manim-container -v "/full/path/to/your/directory:/manim" manimcommunity/manim /bin/bash
|
||||
|
||||
|
||||
to obtain an interactive shell inside your container allowing you
|
||||
|
|
@ -75,4 +75,4 @@ local JupyterLab instance. To do that, simply run
|
|||
|
||||
docker run -it -p 8888:8888 manimcommunity/manim jupyter lab --ip=0.0.0.0
|
||||
|
||||
and then follow the instructions in the terminal.
|
||||
and then follow the instructions in the terminal.
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ a way that allows them to be shared interactively via Binder as well:
|
|||
FROM manimcommunity/manim:v0.9.0
|
||||
|
||||
COPY --chown=manimuser:manimuser . /manim
|
||||
|
||||
|
||||
Don't forget to change the version tag ``v0.9.0`` to the version you
|
||||
were working with locally when creating your notebooks.
|
||||
#. Make the directory with your worksheets and the ``Dockerfile``
|
||||
available to the public (and in particular: to Binder!). There are
|
||||
`several different options to do so
|
||||
`several different options to do so
|
||||
<https://mybinder.readthedocs.io/en/latest/introduction.html#how-can-i-prepare-a-repository-for-binder>`__,
|
||||
within the community we usually work with GitHub
|
||||
repositories or gists.
|
||||
|
|
@ -44,7 +44,7 @@ a way that allows them to be shared interactively via Binder as well:
|
|||
|
||||
.. hint::
|
||||
|
||||
The repository containing our `interactive tutorial
|
||||
The repository containing our `interactive tutorial
|
||||
<https://try.manim.community>`__ can be found at
|
||||
https://github.com/ManimCommunity/jupyter_examples.
|
||||
|
||||
|
|
@ -88,12 +88,12 @@ in a new code cell. Then create another cell containing the
|
|||
following code::
|
||||
|
||||
%%manim -qm -v WARNING SquareToCircle
|
||||
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
circle = Circle()
|
||||
circle.set_fill(PINK, opacity=0.5)
|
||||
circle = Circle()
|
||||
circle.set_fill(PINK, opacity=0.5)
|
||||
self.play(Create(square))
|
||||
self.play(Transform(square, circle))
|
||||
self.wait()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ system and package manager. If you happen to know exactly what you are doing,
|
|||
you can also simply ensure that your system has:
|
||||
|
||||
- a reasonably recent version of Python 3 (3.7 or above),
|
||||
- with working Cairo bindings in the form of
|
||||
- with working Cairo bindings in the form of
|
||||
`pycairo <https://cairographics.org/pycairo/>`__,
|
||||
- FFmpeg accessible from the command line as ``ffmpeg``,
|
||||
- and `Pango <https://pango.gnome.org>`__ headers.
|
||||
|
|
@ -20,10 +20,10 @@ Then, installing Manim is just a matter of running:
|
|||
.. note::
|
||||
|
||||
In light of the current efforts of migrating to rendering via OpenGL,
|
||||
this list might be incomplete. Please `let us know
|
||||
this list might be incomplete. Please `let us know
|
||||
<https://github.com/ManimCommunity/manim/issues/new/choose>` if you
|
||||
ran into missing dependencies while installing.
|
||||
|
||||
|
||||
In any case, we have also compiled instructions for several common
|
||||
combinations of operating systems and package managers below.
|
||||
|
||||
|
|
@ -38,13 +38,13 @@ simply run:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt update
|
||||
sudo apt update
|
||||
sudo apt install libcairo2-dev libpango1.0-dev ffmpeg
|
||||
|
||||
If you don't have python3-pip installed, install it via:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
sudo apt install python3-pip
|
||||
|
||||
Then, to install Manim, run:
|
||||
|
|
@ -95,11 +95,11 @@ pacman – Arch / Manjaro
|
|||
|
||||
.. tip::
|
||||
|
||||
Thanks to *groctel*, there is a `dedicated Manim package
|
||||
Thanks to *groctel*, there is a `dedicated Manim package
|
||||
on the AUR! <https://aur.archlinux.org/packages/manim/>`
|
||||
|
||||
If you don't want to use the packaged version from AUR, here is what
|
||||
you need to do manually: Update your package sources, then install
|
||||
you need to do manually: Update your package sources, then install
|
||||
Cairo, Pango, and FFmpeg:
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
@ -110,7 +110,7 @@ Cairo, Pango, and FFmpeg:
|
|||
If you don't have ``python-pip`` installed, get it by running:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
sudo pacman -S python-pip
|
||||
|
||||
then simply install Manim via:
|
||||
|
|
@ -134,7 +134,7 @@ equations, LaTeX has to be installed as well. Note that this is an optional
|
|||
dependency: if you don't intend to use LaTeX, you don't have to install it.
|
||||
|
||||
You can use whichever LaTeX distribution you like or whichever is easiest
|
||||
to install with your package manager. Usually,
|
||||
to install with your package manager. Usually,
|
||||
`TeX Live <https://www.tug.org/texlive/>`__ is a good candidate if you don't
|
||||
care too much about disk space.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ follow `Homebrew's installation instructions <https://docs.brew.sh/Installation>
|
|||
layer between Intel and ARM architectures. This is no longer necessary, Manim can
|
||||
(and is recommended to) be installed natively.
|
||||
|
||||
|
||||
|
||||
Required Dependencies
|
||||
---------------------
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ and some required Python packages), run:
|
|||
brew install py3cairo ffmpeg
|
||||
|
||||
On *Apple Silicon* based machines (i.e., devices with the M1 chip or similar; if
|
||||
you are unsure which processor you have check by opening the Apple menu, select
|
||||
you are unsure which processor you have check by opening the Apple menu, select
|
||||
*About This Mac* and check the entry next to *Chip*), some additional dependencies
|
||||
are required, namely:
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ In order to make use of Manim's interface to LaTeX for, e.g., rendering
|
|||
equations, LaTeX has to be installed as well. Note that this is an optional
|
||||
dependency: if you don't intend to use LaTeX, you don't have to install it.
|
||||
|
||||
For MacOS, the recommended LaTeX distribution is
|
||||
For MacOS, the recommended LaTeX distribution is
|
||||
`MacTeX <http://www.tug.org/mactex/>`__. You can install it by following
|
||||
the instructions from the link, or alternatively also via Homebrew by
|
||||
running:
|
||||
|
|
@ -79,7 +79,7 @@ running:
|
|||
|
||||
MacTeX is a *full* LaTeX distribution and will require more than 4GB of
|
||||
disk space. If this is an issue for you, consider installing a smaller
|
||||
distribution like
|
||||
distribution like
|
||||
`BasicTeX <http://www.tug.org/mactex/morepackages.html>`__.
|
||||
|
||||
Should you choose to work with some partial TeX distribution, the full list
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ Version incompatibility
|
|||
|
||||
Confusion and conflict between versions is by far the most common reason
|
||||
for installation failures. Some signs and errors resulting from this are
|
||||
as follows:
|
||||
as follows:
|
||||
|
||||
- ``There are no scenes in that module``
|
||||
- ``ModuleNotFoundError: No module named 'manim'``
|
||||
- ``ModuleNotFoundError: No module named 'manimlib'``
|
||||
- You followed any tutorial created before October 2020 (because the community edition did not exist before then)
|
||||
- You cloned a repository on GitHub (installation of the community version for normal use does not require the cloning of any repository)
|
||||
- Different import statements (explained below)
|
||||
- ``There are no scenes in that module``
|
||||
- ``ModuleNotFoundError: No module named 'manim'``
|
||||
- ``ModuleNotFoundError: No module named 'manimlib'``
|
||||
- You followed any tutorial created before October 2020 (because the community edition did not exist before then)
|
||||
- You cloned a repository on GitHub (installation of the community version for normal use does not require the cloning of any repository)
|
||||
- Different import statements (explained below)
|
||||
- You used documentation for multiple versions (such as the readme for 3b1b/manim and this documentation)
|
||||
|
||||
.. note::
|
||||
|
|
@ -41,7 +41,7 @@ generally not work without some modification.
|
|||
Identifying the version you are running
|
||||
---------------------------------------
|
||||
|
||||
The community edition of manim should always state `Manim Community <version_number>`
|
||||
The community edition of manim should always state `Manim Community <version_number>`
|
||||
as its first line of any command you run.
|
||||
|
||||
Identifying and removing conflicting versions of manim
|
||||
|
|
@ -120,7 +120,7 @@ First, make sure your ``dvisvgm`` version is at least 2.4:
|
|||
|
||||
If you do not know how to update ``dvisvgm``, please refer to your operating system's documentation.
|
||||
|
||||
Second, check whether your ``dvisvgm`` supports PostScript specials. This is
|
||||
Second, check whether your ``dvisvgm`` supports PostScript specials. This is
|
||||
needed to convert from PDF to SVG.
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
@ -128,7 +128,7 @@ needed to convert from PDF to SVG.
|
|||
dvisvgm -l
|
||||
|
||||
|
||||
If the output to this command does **not** contain ``ps dvips PostScript specials``,
|
||||
If the output to this command does **not** contain ``ps dvips PostScript specials``,
|
||||
this is a bad sign. In this case, run
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
@ -136,16 +136,16 @@ this is a bad sign. In this case, run
|
|||
dvisvgm -h
|
||||
|
||||
|
||||
If the output does **not** contain ``--libgs=filename``, this means your
|
||||
If the output does **not** contain ``--libgs=filename``, this means your
|
||||
``dvisvgm`` does not currently support PostScript. You must get another binary.
|
||||
|
||||
If, however, ``--libgs=filename`` appears in the help, that means that your
|
||||
``dvisvgm`` needs the Ghostscript library to support PostScript. Search for
|
||||
``libgs.so`` (on Linux, probably in ``/usr/local/lib`` or ``/usr/lib``) or
|
||||
``gsdll32.dll`` (on 32-bit Windows, probably in ``C:\windows\system32``) or
|
||||
``gsdll64.dll`` (on 64-bit Windows, probably in ``c:\windows\system32`` -- yes
|
||||
32) or ``libgsl.dylib`` (on Mac OS, probably in ``/usr/local/lib`` or
|
||||
``/opt/local/lib``). Please look carefully, as the file might be located
|
||||
If, however, ``--libgs=filename`` appears in the help, that means that your
|
||||
``dvisvgm`` needs the Ghostscript library to support PostScript. Search for
|
||||
``libgs.so`` (on Linux, probably in ``/usr/local/lib`` or ``/usr/lib``) or
|
||||
``gsdll32.dll`` (on 32-bit Windows, probably in ``C:\windows\system32``) or
|
||||
``gsdll64.dll`` (on 64-bit Windows, probably in ``c:\windows\system32`` -- yes
|
||||
32) or ``libgsl.dylib`` (on Mac OS, probably in ``/usr/local/lib`` or
|
||||
``/opt/local/lib``). Please look carefully, as the file might be located
|
||||
elsewhere, e.g. in the directory where Ghostscript is installed.
|
||||
|
||||
As soon as you have found the library, try (on Mac OS or Linux)
|
||||
|
|
@ -163,8 +163,8 @@ or (on Windows)
|
|||
dvisvgm -l
|
||||
|
||||
|
||||
You should now see ``ps dvips PostScript specials`` in the output. Refer to
|
||||
your operating system's documentation to find out how you can set or export the
|
||||
You should now see ``ps dvips PostScript specials`` in the output. Refer to
|
||||
your operating system's documentation to find out how you can set or export the
|
||||
environment variable ``LIBGS`` automatically whenever you open a shell.
|
||||
|
||||
As a last check, you can run
|
||||
|
|
@ -173,12 +173,12 @@ As a last check, you can run
|
|||
|
||||
dvisvgm -V1
|
||||
|
||||
while still having ``LIBGS`` set to the correct path, of course. If ``dvisvgm``
|
||||
can find your Ghostscript installation, it will be shown in the output together
|
||||
while still having ``LIBGS`` set to the correct path, of course. If ``dvisvgm``
|
||||
can find your Ghostscript installation, it will be shown in the output together
|
||||
with the version number.
|
||||
|
||||
If you do not have the necessary library on your system, please refer to your
|
||||
operating system's documentation to find out where you can get it and how you
|
||||
If you do not have the necessary library on your system, please refer to your
|
||||
operating system's documentation to find out where you can get it and how you
|
||||
have to install it.
|
||||
|
||||
If you are unable to solve your problem, check out the `dvisvgm FAQ <https://dvisvgm.de/FAQ/>`_.
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
Differences between Manim Versions
|
||||
==================================
|
||||
|
||||
While originally a single library, there are now three main versions of manim,
|
||||
each with their own advantages, disadvantages, and ideal use cases.
|
||||
It is important to understand these differences in order to select the best version
|
||||
While originally a single library, there are now three main versions of manim,
|
||||
each with their own advantages, disadvantages, and ideal use cases.
|
||||
It is important to understand these differences in order to select the best version
|
||||
for your use case and avoid confusion arising from version mismatches.
|
||||
|
||||
A brief history of Manim
|
||||
************************
|
||||
|
||||
Manim was originally created by Grant Sanderson as a personal project and for use in his YouTube channel,
|
||||
`3Blue1Brown <https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw>`_. As his channel gained popularity,
|
||||
many grew to like the style of his animations and wanted to use manim for their own projects.
|
||||
However, as manim was only intended for personal use,
|
||||
Manim was originally created by Grant Sanderson as a personal project and for use in his YouTube channel,
|
||||
`3Blue1Brown <https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw>`_. As his channel gained popularity,
|
||||
many grew to like the style of his animations and wanted to use manim for their own projects.
|
||||
However, as manim was only intended for personal use,
|
||||
it was very difficult for other users to install and use it.
|
||||
|
||||
In late 2019, Grant started working on faster OpenGL rendering in a new branch,
|
||||
known as the shaders branch. In mid-2020, a group of developers forked it into what is now the community edition;
|
||||
this is the version documented on this website.
|
||||
In early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository.
|
||||
In late 2019, Grant started working on faster OpenGL rendering in a new branch,
|
||||
known as the shaders branch. In mid-2020, a group of developers forked it into what is now the community edition;
|
||||
this is the version documented on this website.
|
||||
In early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository.
|
||||
The old version is still available as the branch ``cairo-backend``.
|
||||
|
||||
The three versions of Manim
|
||||
|
|
@ -32,8 +32,8 @@ There are currently three main versions of manim. They are as follows:
|
|||
|
||||
Which version to use
|
||||
********************
|
||||
We recommend using the community edition for most purposes, as it has been developed to be more stable,
|
||||
better tested, quicker to respond to community contributions, and easier for beginners to use.
|
||||
We recommend using the community edition for most purposes, as it has been developed to be more stable,
|
||||
better tested, quicker to respond to community contributions, and easier for beginners to use.
|
||||
It also has partial experimental OpenGL support and should have full support shortly (as of April 2021).
|
||||
|
||||
If you would like to use a version with full OpenGL support or render recent 3Blue1Brown videos (2020 onwards), you should use ManimGL.
|
||||
|
|
@ -42,8 +42,8 @@ If you would like to render old 3Blue1Brown projects (2019 and before), you shou
|
|||
|
||||
Notes on installation, documentation, and use
|
||||
*********************************************
|
||||
If you are a beginner, it is very important that you only use the documentation for your desired version.
|
||||
Trying to install or learn manim using documentation or guides made for different versions will likely fail and only lead to more confusion.
|
||||
As many tutorials and guides on the internet are outdated, we do not recommend you follow them.
|
||||
You should only read tutorials and documentation for other versions once you are aware of the differences between them
|
||||
If you are a beginner, it is very important that you only use the documentation for your desired version.
|
||||
Trying to install or learn manim using documentation or guides made for different versions will likely fail and only lead to more confusion.
|
||||
As many tutorials and guides on the internet are outdated, we do not recommend you follow them.
|
||||
You should only read tutorials and documentation for other versions once you are aware of the differences between them
|
||||
and know how to adapt code for your desired version.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Windows
|
|||
=======
|
||||
|
||||
The easiest way of installing Manim and its dependencies is by using a
|
||||
package manager like `Chocolatey <https://chocolatey.org/>`__
|
||||
package manager like `Chocolatey <https://chocolatey.org/>`__
|
||||
or `Scoop <https://scoop.sh>`__. If you are not afraid of editing
|
||||
your System's ``PATH``, a manual installation is also possible.
|
||||
In fact, if you already have an existing Python
|
||||
|
|
@ -11,7 +11,7 @@ everything up and running.
|
|||
|
||||
If you choose to use one of the package managers, please follow
|
||||
their installation instructions
|
||||
(`for Chocolatey <https://chocolatey.org/install#install-step2>`__,
|
||||
(`for Chocolatey <https://chocolatey.org/install#install-step2>`__,
|
||||
`for Scoop <https://scoop-docs.now.sh/docs/getting-started/Quick-Start.html>`__)
|
||||
to make one of them available on your system.
|
||||
|
||||
|
|
@ -69,24 +69,24 @@ installed on your system.
|
|||
We have received reports of problems caused by using the version of
|
||||
Python that can be installed from the Windows Store. At this point,
|
||||
we recommend staying away from the Windows Store version. Instead,
|
||||
install Python directly from the
|
||||
install Python directly from the
|
||||
`official website <https://www.python.org>`__.
|
||||
|
||||
**FFmpeg:** In order to install FFmpeg, you can get a
|
||||
pre-compiled and ready-to-use version from one of the resources
|
||||
linked at https://ffmpeg.org/download.html#build-windows, such as
|
||||
`the version available here
|
||||
`the version available here
|
||||
<https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.7z>`__
|
||||
(recommended), or if you know exactly what you are doing
|
||||
you can alternatively get the source code
|
||||
from https://ffmpeg.org/download.html and compile it yourself.
|
||||
|
||||
|
||||
After downloading the pre-compiled archive,
|
||||
After downloading the pre-compiled archive,
|
||||
`unzip it <https://www.7-zip.org>`__ and, if you like, move the
|
||||
extracted directory to some more permanent place (e.g.,
|
||||
extracted directory to some more permanent place (e.g.,
|
||||
``C:\Program Files\``). Next, edit the ``PATH`` environment variable:
|
||||
first, visit ``Control Panel`` > ``System`` > ``System settings`` >
|
||||
first, visit ``Control Panel`` > ``System`` > ``System settings`` >
|
||||
``Environment Variables``, then add the full path to the ``bin``
|
||||
directory inside of the (moved) ffmpeg directory to the
|
||||
``PATH`` variable. Finally, save your changes and exit.
|
||||
|
|
@ -111,14 +111,14 @@ In order to make use of Manim's interface to LaTeX to, for example, render
|
|||
equations, LaTeX has to be installed as well. Note that this is an optional
|
||||
dependency: if you don't intend to use LaTeX, you don't have to install it.
|
||||
|
||||
For Windows, the recommended LaTeX distribution is
|
||||
For Windows, the recommended LaTeX distribution is
|
||||
`MiKTeX <https://miktex.org/download>`__. You can install it by using the
|
||||
installer from the linked MiKTeX site, or by using the package manager
|
||||
of your choice (Chocolatey: ``choco install miktex.install``,
|
||||
Scoop: ``scoop install latex``).
|
||||
|
||||
If you are concerned about disk space, there are some alternative,
|
||||
smaller distributions of LaTeX like
|
||||
smaller distributions of LaTeX like
|
||||
`TinyTeX <https://yihui.org/tinytex/>`__ (Chocolatey: ``choco install tinytex``,
|
||||
Scoop: first ``scoop bucket add r-bucket https://github.com/cderv/r-bucket.git``,
|
||||
then ``scoop install tinytex``). In this case, you will have to manage the
|
||||
|
|
|
|||
|
|
@ -133,7 +133,8 @@ class ManimDirective(Directive):
|
|||
option_spec = {
|
||||
"hide_source": bool,
|
||||
"quality": lambda arg: directives.choice(
|
||||
arg, ("low", "medium", "high", "fourk")
|
||||
arg,
|
||||
("low", "medium", "high", "fourk"),
|
||||
),
|
||||
"save_as_gif": bool,
|
||||
"save_last_frame": bool,
|
||||
|
|
@ -148,7 +149,9 @@ class ManimDirective(Directive):
|
|||
if "skip-manim" in self.state.document.settings.env.app.builder.tags.tags:
|
||||
node = skip_manim_node()
|
||||
self.state.nested_parse(
|
||||
StringList(self.content[0]), self.content_offset, node
|
||||
StringList(self.content[0]),
|
||||
self.content_offset,
|
||||
node,
|
||||
)
|
||||
return [node]
|
||||
|
||||
|
|
@ -273,7 +276,8 @@ class ManimDirective(Directive):
|
|||
ref_block=ref_block,
|
||||
)
|
||||
state_machine.insert_input(
|
||||
rendered_template.split("\n"), source=document.attributes["source"]
|
||||
rendered_template.split("\n"),
|
||||
source=document.attributes["source"],
|
||||
)
|
||||
|
||||
return []
|
||||
|
|
@ -289,7 +293,7 @@ def _write_rendering_stats(scene_name, run_time, file_name):
|
|||
re.sub(r"^(reference\/)|(manim\.)", "", file_name),
|
||||
scene_name,
|
||||
"%.3f" % run_time,
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -312,7 +316,7 @@ def _log_rendering_times(*args):
|
|||
continue
|
||||
time_sum = sum(float(row[2]) for row in group)
|
||||
print(
|
||||
f"{key}{f'{time_sum:.3f}'.rjust(7, '.')}s => {len(group)} EXAMPLES"
|
||||
f"{key}{f'{time_sum:.3f}'.rjust(7, '.')}s => {len(group)} EXAMPLES",
|
||||
)
|
||||
for row in group:
|
||||
print(f"{' '*(max_file_length)} {row[2].rjust(7)}s {row[1]}")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Plugins are features that extend Manim's core functionality. Since Manim is
|
|||
extensible and not everything belongs in its core, we'll go over how to
|
||||
install, use, and create your own plugins.
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
The standard naming convention for plugins is to prefix the plugin with
|
||||
``manim-``. This makes them easy for users to find on package
|
||||
|
|
@ -65,7 +65,7 @@ For enabling a plugin ``manim.cfg`` or command line parameters should be used.
|
|||
|
||||
The plugins should be module name of the plugin and not PyPi name.
|
||||
|
||||
Enabling plugins through ``manim.cfg``
|
||||
Enabling plugins through ``manim.cfg``
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
|
|
|
|||
|
|
@ -44,5 +44,3 @@ Module Index
|
|||
~animation.transform
|
||||
~animation.transform_matching_parts
|
||||
~animation.update
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,5 +12,3 @@ Module Index
|
|||
~_config
|
||||
~_config.utils
|
||||
~_config.logger_utils
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,4 +77,3 @@ Module Index
|
|||
~mobject.types.image_mobject
|
||||
~mobject.types.point_cloud_mobject
|
||||
~mobject.types.vectorized_mobject
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ User-agent: *
|
|||
Disallow: /
|
||||
Allow: /en/stable/
|
||||
|
||||
Sitemap: https://docs.manim.community/sitemap.xml
|
||||
Sitemap: https://docs.manim.community/sitemap.xml
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ the use of :meth:`.animate`.
|
|||
self.play(square.animate.shift(UP).rotate(PI / 3))
|
||||
self.wait(1)
|
||||
|
||||
:meth:`.animate` is a property of all mobjects that animates the methods that come
|
||||
:meth:`.animate` is a property of all mobjects that animates the methods that come
|
||||
afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of
|
||||
the square, while :code:`sqaure.animate.set_fill(WHITE)` animates this action.
|
||||
|
||||
|
|
@ -368,7 +368,7 @@ Using coordinates of a mobject
|
|||
==============================
|
||||
|
||||
Mobjects contain points that define their boundaries.
|
||||
These points can be used to add other mobjects respectively to each other,
|
||||
These points can be used to add other mobjects respectively to each other,
|
||||
e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top`
|
||||
and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:
|
||||
|
||||
|
|
@ -411,12 +411,12 @@ It is also possible to transform a mobject into another mobject like this:
|
|||
m2 = Rectangle().set_color(RED).rotate(0.2)
|
||||
self.play(Transform(m1,m2))
|
||||
|
||||
The Transform function maps points of the previous mobject to the points of the
|
||||
The Transform function maps points of the previous mobject to the points of the
|
||||
next mobject.
|
||||
This might result in strange behaviour, e.g. when the dots of one mobject are
|
||||
This might result in strange behaviour, e.g. when the dots of one mobject are
|
||||
arranged clockwise and the other points are arranged counterclockwise.
|
||||
Here it might help to use the `flip` function and reposition the points via the
|
||||
`roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_
|
||||
Here it might help to use the `flip` function and reposition the points via the
|
||||
`roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_
|
||||
function of numpy:
|
||||
|
||||
.. manim:: ExampleRotation
|
||||
|
|
@ -428,11 +428,11 @@ function of numpy:
|
|||
m1b = Circle().set_color(RED).shift(LEFT)
|
||||
m2a= Square().set_color(BLUE).shift(RIGHT)
|
||||
m2b= Circle().set_color(BLUE).shift(RIGHT)
|
||||
|
||||
|
||||
points = m2a.points
|
||||
points = np.roll(points, int(len(points)/4), axis=0)
|
||||
m2a.points = points
|
||||
|
||||
|
||||
self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1)
|
||||
|
||||
******
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ high, and 4k quality, respectively.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -ql <file.py> SceneName
|
||||
manim -ql <file.py> SceneName
|
||||
|
||||
These flags set the values of the config options ``config.pixel_width``,
|
||||
``config.pixel_height``, ``config.frame_rate``, and ``config.quality``.
|
||||
|
|
@ -110,7 +110,7 @@ instead of the whole video, you can execute
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -sqh <file.py> SceneName
|
||||
manim -sqh <file.py> SceneName
|
||||
|
||||
The following example specifies the output file name (with the :code:`-o`
|
||||
flag), renders only the first ten animations (:code:`-n` flag) with a white
|
||||
|
|
@ -120,7 +120,7 @@ open the file after it is rendered.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -o myscene -i -n 0,10 -c WHITE <file.py> SceneName
|
||||
manim -o myscene -i -n 0,10 -c WHITE <file.py> SceneName
|
||||
|
||||
.. tip:: There are many more command-line flags that manim accepts. All the
|
||||
possible flags are shown by executing ``manim render --help``. A complete list
|
||||
|
|
@ -162,7 +162,7 @@ Now, executing the following command
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -o myscene -i -c WHITE <file.py> SceneName
|
||||
manim -o myscene -i -c WHITE <file.py> SceneName
|
||||
|
||||
is equivalent to executing the following command, provided that ``manim.cfg``
|
||||
is in the same directory as <file.py>,
|
||||
|
|
@ -377,8 +377,8 @@ A list of all CLI flags
|
|||
plugins Manages Manim plugins.
|
||||
|
||||
Made with <3 by Manim Community developers.
|
||||
|
||||
Each of the subcommands has its own help page which can be
|
||||
|
||||
Each of the subcommands has its own help page which can be
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ the following command:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -pql scene.py SquareToCircle
|
||||
manim -pql scene.py SquareToCircle
|
||||
|
||||
After showing some output, manim should render the scene into a .mp4 file,
|
||||
and open that file with the default movie player application. You should see a
|
||||
|
|
@ -158,7 +158,7 @@ And render it using the following command:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
manim -pql scene.py SquareToCircle
|
||||
manim -pql scene.py SquareToCircle
|
||||
|
||||
The output should look as follows.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ There are two different ways by which you can render **Text** in videos:
|
|||
1. Using Pango (:mod:`~.text_mobject`)
|
||||
2. Using LaTeX (:mod:`~.tex_mobject`)
|
||||
|
||||
If you want to render simple text, you should use either :class:`~.Text` or
|
||||
If you want to render simple text, you should use either :class:`~.Text` or
|
||||
:class:`~.MarkupText`, or one of its derivatives like :class:`~.Paragraph`.
|
||||
See :ref:`using-text-objects` for more information.
|
||||
|
||||
LaTeX should be used when you need mathematical typesetting. See
|
||||
LaTeX should be used when you need mathematical typesetting. See
|
||||
:ref:`rendering-with-latex` for more information.
|
||||
|
||||
.. _using-text-objects:
|
||||
|
|
@ -26,7 +26,7 @@ render non-English alphabets like 你好 or こんにちは or 안녕하세요
|
|||
|
||||
Here is a simple *Hello World* animation.
|
||||
|
||||
.. manim:: HelloWorld
|
||||
.. manim:: HelloWorld
|
||||
:save_last_frame:
|
||||
:ref_classes: Text
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ You can also use :class:`~.MarkupText` which allows the use of PangoMarkup
|
|||
(see the documentation of :class:`~.MarkupText` for details) to render text.
|
||||
For example:
|
||||
|
||||
.. manim:: SingleLineColor
|
||||
.. manim:: SingleLineColor
|
||||
:save_last_frame:
|
||||
:ref_classes: MarkupText
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ Using Fonts
|
|||
|
||||
You can set a different font using :attr:`~.Text.font`.
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
The font used must be installed in your system, and Pango should know
|
||||
about it. You can get a list of fonts using :func:`manimpango.list_fonts`.
|
||||
|
|
@ -71,9 +71,9 @@ You can set a different font using :attr:`~.Text.font`.
|
|||
[...]
|
||||
|
||||
|
||||
.. manim:: FontsExample
|
||||
.. manim:: FontsExample
|
||||
:save_last_frame:
|
||||
|
||||
|
||||
class FontsExample(Scene):
|
||||
def construct(self):
|
||||
ft = Text("Noto Sans", font="Noto Sans")
|
||||
|
|
@ -81,7 +81,7 @@ You can set a different font using :attr:`~.Text.font`.
|
|||
|
||||
Setting Slant and Weight
|
||||
------------------------
|
||||
Slant is the style of the Text, and it can be ``NORMAL`` (the default),
|
||||
Slant is the style of the Text, and it can be ``NORMAL`` (the default),
|
||||
``ITALIC`` or ``OBLIQUE``. Usually, for many fonts both ``ITALIC`` and
|
||||
``OBLIQUE`` look similar, but ``ITALIC`` uses **Roman Style**, whereas
|
||||
``OBLIQUE`` uses **Italic Style**.
|
||||
|
|
@ -97,7 +97,7 @@ Weight specifies the boldness of a font. You can see a list of weights in
|
|||
a = Text("Italic", slant=ITALIC)
|
||||
self.add(a)
|
||||
|
||||
.. manim:: DifferentWeight
|
||||
.. manim:: DifferentWeight
|
||||
:save_last_frame:
|
||||
|
||||
class DifferentWeight(Scene):
|
||||
|
|
@ -131,10 +131,10 @@ as explained in :ref:`iterating-text`.
|
|||
|
||||
:attr:`~Text.t2c` accepts two types of dictionaries,
|
||||
|
||||
* The keys can contain indices like ``[2:-1]`` or ``[4:8]``,
|
||||
* The keys can contain indices like ``[2:-1]`` or ``[4:8]``,
|
||||
this works similar to how `slicing <https://realpython.com/python-strings/#string-slicing>`_
|
||||
works in Python. The values should be the color of the Text from :class:`~.Color`.
|
||||
|
||||
|
||||
|
||||
* The keys contain words or characters which should be colored separately
|
||||
and the values should be the color from :class:`~.Color`:
|
||||
|
|
@ -166,7 +166,7 @@ be an iterable of any length:
|
|||
t = Text("Hello", gradient=(RED, BLUE, GREEN), font_size=96)
|
||||
self.add(t)
|
||||
|
||||
You can also use :attr:`~.Text.t2g` for gradients with specific
|
||||
You can also use :attr:`~.Text.t2g` for gradients with specific
|
||||
characters of the text. It shares a similar syntax to :ref:`the
|
||||
interface for colors <using-colors>`:
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ Disabling Ligatures
|
|||
-------------------
|
||||
|
||||
By disabling ligatures you would get a one-to-one mapping between characters and
|
||||
submobjects. This fixes the issues with coloring text.
|
||||
submobjects. This fixes the issues with coloring text.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
|
@ -218,7 +218,7 @@ submobjects. This fixes the issues with coloring text.
|
|||
Be aware that using this method with text that heavily depends on
|
||||
ligatures (Arabic text) may yield unexpected results.
|
||||
|
||||
You can disable ligatures by passing ``disable_ligatures`` to
|
||||
You can disable ligatures by passing ``disable_ligatures`` to
|
||||
:class:`Text`. For example:
|
||||
|
||||
.. manim:: DisableLigature
|
||||
|
|
@ -262,14 +262,14 @@ For example, you can set each letter to different color by iterating it.
|
|||
Working with :class:`~.MarkupText`
|
||||
==================================
|
||||
|
||||
MarkupText is similar to :class:`~.Text`, the only difference between them is
|
||||
MarkupText is similar to :class:`~.Text`, the only difference between them is
|
||||
that this accepts and processes PangoMarkup (which is similar to
|
||||
html), instead of just rendering plain text.
|
||||
|
||||
Consult the documentation of :class:`~.MarkupText` for more details
|
||||
and further references about PangoMarkup.
|
||||
|
||||
.. manim:: MarkupTest
|
||||
.. manim:: MarkupTest
|
||||
:save_last_frame:
|
||||
|
||||
class MarkupTest(Scene):
|
||||
|
|
@ -291,7 +291,7 @@ use :class:`~.Tex` to insert LaTeX.
|
|||
|
||||
For example,
|
||||
|
||||
.. manim:: HelloLaTeX
|
||||
.. manim:: HelloLaTeX
|
||||
:save_last_frame:
|
||||
|
||||
class HelloLaTeX(Scene):
|
||||
|
|
@ -314,14 +314,14 @@ Everything passed to :class:`~.MathTex` is in math mode by default. To be more p
|
|||
similar effect with :class:`~.Tex` by enclosing your formula with ``$`` symbols:
|
||||
``$\xrightarrow{x^6y^8}$``:
|
||||
|
||||
.. manim:: MathTeXDemo
|
||||
.. manim:: MathTeXDemo
|
||||
:save_last_frame:
|
||||
|
||||
class MathTeXDemo(Scene):
|
||||
def construct(self):
|
||||
rtarrow0 = MathTex(r"\xrightarrow{x^6y^8}", font_size=96)
|
||||
rtarrow1 = Tex(r"$\xrightarrow{x^6y^8}$", font_size=96)
|
||||
|
||||
|
||||
self.add(VGroup(rtarrow0, rtarrow1).arrange(DOWN))
|
||||
|
||||
|
||||
|
|
@ -339,8 +339,8 @@ as the ``mathtt`` math-text type or the ``looparrowright`` arrow.
|
|||
tex = Tex(r'$\mathtt{H} \looparrowright$ \LaTeX', font_size=144)
|
||||
self.add(tex)
|
||||
|
||||
On the Manim side, the :class:`~.Tex` class also accepts attributes to
|
||||
change the appearance of the output. This is very similar to the
|
||||
On the Manim side, the :class:`~.Tex` class also accepts attributes to
|
||||
change the appearance of the output. This is very similar to the
|
||||
:class:`~.Text` class. For example, the ``color`` keyword changes the
|
||||
color of the TeX mobject.
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ color of the TeX mobject.
|
|||
Extra LaTeX Packages
|
||||
====================
|
||||
|
||||
Some commands require special packages to be loaded into the TeX template.
|
||||
Some commands require special packages to be loaded into the TeX template.
|
||||
For example, to use the ``mathscr`` script, we need to add the ``mathrsfs``
|
||||
package. Since this package isn't loaded into Manim's tex template by default,
|
||||
we have to add it manually.
|
||||
|
|
@ -401,7 +401,7 @@ the Tex, not just the specific symbol or Tex expression. Consider the following
|
|||
equation.set_color_by_tex("x", YELLOW)
|
||||
self.add(equation)
|
||||
|
||||
As you can see, this colors the entire equation yellow, contrary to what
|
||||
As you can see, this colors the entire equation yellow, contrary to what
|
||||
may be expected. To color only ``x`` yellow, we have to do the following:
|
||||
|
||||
.. manim:: CorrectLaTeXSubstringColoring
|
||||
|
|
@ -417,8 +417,8 @@ may be expected. To color only ``x`` yellow, we have to do the following:
|
|||
self.add(equation)
|
||||
|
||||
By setting ``substrings_to_isolate`` to ``x``, we split up the
|
||||
:class:`~.MathTex` into substrings automatically and isolate the ``x`` components
|
||||
into individual substrings. Only then can :meth:`~.set_color_by_tex` be used
|
||||
:class:`~.MathTex` into substrings automatically and isolate the ``x`` components
|
||||
into individual substrings. Only then can :meth:`~.set_color_by_tex` be used
|
||||
to achieve the desired result.
|
||||
|
||||
Note that Manim also supports a custom syntax that allows splitting
|
||||
|
|
@ -432,9 +432,9 @@ to write using :class:`~.TransformMatchingTex`.
|
|||
LaTeX Maths Fonts - The Template Library
|
||||
========================================
|
||||
|
||||
Changing fonts in LaTeX when typesetting mathematical formulae is
|
||||
Changing fonts in LaTeX when typesetting mathematical formulae is
|
||||
trickier than regular text. It requires changing the template that is used
|
||||
to compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates`
|
||||
to compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates`
|
||||
ready for you to use. These templates will all work in math mode:
|
||||
|
||||
.. manim:: LaTeXMathFonts
|
||||
|
|
@ -445,11 +445,11 @@ ready for you to use. These templates will all work in math mode:
|
|||
tex = Tex(r'$x^2 + y^2 = z^2$', tex_template=TexFontTemplates.french_cursive, font_size=144)
|
||||
self.add(tex)
|
||||
|
||||
Manim also has a :class:`~.TexTemplateLibrary` containing the TeX
|
||||
Manim also has a :class:`~.TexTemplateLibrary` containing the TeX
|
||||
templates used by 3Blue1Brown. One example is the ctex template,
|
||||
used for typesetting Chinese script. For this to work, the ctex LaTeX package
|
||||
must be installed on your system. Furthermore, if you are only
|
||||
typesetting Text, you probably do not need :class:`~.Tex` at all, and
|
||||
must be installed on your system. Furthermore, if you are only
|
||||
typesetting Text, you probably do not need :class:`~.Tex` at all, and
|
||||
should use :class:`~.Text` instead.
|
||||
|
||||
.. manim:: LaTeXTemplateLibrary
|
||||
|
|
@ -465,7 +465,7 @@ Aligning formulae
|
|||
=================
|
||||
|
||||
:class:`~.MathTex` mobject is typeset in the LaTeX ``align*``
|
||||
environment. This means you can use the ``&`` alignment character
|
||||
environment. This means you can use the ``&`` alignment character
|
||||
when typesetting multiline formulae:
|
||||
|
||||
.. manim:: LaTeXAlignEnvironment
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ TemplateForFrenchCursive = TexTemplate(
|
|||
\usepackage[default]{frcursive}
|
||||
\usepackage[eulergreek,noplusnominus,noequal,nohbar,%
|
||||
nolessnomore,noasterisk]{mathastext}
|
||||
"""
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -33,9 +33,9 @@ class TexFontTemplateManual(Scene):
|
|||
self.play(
|
||||
Create(
|
||||
Tex(
|
||||
"See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html"
|
||||
).shift(2 * DOWN)
|
||||
)
|
||||
"See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html",
|
||||
).shift(2 * DOWN),
|
||||
),
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
|
@ -132,8 +132,8 @@ class TexFontTemplateLibrary(Scene):
|
|||
self.play(
|
||||
Create(
|
||||
Tex(
|
||||
"See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html"
|
||||
).shift(2 * DOWN)
|
||||
)
|
||||
"See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html",
|
||||
).shift(2 * DOWN),
|
||||
),
|
||||
)
|
||||
self.wait(2)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class OpeningManim(Scene):
|
|||
self.wait()
|
||||
|
||||
grid_transform_title = Tex(
|
||||
r"That was a non-linear function \\ applied to the grid"
|
||||
r"That was a non-linear function \\ applied to the grid",
|
||||
)
|
||||
grid_transform_title.move_to(grid_title, UL)
|
||||
grid.prepare_for_nonlinear_transform()
|
||||
|
|
@ -58,8 +58,8 @@ class OpeningManim(Scene):
|
|||
np.sin(p[1]),
|
||||
np.sin(p[0]),
|
||||
0,
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
run_time=3,
|
||||
)
|
||||
|
|
@ -86,8 +86,9 @@ class WarpSquare(Scene):
|
|||
square = Square()
|
||||
self.play(
|
||||
ApplyPointwiseFunction(
|
||||
lambda point: complex_to_R3(np.exp(R3_to_complex(point))), square
|
||||
)
|
||||
lambda point: complex_to_R3(np.exp(R3_to_complex(point))),
|
||||
square,
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ logging_level_info = dim green
|
|||
logging_level_warning = dim red
|
||||
logging_level_error = red
|
||||
logging_level_critical = red
|
||||
log_level =
|
||||
log_level =
|
||||
log_time = dim yellow
|
||||
log_message = green
|
||||
log_path = dim
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def get_plane_mesh(context):
|
|||
[-1, 0, -1, 1],
|
||||
[1, 0, -1, 1],
|
||||
[1, 0, 1, 1],
|
||||
]
|
||||
],
|
||||
)
|
||||
attributes["in_color"] = np.array(
|
||||
[
|
||||
|
|
@ -66,7 +66,7 @@ def get_plane_mesh(context):
|
|||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
]
|
||||
],
|
||||
)
|
||||
return Mesh(shader, attributes)
|
||||
|
||||
|
|
@ -95,7 +95,8 @@ class GuiTest(Scene):
|
|||
|
||||
def update_mesh(mesh, dt):
|
||||
mesh.model_matrix = np.matmul(
|
||||
opengl.rotation_matrix(z=dt), mesh.model_matrix
|
||||
opengl.rotation_matrix(z=dt),
|
||||
mesh.model_matrix,
|
||||
)
|
||||
|
||||
mesh.add_updater(update_mesh)
|
||||
|
|
@ -124,7 +125,7 @@ class GuiTest2(Scene):
|
|||
"min_value": 0,
|
||||
"max_value": 1,
|
||||
"default_value": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
self.interactive_embed()
|
||||
|
|
@ -145,7 +146,8 @@ class ThreeDMobjectTest(Scene):
|
|||
|
||||
def update_mesh(mesh, dt):
|
||||
mesh.model_matrix = np.matmul(
|
||||
opengl.rotation_matrix(z=dt), mesh.model_matrix
|
||||
opengl.rotation_matrix(z=dt),
|
||||
mesh.model_matrix,
|
||||
)
|
||||
|
||||
mesh.add_updater(update_mesh)
|
||||
|
|
@ -157,7 +159,8 @@ class NamedFullScreenQuad(Scene):
|
|||
def construct(self):
|
||||
surface = FullScreenQuad(self.renderer.context, fragment_shader_name="design_3")
|
||||
surface.shader.set_uniform(
|
||||
"u_resolution", (config["pixel_width"], config["pixel_height"], 0.0)
|
||||
"u_resolution",
|
||||
(config["pixel_width"], config["pixel_height"], 0.0),
|
||||
)
|
||||
surface.shader.set_uniform("u_time", 0)
|
||||
self.add(surface)
|
||||
|
|
@ -219,7 +222,8 @@ class InlineFullScreenQuad(Scene):
|
|||
""",
|
||||
)
|
||||
surface.shader.set_uniform(
|
||||
"u_resolution", (config["pixel_width"], config["pixel_height"])
|
||||
"u_resolution",
|
||||
(config["pixel_width"], config["pixel_height"]),
|
||||
)
|
||||
shader_time = 0
|
||||
|
||||
|
|
@ -322,7 +326,8 @@ class InlineShaderExample(Scene):
|
|||
)
|
||||
shader.set_uniform("u_model_view_matrix", opengl.view_matrix())
|
||||
shader.set_uniform(
|
||||
"u_projection_matrix", opengl.orthographic_projection_matrix()
|
||||
"u_projection_matrix",
|
||||
opengl.orthographic_projection_matrix(),
|
||||
)
|
||||
|
||||
attributes = np.zeros(
|
||||
|
|
@ -340,7 +345,7 @@ class InlineShaderExample(Scene):
|
|||
[-1, -1, 0, 1],
|
||||
[1, -1, 0, 1],
|
||||
[1, 1, 0, 1],
|
||||
]
|
||||
],
|
||||
)
|
||||
attributes["in_color"] = np.array(
|
||||
[
|
||||
|
|
@ -350,7 +355,7 @@ class InlineShaderExample(Scene):
|
|||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
]
|
||||
],
|
||||
)
|
||||
mesh = Mesh(shader, attributes)
|
||||
self.add(mesh)
|
||||
|
|
@ -367,7 +372,8 @@ class NamedShaderExample(Scene):
|
|||
view_matrix = self.camera.get_view_matrix()
|
||||
shader.set_uniform("u_model_view_matrix", view_matrix)
|
||||
shader.set_uniform(
|
||||
"u_projection_matrix", opengl.perspective_projection_matrix()
|
||||
"u_projection_matrix",
|
||||
opengl.perspective_projection_matrix(),
|
||||
)
|
||||
attributes = np.zeros(
|
||||
6,
|
||||
|
|
@ -383,7 +389,7 @@ class NamedShaderExample(Scene):
|
|||
[-1, -1, 0, 1],
|
||||
[1, -1, 0, 1],
|
||||
[1, 1, 0, 1],
|
||||
]
|
||||
],
|
||||
)
|
||||
mesh = Mesh(shader, attributes)
|
||||
self.add(mesh)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# flake8: noqa
|
||||
|
||||
import pkg_resources
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ parser = make_config_parser()
|
|||
# Throughout the codebase, use manim.console.print() instead of print().
|
||||
# Use error_console to print errors so that it outputs to stderr.
|
||||
logger, console, error_console = make_logger(
|
||||
parser["logger"], parser["CLI"]["verbosity"]
|
||||
parser["logger"],
|
||||
parser["CLI"]["verbosity"],
|
||||
)
|
||||
# TODO: temporary to have a clean terminal output when working with PIL or matplotlib
|
||||
logging.getLogger("PIL").setLevel(logging.INFO)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ fullscreen = False
|
|||
window_position = UR
|
||||
|
||||
# Manually adjust the size of the window, or use default to automatically scale the window based on
|
||||
# the dimensions of the monitor.
|
||||
# the dimensions of the monitor.
|
||||
# --window_size
|
||||
window_size = default
|
||||
|
||||
|
|
@ -150,7 +150,7 @@ tex_template =
|
|||
|
||||
# specify the plugins as comma separated values
|
||||
# manim will load that plugin if it specified here.
|
||||
plugins =
|
||||
plugins =
|
||||
|
||||
# Overrides the default output folders, NOT the output file names. Note that
|
||||
# if the custom_folders flag is present, the Tex and text files will not be put
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ Loading the default color configuration.[/logging.level.error]
|
|||
|
||||
|
||||
def make_logger(
|
||||
parser: configparser.ConfigParser, verbosity: str
|
||||
parser: configparser.ConfigParser,
|
||||
verbosity: str,
|
||||
) -> typing.Tuple[logging.Logger, Console]:
|
||||
"""Make the manim logger and console.
|
||||
|
||||
|
|
@ -88,7 +89,8 @@ def make_logger(
|
|||
# set the rich handler
|
||||
RichHandler.KEYWORDS = HIGHLIGHTED_KEYWORDS
|
||||
rich_handler = RichHandler(
|
||||
console=console, show_time=parser.getboolean("log_timestamps")
|
||||
console=console,
|
||||
show_time=parser.getboolean("log_timestamps"),
|
||||
)
|
||||
|
||||
# finally, the logger
|
||||
|
|
@ -130,7 +132,7 @@ def parse_theme(parser: configparser.ConfigParser) -> Theme:
|
|||
k: v
|
||||
for k, v in theme.items()
|
||||
if k not in ["log.width", "log.height", "log.timestamps"]
|
||||
}
|
||||
},
|
||||
)
|
||||
except (color.ColorParseError, errors.StyleSyntaxError):
|
||||
printf(WRONG_COLOR_CONFIG_MSG)
|
||||
|
|
@ -201,5 +203,5 @@ class JSONFormatter(logging.Formatter):
|
|||
"levelname": record_c.levelname,
|
||||
"module": record_c.module,
|
||||
"message": super().format(record_c),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -445,18 +445,18 @@ class ManimConfig(MutableMapping):
|
|||
self._d[key] = val
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{key} must be an integer such that {lo} <= {key} <= {hi}"
|
||||
f"{key} must be an integer such that {lo} <= {key} <= {hi}",
|
||||
)
|
||||
|
||||
def _set_pos_number(self, key: str, val: int, allow_inf: bool) -> None:
|
||||
"""Set ``key`` to ``val`` if ``val`` is a positive integer."""
|
||||
if isinstance(val, int) and val > -1:
|
||||
self._d[key] = val
|
||||
elif allow_inf and (val == -1 or val == float("inf")):
|
||||
elif allow_inf and val in [-1, float("inf")]:
|
||||
self._d[key] = float("inf")
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{key} must be a non-negative integer (use -1 for infinity)"
|
||||
f"{key} must be a non-negative integer (use -1 for infinity)",
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
@ -696,9 +696,8 @@ class ManimConfig(MutableMapping):
|
|||
self[key] = attr
|
||||
|
||||
# dry_run is special because it can only be set to True
|
||||
if hasattr(args, "dry_run"):
|
||||
if getattr(args, "dry_run"):
|
||||
self["dry_run"] = True
|
||||
if getattr(args, "dry_run", False):
|
||||
self["dry_run"] = True
|
||||
|
||||
for key in [
|
||||
"media_dir", # always set this one first
|
||||
|
|
@ -723,7 +722,7 @@ class ManimConfig(MutableMapping):
|
|||
self.upto_animation_number = nflag[1]
|
||||
except Exception:
|
||||
logging.getLogger("manim").info(
|
||||
f"No end scene number specified in -n option. Rendering from {nflag[0]} onwards..."
|
||||
f"No end scene number specified in -n option. Rendering from {nflag[0]} onwards...",
|
||||
)
|
||||
|
||||
# Handle the quality flags
|
||||
|
|
@ -759,10 +758,9 @@ class ManimConfig(MutableMapping):
|
|||
if args.tex_template:
|
||||
self.tex_template = TexTemplateFromFile(tex_filename=args.tex_template)
|
||||
|
||||
if self.renderer == "opengl":
|
||||
if getattr(args, "write_to_movie") is None:
|
||||
# --write_to_movie was not passed on the command line, so don't generate video.
|
||||
self["write_to_movie"] = False
|
||||
if self.renderer == "opengl" and getattr(args, "write_to_movie") is None:
|
||||
# --write_to_movie was not passed on the command line, so don't generate video.
|
||||
self["write_to_movie"] = False
|
||||
|
||||
# Handle --gui_location flag.
|
||||
if getattr(args, "gui_location") is not None:
|
||||
|
|
@ -827,7 +825,9 @@ class ManimConfig(MutableMapping):
|
|||
progress_bar = property(
|
||||
lambda self: self._d["progress_bar"],
|
||||
lambda self, val: self._set_from_list(
|
||||
"progress_bar", val, ["none", "display", "leave"]
|
||||
"progress_bar",
|
||||
val,
|
||||
["none", "display", "leave"],
|
||||
),
|
||||
doc="Whether to show progress bars while rendering animations.",
|
||||
)
|
||||
|
|
@ -912,13 +912,15 @@ class ManimConfig(MutableMapping):
|
|||
)
|
||||
if self.format == "webm":
|
||||
logging.getLogger("manim").warning(
|
||||
"Output format set as webm, this can be slower than other formats"
|
||||
"Output format set as webm, this can be slower than other formats",
|
||||
)
|
||||
|
||||
ffmpeg_loglevel = property(
|
||||
lambda self: self._d["ffmpeg_loglevel"],
|
||||
lambda self, val: self._set_from_list(
|
||||
"ffmpeg_loglevel", val, ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
"ffmpeg_loglevel",
|
||||
val,
|
||||
["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
),
|
||||
doc="Verbosity level of ffmpeg (no flag).",
|
||||
)
|
||||
|
|
@ -1052,7 +1054,9 @@ class ManimConfig(MutableMapping):
|
|||
movie_file_extension = property(
|
||||
lambda self: self._d["movie_file_extension"],
|
||||
lambda self, val: self._set_from_list(
|
||||
"movie_file_extension", val, [".mp4", ".mov", ".webm"]
|
||||
"movie_file_extension",
|
||||
val,
|
||||
[".mp4", ".mov", ".webm"],
|
||||
),
|
||||
doc="Either .mp4, .webm or .mov.",
|
||||
)
|
||||
|
|
@ -1125,7 +1129,7 @@ class ManimConfig(MutableMapping):
|
|||
"It is unclear what it means to set dry_run to "
|
||||
"False. Instead, try setting each option "
|
||||
"individually. (write_to_movie, write_all, "
|
||||
"save_last_frame, save_pngs, or save_as_gif)"
|
||||
"save_last_frame, save_pngs, or save_as_gif)",
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
@ -1401,7 +1405,7 @@ class ManimConfig(MutableMapping):
|
|||
raise KeyError(
|
||||
"must pass one of "
|
||||
"{media,video,images,text,tex,log}_dir "
|
||||
"or {input,output}_file"
|
||||
"or {input,output}_file",
|
||||
)
|
||||
|
||||
dirs.remove(key) # a path cannot contain itself
|
||||
|
|
@ -1418,7 +1422,7 @@ class ManimConfig(MutableMapping):
|
|||
raise KeyError(
|
||||
f"{key} {self._d[key]} requires the following "
|
||||
+ "keyword arguments: "
|
||||
+ " ".join(exc.args)
|
||||
+ " ".join(exc.args),
|
||||
) from exc
|
||||
return Path(path) if path else None
|
||||
|
||||
|
|
@ -1520,7 +1524,7 @@ class ManimConfig(MutableMapping):
|
|||
if val:
|
||||
if not os.access(val, os.R_OK):
|
||||
logging.getLogger("manim").warning(
|
||||
f"Custom TeX template {val} not found or not readable."
|
||||
f"Custom TeX template {val} not found or not readable.",
|
||||
)
|
||||
else:
|
||||
self._d["tex_template_file"] = Path(val)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class Animation:
|
|||
logger.debug(
|
||||
f"The {cls.__name__} animation has been is overridden for "
|
||||
f"{type(mobject).__name__} mobjects. use_override = False can "
|
||||
f" be used as keyword argument to prevent animation overriding."
|
||||
f" be used as keyword argument to prevent animation overriding.",
|
||||
)
|
||||
return anim
|
||||
return super().__new__(cls)
|
||||
|
|
@ -141,7 +141,7 @@ class Animation:
|
|||
(
|
||||
"CONFIG has been removed from ManimCommunity.",
|
||||
"Please use keyword arguments instead.",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
def _typecheck_input(self, mobject: Union[Mobject, None]) -> None:
|
||||
|
|
@ -418,7 +418,7 @@ class Animation:
|
|||
|
||||
|
||||
def prepare_animation(
|
||||
anim: Union["Animation", "mobject._AnimationBuilder"]
|
||||
anim: Union["Animation", "mobject._AnimationBuilder"],
|
||||
) -> "Animation":
|
||||
r"""Returns either an unchanged animation, or the animation built
|
||||
from a passed animation factory.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class AnimationGroup(Animation):
|
|||
self.group = group
|
||||
if self.group is None:
|
||||
mobjects = remove_list_redundancies(
|
||||
[anim.mobject for anim in self.animations]
|
||||
[anim.mobject for anim in self.animations],
|
||||
)
|
||||
if config["renderer"] == "opengl":
|
||||
self.group = OpenGLGroup(*mobjects)
|
||||
|
|
|
|||
|
|
@ -121,7 +121,10 @@ class ShowPartial(Animation):
|
|||
super().__init__(mobject, **kwargs)
|
||||
|
||||
def interpolate_submobject(
|
||||
self, submobject: Mobject, starting_submobject: Mobject, alpha: float
|
||||
self,
|
||||
submobject: Mobject,
|
||||
starting_submobject: Mobject,
|
||||
alpha: float,
|
||||
) -> None:
|
||||
submobject.pointwise_become_partial(
|
||||
starting_submobject, *self._get_bounds(alpha)
|
||||
|
|
@ -254,7 +257,11 @@ class DrawBorderThenFill(Animation):
|
|||
return [*super().get_all_mobjects(), self.outline]
|
||||
|
||||
def interpolate_submobject(
|
||||
self, submobject: Mobject, starting_submobject: Mobject, outline, alpha: float
|
||||
self,
|
||||
submobject: Mobject,
|
||||
starting_submobject: Mobject,
|
||||
outline,
|
||||
alpha: float,
|
||||
) -> None: # Fixme: not matching the parent class? What is outline doing here?
|
||||
index: int
|
||||
subalpha: int
|
||||
|
|
@ -294,7 +301,9 @@ class Write(DrawBorderThenFill):
|
|||
run_time: Optional[float] = kwargs.pop("run_time", None)
|
||||
lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
|
||||
run_time, lag_ratio = self._set_default_config_from_length(
|
||||
vmobject, run_time, lag_ratio
|
||||
vmobject,
|
||||
run_time,
|
||||
lag_ratio,
|
||||
)
|
||||
self.reverse = reverse
|
||||
super().__init__(
|
||||
|
|
@ -374,7 +383,9 @@ class Unwrite(Write):
|
|||
run_time: Optional[float] = kwargs.pop("run_time", None)
|
||||
lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
|
||||
run_time, lag_ratio = self._set_default_config_from_length(
|
||||
vmobject, run_time, lag_ratio
|
||||
vmobject,
|
||||
run_time,
|
||||
lag_ratio,
|
||||
)
|
||||
super().__init__(
|
||||
vmobject,
|
||||
|
|
|
|||
|
|
@ -464,7 +464,10 @@ class ApplyWave(Homotopy):
|
|||
return (1 - 2 * wave_func(t * ripples)) * (1 - 2 * ((phase) % 2))
|
||||
|
||||
def homotopy(
|
||||
x: float, y: float, z: float, t: float
|
||||
x: float,
|
||||
y: float,
|
||||
z: float,
|
||||
t: float,
|
||||
) -> Tuple[float, float, float]:
|
||||
upper = interpolate(0, 1 + time_width, t)
|
||||
lower = upper - time_width
|
||||
|
|
@ -536,7 +539,10 @@ class Wiggle(Animation):
|
|||
return self.mobject.get_center()
|
||||
|
||||
def interpolate_submobject(
|
||||
self, submobject: "Mobject", starting_submobject: "Mobject", alpha: float
|
||||
self,
|
||||
submobject: "Mobject",
|
||||
starting_submobject: "Mobject",
|
||||
alpha: float,
|
||||
) -> None:
|
||||
submobject.points[:, :] = starting_submobject.points
|
||||
submobject.scale(
|
||||
|
|
@ -606,11 +612,15 @@ class Circumscribe(Succession):
|
|||
):
|
||||
if shape is Rectangle:
|
||||
frame = SurroundingRectangle(
|
||||
mobject, color, buff, stroke_width=stroke_width
|
||||
mobject,
|
||||
color,
|
||||
buff,
|
||||
stroke_width=stroke_width,
|
||||
)
|
||||
elif shape is Circle:
|
||||
frame = Circle(color=color, stroke_width=stroke_width).surround(
|
||||
mobject, buffer_factor=1
|
||||
mobject,
|
||||
buffer_factor=1,
|
||||
)
|
||||
radius = frame.width / 2
|
||||
frame.scale((radius + buff) / radius)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ class Homotopy(Animation):
|
|||
return lambda p: self.homotopy(*p, t)
|
||||
|
||||
def interpolate_submobject(
|
||||
self, submobject: "Mobject", starting_submobject: "Mobject", alpha: float
|
||||
self,
|
||||
submobject: "Mobject",
|
||||
starting_submobject: "Mobject",
|
||||
alpha: float,
|
||||
) -> None:
|
||||
submobject.points = starting_submobject.points
|
||||
submobject.apply_function(
|
||||
|
|
@ -52,7 +55,10 @@ class Homotopy(Animation):
|
|||
|
||||
class SmoothedVectorizedHomotopy(Homotopy):
|
||||
def interpolate_submobject(
|
||||
self, submobject: "Mobject", starting_submobject: "Mobject", alpha: float
|
||||
self,
|
||||
submobject: "Mobject",
|
||||
starting_submobject: "Mobject",
|
||||
alpha: float,
|
||||
) -> None:
|
||||
Homotopy.interpolate_submobject(self, submobject, starting_submobject, alpha)
|
||||
submobject.make_smooth()
|
||||
|
|
@ -67,7 +73,10 @@ class ComplexHomotopy(Homotopy):
|
|||
"""
|
||||
|
||||
def homotopy(
|
||||
x: float, y: float, z: float, t: float
|
||||
x: float,
|
||||
y: float,
|
||||
z: float,
|
||||
t: float,
|
||||
) -> Tuple[float, float, float]:
|
||||
c = complex_homotopy(complex(x, y), t)
|
||||
return (c.real, c.imag, z)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ class Transform(Animation):
|
|||
def path_func(
|
||||
self,
|
||||
) -> Callable[
|
||||
[Iterable[np.ndarray], Iterable[np.ndarray], float], Iterable[np.ndarray]
|
||||
[Iterable[np.ndarray], Iterable[np.ndarray], float],
|
||||
Iterable[np.ndarray],
|
||||
]:
|
||||
return self._path_func
|
||||
|
||||
|
|
@ -91,7 +92,8 @@ class Transform(Animation):
|
|||
def path_func(
|
||||
self,
|
||||
path_func: Callable[
|
||||
[Iterable[np.ndarray], Iterable[np.ndarray], float], Iterable[np.ndarray]
|
||||
[Iterable[np.ndarray], Iterable[np.ndarray], float],
|
||||
Iterable[np.ndarray],
|
||||
],
|
||||
) -> None:
|
||||
if path_func is not None:
|
||||
|
|
@ -245,7 +247,7 @@ class MoveToTarget(Transform):
|
|||
def check_validity_of_input(self, mobject: Mobject) -> None:
|
||||
if not hasattr(mobject, "target"):
|
||||
raise ValueError(
|
||||
"MoveToTarget called on mobject" "without attribute 'target'"
|
||||
"MoveToTarget called on mobject" "without attribute 'target'",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -276,7 +278,7 @@ class ApplyMethod(Transform):
|
|||
if not inspect.ismethod(method):
|
||||
raise ValueError(
|
||||
"Whoops, looks like you accidentally invoked "
|
||||
"the method you want to animate"
|
||||
"the method you want to animate",
|
||||
)
|
||||
assert isinstance(method.__self__, (Mobject, OpenGLMobject))
|
||||
|
||||
|
|
@ -364,7 +366,7 @@ class ApplyFunction(Transform):
|
|||
target = self.function(self.mobject.copy())
|
||||
if not isinstance(target, (Mobject, OpenGLMobject)):
|
||||
raise TypeError(
|
||||
"Functions passed to ApplyFunction must return object of type Mobject"
|
||||
"Functions passed to ApplyFunction must return object of type Mobject",
|
||||
)
|
||||
return target
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class TransformMatchingAbstractBase(AnimationGroup):
|
|||
target_map.pop(key2, None)
|
||||
if len(key_mapped_source) > 0:
|
||||
anims.append(
|
||||
FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs)
|
||||
FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs),
|
||||
)
|
||||
|
||||
fade_source = group_type()
|
||||
|
|
@ -130,7 +130,7 @@ class TransformMatchingAbstractBase(AnimationGroup):
|
|||
else:
|
||||
anims.append(FadeOut(fade_source, target_position=fade_target, **kwargs))
|
||||
anims.append(
|
||||
FadeIn(fade_target.copy(), target_position=fade_target, **kwargs)
|
||||
FadeIn(fade_target.copy(), target_position=fade_target, **kwargs),
|
||||
)
|
||||
|
||||
super().__init__(*anims)
|
||||
|
|
|
|||
|
|
@ -249,10 +249,12 @@ class Camera:
|
|||
self.background = self.background.astype(self.pixel_array_dtype)
|
||||
else:
|
||||
background_rgba = color_to_int_rgba(
|
||||
self.background_color, self.background_opacity
|
||||
self.background_color,
|
||||
self.background_opacity,
|
||||
)
|
||||
self.background = np.zeros(
|
||||
(height, width, self.n_channels), dtype=self.pixel_array_dtype
|
||||
(height, width, self.n_channels),
|
||||
dtype=self.pixel_array_dtype,
|
||||
)
|
||||
self.background[:, :] = background_rgba
|
||||
|
||||
|
|
@ -345,6 +347,7 @@ class Camera:
|
|||
coords_to_colors_func : function
|
||||
The function whose input is an (x,y) pair of coordinates and
|
||||
whose return values must be the colors for that point
|
||||
|
||||
Returns
|
||||
-------
|
||||
np.array
|
||||
|
|
@ -396,7 +399,10 @@ class Camera:
|
|||
####
|
||||
|
||||
def get_mobjects_to_display(
|
||||
self, mobjects, include_submobjects=True, excluded_mobjects=None
|
||||
self,
|
||||
mobjects,
|
||||
include_submobjects=True,
|
||||
excluded_mobjects=None,
|
||||
):
|
||||
"""Used to get the list of mobjects to display
|
||||
with the camera.
|
||||
|
|
@ -417,11 +423,14 @@ class Camera:
|
|||
"""
|
||||
if include_submobjects:
|
||||
mobjects = extract_mobject_family_members(
|
||||
mobjects, use_z_index=self.use_z_index, only_those_with_points=True
|
||||
mobjects,
|
||||
use_z_index=self.use_z_index,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if excluded_mobjects:
|
||||
all_excluded = extract_mobject_family_members(
|
||||
excluded_mobjects, use_z_index=self.use_z_index
|
||||
excluded_mobjects,
|
||||
use_z_index=self.use_z_index,
|
||||
)
|
||||
mobjects = list_difference_update(mobjects, all_excluded)
|
||||
return mobjects
|
||||
|
|
@ -546,7 +555,10 @@ class Camera:
|
|||
fh = self.frame_height
|
||||
fc = self.frame_center
|
||||
surface = cairo.ImageSurface.create_for_data(
|
||||
pixel_array, cairo.FORMAT_ARGB32, pw, ph
|
||||
pixel_array,
|
||||
cairo.FORMAT_ARGB32,
|
||||
pw,
|
||||
ph,
|
||||
)
|
||||
ctx = cairo.Context(surface)
|
||||
ctx.scale(pw, ph)
|
||||
|
|
@ -558,7 +570,7 @@ class Camera:
|
|||
-fdiv(ph, fh),
|
||||
(pw / 2) - fc[0] * fdiv(pw, fw),
|
||||
(ph / 2) + fc[1] * fdiv(ph, fh),
|
||||
)
|
||||
),
|
||||
)
|
||||
self.cache_cairo_context(pixel_array, ctx)
|
||||
return ctx
|
||||
|
|
@ -581,7 +593,8 @@ class Camera:
|
|||
self.display_multiple_background_colored_vmobjects(batch, pixel_array)
|
||||
else:
|
||||
self.display_multiple_non_background_colored_vmobjects(
|
||||
batch, pixel_array
|
||||
batch,
|
||||
pixel_array,
|
||||
)
|
||||
|
||||
def display_multiple_non_background_colored_vmobjects(self, vmobjects, pixel_array):
|
||||
|
|
@ -648,7 +661,7 @@ class Camera:
|
|||
ctx.new_sub_path()
|
||||
start = subpath[0]
|
||||
ctx.move_to(*start[:2])
|
||||
for p0, p1, p2, p3 in quads:
|
||||
for _p0, p1, p2, p3 in quads:
|
||||
ctx.curve_to(*p1[:2], *p2[:2], *p3[:2])
|
||||
if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]):
|
||||
ctx.close_path()
|
||||
|
|
@ -727,13 +740,15 @@ class Camera:
|
|||
if width == 0:
|
||||
return self
|
||||
self.set_cairo_context_color(
|
||||
ctx, self.get_stroke_rgbas(vmobject, background=background), vmobject
|
||||
ctx,
|
||||
self.get_stroke_rgbas(vmobject, background=background),
|
||||
vmobject,
|
||||
)
|
||||
ctx.set_line_width(
|
||||
width
|
||||
* self.cairo_line_width_multiple
|
||||
# This ensures lines have constant width as you zoom in on them.
|
||||
* (self.frame_width / self.frame_width)
|
||||
* (self.frame_width / self.frame_width),
|
||||
)
|
||||
ctx.stroke_preserve()
|
||||
return self
|
||||
|
|
@ -847,6 +862,7 @@ class Camera:
|
|||
The thickness of each point of the PMobject
|
||||
pixel_array : np.array
|
||||
The pixel array to modify.
|
||||
|
||||
"""
|
||||
if len(points) == 0:
|
||||
return
|
||||
|
|
@ -910,7 +926,8 @@ class Camera:
|
|||
pixel_width = max(int(pdist([ul_coords, ur_coords])), 1)
|
||||
pixel_height = max(int(pdist([ul_coords, dl_coords])), 1)
|
||||
sub_image = sub_image.resize(
|
||||
(pixel_width, pixel_height), resample=image_mobject.resampling_algorithm
|
||||
(pixel_width, pixel_height),
|
||||
resample=image_mobject.resampling_algorithm,
|
||||
)
|
||||
|
||||
# Rotate
|
||||
|
|
@ -918,14 +935,17 @@ class Camera:
|
|||
adjusted_angle = -int(360 * angle / TAU)
|
||||
if adjusted_angle != 0:
|
||||
sub_image = sub_image.rotate(
|
||||
adjusted_angle, resample=image_mobject.resampling_algorithm, expand=1
|
||||
adjusted_angle,
|
||||
resample=image_mobject.resampling_algorithm,
|
||||
expand=1,
|
||||
)
|
||||
|
||||
# TODO, there is no accounting for a shear...
|
||||
|
||||
# Paste into an image as large as the camera's pixel array
|
||||
full_image = Image.fromarray(
|
||||
np.zeros((self.pixel_height, self.pixel_width)), mode="RGBA"
|
||||
np.zeros((self.pixel_height, self.pixel_width)),
|
||||
mode="RGBA",
|
||||
)
|
||||
new_ul_coords = center_coords - np.array(sub_image.size) / 2
|
||||
new_ul_coords = new_ul_coords.astype(int)
|
||||
|
|
@ -964,7 +984,8 @@ class Camera:
|
|||
The Image to overlay.
|
||||
"""
|
||||
pixel_array[:, :] = np.array(
|
||||
Image.alpha_composite(self.get_image(pixel_array), image), dtype="uint8"
|
||||
Image.alpha_composite(self.get_image(pixel_array), image),
|
||||
dtype="uint8",
|
||||
)
|
||||
|
||||
def adjust_out_of_range_points(self, points):
|
||||
|
|
@ -988,14 +1009,18 @@ class Camera:
|
|||
violators = points[violator_indices, :]
|
||||
violator_norms = norms[violator_indices]
|
||||
reshaped_norms = np.repeat(
|
||||
violator_norms.reshape((len(violator_norms), 1)), points.shape[1], 1
|
||||
violator_norms.reshape((len(violator_norms), 1)),
|
||||
points.shape[1],
|
||||
1,
|
||||
)
|
||||
rescaled = self.max_allowable_norm * violators / reshaped_norms
|
||||
points[violator_indices] = rescaled
|
||||
return points
|
||||
|
||||
def transform_points_pre_display(
|
||||
self, mobject, points
|
||||
self,
|
||||
mobject,
|
||||
points,
|
||||
): # TODO: Write more detailed docstrings for this method.
|
||||
# NOTE: There seems to be an unused argument `mobject`.
|
||||
|
||||
|
|
@ -1008,7 +1033,9 @@ class Camera:
|
|||
return points
|
||||
|
||||
def points_to_pixel_coords(
|
||||
self, mobject, points
|
||||
self,
|
||||
mobject,
|
||||
points,
|
||||
): # TODO: Write more detailed docstrings for this method.
|
||||
points = self.transform_points_pre_display(mobject, points)
|
||||
shifted_points = points - self.frame_center
|
||||
|
|
@ -1127,7 +1154,8 @@ class Camera:
|
|||
::-1
|
||||
].transpose(1, 2, 0)
|
||||
uncentered_space_coords = fdiv(
|
||||
uncentered_pixel_coords * full_space_dims, full_pixel_dims
|
||||
uncentered_pixel_coords * full_space_dims,
|
||||
full_pixel_dims,
|
||||
)
|
||||
# Could structure above line's computation slightly differently, but figured (without much
|
||||
# thought) multiplying by frame_shape first, THEN dividing by pixel_shape, is probably
|
||||
|
|
@ -1162,7 +1190,11 @@ class BackgroundColoredVMobjectDisplayer:
|
|||
self.pixel_array[:, :] = 0
|
||||
|
||||
def resize_background_array(
|
||||
self, background_array, new_width, new_height, mode="RGBA"
|
||||
self,
|
||||
background_array,
|
||||
new_width,
|
||||
new_height,
|
||||
mode="RGBA",
|
||||
):
|
||||
"""Resizes the pixel array representing the background.
|
||||
|
||||
|
|
@ -1254,7 +1286,8 @@ class BackgroundColoredVMobjectDisplayer:
|
|||
background_array = self.get_background_array(image)
|
||||
pixel_array = self.pixel_array
|
||||
self.camera.display_multiple_non_background_colored_vmobjects(
|
||||
batch, pixel_array
|
||||
batch,
|
||||
pixel_array,
|
||||
)
|
||||
new_array = np.array(
|
||||
(background_array * pixel_array.astype("float") / 255),
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ class MappingCamera(Camera):
|
|||
|
||||
def points_to_pixel_coords(self, points):
|
||||
return Camera.points_to_pixel_coords(
|
||||
self, np.apply_along_axis(self.mapping_func, 1, points)
|
||||
self,
|
||||
np.apply_along_axis(self.mapping_func, 1, points),
|
||||
)
|
||||
|
||||
def capture_mobjects(self, mobjects, **kwargs):
|
||||
|
|
@ -74,7 +75,7 @@ class OldMultiCamera(Camera):
|
|||
+ camera_with_start_positions[0].pixel_width,
|
||||
"end_y": camera_with_start_positions[1][0]
|
||||
+ camera_with_start_positions[0].pixel_height,
|
||||
}
|
||||
},
|
||||
)
|
||||
for camera_with_start_positions in cameras_with_start_positions
|
||||
]
|
||||
|
|
|
|||
|
|
@ -121,7 +121,9 @@ class ThreeDCamera(Camera):
|
|||
return rgbas
|
||||
|
||||
def get_stroke_rgbas(
|
||||
self, vmobject, background=False
|
||||
self,
|
||||
vmobject,
|
||||
background=False,
|
||||
): # NOTE : DocStrings From parent
|
||||
return self.modified_rgbas(vmobject, vmobject.get_stroke_rgbas(background))
|
||||
|
||||
|
|
@ -333,7 +335,9 @@ class ThreeDCamera(Camera):
|
|||
return self.project_points(point.reshape((1, 3)))[0, :]
|
||||
|
||||
def transform_points_pre_display(
|
||||
self, mobject, points
|
||||
self,
|
||||
mobject,
|
||||
points,
|
||||
): # TODO: Write Docstrings for this Method.
|
||||
points = super().transform_points_pre_display(mobject, points)
|
||||
fixed_orientation = mobject in self.fixed_orientation_mobjects
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class WebGLCamera(Camera):
|
|||
"style": vmobject.get_style(simple=True),
|
||||
"id": id(vmobject),
|
||||
"needs_redraw": needs_redraw,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
def reset(self):
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ def cfg(ctx):
|
|||
def write(level: str = None, openfile: bool = False) -> None:
|
||||
config_paths = config_file_paths()
|
||||
console.print(
|
||||
"[yellow bold]Manim Configuration File Writer[/yellow bold]", justify="center"
|
||||
"[yellow bold]Manim Configuration File Writer[/yellow bold]",
|
||||
justify="center",
|
||||
)
|
||||
|
||||
USER_CONFIG_MSG = f"""A configuration file at [yellow]{config_paths[1]}[/yellow] has been created with your required changes.
|
||||
|
|
@ -182,17 +183,21 @@ To save your config please save that file and place it in your current working d
|
|||
raise Exception(
|
||||
"""Not enough values in input.
|
||||
You may have added a new entry to default.cfg, in which case you will have to
|
||||
modify write_cfg_subcmd_input to account for it."""
|
||||
modify write_cfg_subcmd_input to account for it.""",
|
||||
)
|
||||
if temp:
|
||||
while temp and not _is_expected_datatype(
|
||||
temp, default[key], bool(style)
|
||||
temp,
|
||||
default[key],
|
||||
bool(style),
|
||||
):
|
||||
console.print(
|
||||
f"[red bold]Invalid {desc}. Try again.[/red bold]"
|
||||
f"[red bold]Invalid {desc}. Try again.[/red bold]",
|
||||
)
|
||||
console.print(
|
||||
f"Enter the {desc} for {key}:", style=style, end=""
|
||||
f"Enter the {desc} for {key}:",
|
||||
style=style,
|
||||
end="",
|
||||
)
|
||||
temp = input()
|
||||
else:
|
||||
|
|
@ -259,7 +264,7 @@ Are you sure you want to continue? (y/n)""",
|
|||
style="red bold",
|
||||
end="",
|
||||
)
|
||||
proceed = True if input().lower() == "y" else False
|
||||
proceed = input().lower() == "y"
|
||||
else:
|
||||
proceed = True
|
||||
if proceed:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ def select_resolution():
|
|||
resolution_options = []
|
||||
for quality in QUALITIES.items():
|
||||
resolution_options.append(
|
||||
(quality[1]["pixel_height"], quality[1]["pixel_width"])
|
||||
(quality[1]["pixel_height"], quality[1]["pixel_width"]),
|
||||
)
|
||||
resolution_options.pop()
|
||||
choice = click.prompt(
|
||||
|
|
@ -100,7 +100,7 @@ def project(default_settings, **args):
|
|||
|
||||
if project_name.is_dir():
|
||||
console.print(
|
||||
f"\nFolder [red]{project_name}[/red] exists. Please type another name\n"
|
||||
f"\nFolder [red]{project_name}[/red] exists. Please type another name\n",
|
||||
)
|
||||
else:
|
||||
project_name.mkdir()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ from ...plugins.plugins_flags import list_plugins
|
|||
help="Manages Manim plugins.",
|
||||
)
|
||||
@click.option(
|
||||
"-l", "--list", "list_available", is_flag=True, help="List available plugins."
|
||||
"-l",
|
||||
"--list",
|
||||
"list_available",
|
||||
is_flag=True,
|
||||
help="List available plugins.",
|
||||
)
|
||||
def plugins(list_available):
|
||||
if list_available:
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@ def render(
|
|||
|
||||
if args["use_opengl_renderer"]:
|
||||
logger.warning(
|
||||
"--use_opengl_renderer is deprecated, please use --renderer=opengl instead!"
|
||||
"--use_opengl_renderer is deprecated, please use --renderer=opengl instead!",
|
||||
)
|
||||
args["renderer"] = "opengl"
|
||||
|
||||
if args["use_webgl_renderer"]:
|
||||
logger.warning(
|
||||
"--use_webgl_renderer is deprecated, please use --renderer=webgl instead!"
|
||||
"--use_webgl_renderer is deprecated, please use --renderer=webgl instead!",
|
||||
)
|
||||
args["renderer"] = "webgl"
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ def render(
|
|||
|
||||
if args["show_in_file_browser"]:
|
||||
logger.warning(
|
||||
"The short form of show_in_file_browser is deprecated and will be moved to support --format."
|
||||
"The short form of show_in_file_browser is deprecated and will be moved to support --format.",
|
||||
)
|
||||
|
||||
class ClickArgs:
|
||||
|
|
@ -124,7 +124,7 @@ def render(
|
|||
except ModuleNotFoundError:
|
||||
console.print(
|
||||
"Dependencies for the WebGL render are missing. Run "
|
||||
"pip install manim[webgl_renderer] to install them."
|
||||
"pip install manim[webgl_renderer] to install them.",
|
||||
)
|
||||
error_console.print_exception()
|
||||
sys.exit(1)
|
||||
|
|
@ -149,10 +149,10 @@ def render(
|
|||
stable = req_info.json()["info"]["version"]
|
||||
if stable != __version__:
|
||||
console.print(
|
||||
f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available."
|
||||
f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.",
|
||||
)
|
||||
console.print(
|
||||
"You should consider upgrading via [yellow]pip install -U manim[/yellow]"
|
||||
"You should consider upgrading via [yellow]pip install -U manim[/yellow]",
|
||||
)
|
||||
except requests.exceptions.HTTPError:
|
||||
logger.debug(f"HTTP Error: {warn_prompt}")
|
||||
|
|
|
|||
|
|
@ -30,7 +30,10 @@ output_options = option_group(
|
|||
help="Path to store rendered videos and latex.",
|
||||
),
|
||||
option(
|
||||
"--log_dir", type=click.Path(), help="Path to store render logs.", default=None
|
||||
"--log_dir",
|
||||
type=click.Path(),
|
||||
help="Path to store render logs.",
|
||||
default=None,
|
||||
),
|
||||
option(
|
||||
"--log_to_file",
|
||||
|
|
|
|||
32
manim/grpc/gen/frameserver_pb2.py
generated
32
manim/grpc/gen/frameserver_pb2.py
generated
|
|
@ -1417,7 +1417,7 @@ FetchSceneDataResponse = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _FETCHSCENEDATARESPONSE,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.FetchSceneDataResponse)
|
||||
},
|
||||
)
|
||||
|
|
@ -1428,7 +1428,7 @@ Scene = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _SCENE,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Scene)
|
||||
},
|
||||
)
|
||||
|
|
@ -1443,7 +1443,7 @@ Animation = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _ANIMATION_ATTRIBUTETWEENDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Animation.AttributeTweenData)
|
||||
},
|
||||
),
|
||||
|
|
@ -1452,12 +1452,12 @@ Animation = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _ANIMATION_MOBJECTTWEENDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Animation.MobjectTweenData)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR": _ANIMATION,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Animation)
|
||||
},
|
||||
)
|
||||
|
|
@ -1470,7 +1470,7 @@ Updater = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _UPDATER,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Updater)
|
||||
},
|
||||
)
|
||||
|
|
@ -1481,7 +1481,7 @@ FrameRequest = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _FRAMEREQUEST,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.FrameRequest)
|
||||
},
|
||||
)
|
||||
|
|
@ -1492,7 +1492,7 @@ Style = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _STYLE,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Style)
|
||||
},
|
||||
)
|
||||
|
|
@ -1503,7 +1503,7 @@ Point = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _POINT,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.Point)
|
||||
},
|
||||
)
|
||||
|
|
@ -1514,7 +1514,7 @@ MobjectData = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _MOBJECTDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.MobjectData)
|
||||
},
|
||||
)
|
||||
|
|
@ -1525,7 +1525,7 @@ VMobjectData = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _VMOBJECTDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.VMobjectData)
|
||||
},
|
||||
)
|
||||
|
|
@ -1536,7 +1536,7 @@ ImageMobjectData = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _IMAGEMOBJECTDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.ImageMobjectData)
|
||||
},
|
||||
)
|
||||
|
|
@ -1547,7 +1547,7 @@ FrameData = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _FRAMEDATA,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.FrameData)
|
||||
},
|
||||
)
|
||||
|
|
@ -1558,7 +1558,7 @@ FrameResponse = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _FRAMERESPONSE,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.FrameResponse)
|
||||
},
|
||||
)
|
||||
|
|
@ -1569,7 +1569,7 @@ EmptyRequest = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYREQUEST,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.EmptyRequest)
|
||||
},
|
||||
)
|
||||
|
|
@ -1580,7 +1580,7 @@ EmptyResponse = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYRESPONSE,
|
||||
"__module__": "frameserver_pb2"
|
||||
"__module__": "frameserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:frameserver.EmptyResponse)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
3
manim/grpc/gen/frameserver_pb2_grpc.py
generated
3
manim/grpc/gen/frameserver_pb2_grpc.py
generated
|
|
@ -71,7 +71,8 @@ def add_FrameServerServicer_to_server(servicer, server):
|
|||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"frameserver.FrameServer", rpc_method_handlers
|
||||
"frameserver.FrameServer",
|
||||
rpc_method_handlers,
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
|
|
|||
10
manim/grpc/gen/renderserver_pb2.py
generated
10
manim/grpc/gen/renderserver_pb2.py
generated
|
|
@ -294,7 +294,7 @@ UpdateSceneDataRequest = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _UPDATESCENEDATAREQUEST,
|
||||
"__module__": "renderserver_pb2"
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.UpdateSceneDataRequest)
|
||||
},
|
||||
)
|
||||
|
|
@ -305,7 +305,7 @@ Scene = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _SCENE,
|
||||
"__module__": "renderserver_pb2"
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.Scene)
|
||||
},
|
||||
)
|
||||
|
|
@ -316,7 +316,7 @@ Animation = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _ANIMATION,
|
||||
"__module__": "renderserver_pb2"
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.Animation)
|
||||
},
|
||||
)
|
||||
|
|
@ -327,7 +327,7 @@ EmptyRequest = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYREQUEST,
|
||||
"__module__": "renderserver_pb2"
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.EmptyRequest)
|
||||
},
|
||||
)
|
||||
|
|
@ -338,7 +338,7 @@ EmptyResponse = _reflection.GeneratedProtocolMessageType(
|
|||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYRESPONSE,
|
||||
"__module__": "renderserver_pb2"
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.EmptyResponse)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
3
manim/grpc/gen/renderserver_pb2_grpc.py
generated
3
manim/grpc/gen/renderserver_pb2_grpc.py
generated
|
|
@ -39,7 +39,8 @@ def add_RenderServerServicer_to_server(servicer, server):
|
|||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"renderserver.RenderServer", rpc_method_handlers
|
||||
"renderserver.RenderServer",
|
||||
rpc_method_handlers,
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
request.first_request or self.previous_scene != requested_scene
|
||||
):
|
||||
previous_mobjects = extract_mobject_family_members(
|
||||
self.previous_scene.mobjects, only_those_with_points=True
|
||||
self.previous_scene.mobjects,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
# Remove everything from the previous scene.
|
||||
ids_to_remove = [
|
||||
|
|
@ -95,7 +96,8 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
mobjects_to_add = [
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
requested_scene.mobjects, only_those_with_points=True
|
||||
requested_scene.mobjects,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
]
|
||||
|
|
@ -111,7 +113,8 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
flickered_mobject_ids = [
|
||||
mob.original_id
|
||||
for mob in extract_mobject_family_members(
|
||||
animation.mobject, only_those_with_points=True
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
]
|
||||
else:
|
||||
|
|
@ -119,14 +122,15 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
# Add offset vector to submobjects.
|
||||
root_mobject_center = animation.mobject.get_center()
|
||||
for updated_mobject in extract_mobject_family_members(
|
||||
animation.mobject, only_those_with_points=True
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
):
|
||||
mobject_tween_data_list.append(
|
||||
frameserver_pb2.Animation.MobjectTweenData(
|
||||
id=updated_mobject.original_id,
|
||||
root_mobject_offset=updated_mobject.get_center()
|
||||
- root_mobject_center,
|
||||
)
|
||||
),
|
||||
)
|
||||
animation_proto = frameserver_pb2.Animation(
|
||||
name=animation.__class__.__name__,
|
||||
|
|
@ -152,10 +156,11 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
flickered_mobject_ids=[
|
||||
mob.original_id
|
||||
for mob in extract_mobject_family_members(
|
||||
updated_mobject, only_those_with_points=True
|
||||
updated_mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
break
|
||||
else:
|
||||
|
|
@ -172,10 +177,11 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
[
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
animation.mobject, only_those_with_points=True
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
]
|
||||
],
|
||||
)
|
||||
for (
|
||||
updated_mobject,
|
||||
|
|
@ -188,15 +194,18 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
[
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
updated_mobject, only_those_with_points=True
|
||||
updated_mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
resp = frameserver_pb2.FrameResponse(
|
||||
frame_data=frameserver_pb2.FrameData(
|
||||
remove=ids_to_remove, add=mobjects_to_add, update=update_data
|
||||
remove=ids_to_remove,
|
||||
add=mobjects_to_add,
|
||||
update=update_data,
|
||||
),
|
||||
scene_finished=scene_finished,
|
||||
animations=animations,
|
||||
|
|
@ -250,7 +259,8 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
self.exception = None
|
||||
try:
|
||||
self.scene_class = scene_classes_from_file(
|
||||
self.input_file_path, require_single_scene=True
|
||||
self.input_file_path,
|
||||
require_single_scene=True,
|
||||
)
|
||||
self.generate_keyframe_data()
|
||||
except Exception as e:
|
||||
|
|
@ -288,10 +298,13 @@ class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
|||
request.scene.background_color = "#000000"
|
||||
else:
|
||||
lines = traceback.format_exception(
|
||||
None, self.exception, self.exception.__traceback__
|
||||
None,
|
||||
self.exception,
|
||||
self.exception.__traceback__,
|
||||
)
|
||||
request = renderserver_pb2.UpdateSceneDataRequest(
|
||||
has_exception=True, exception="\n".join(lines)
|
||||
has_exception=True,
|
||||
exception="\n".join(lines),
|
||||
)
|
||||
stub.UpdateSceneData(request)
|
||||
|
||||
|
|
@ -309,7 +322,7 @@ def generate_attribute_tween_data(animation):
|
|||
attribute="position",
|
||||
start_data=animation.starting_mobject.get_center(),
|
||||
end_data=animation.target_mobject.get_center(),
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
|
@ -372,7 +385,7 @@ def serialize_mobject(mobject):
|
|||
mob_proto.image_mobject_data.path = mobject.path[len(assets_dir_path) + 1 :]
|
||||
else:
|
||||
logger.info(
|
||||
f"Expected path {mobject.path} to be under the assets dir ({assets_dir_path})"
|
||||
f"Expected path {mobject.path} to be under the assets dir ({assets_dir_path})",
|
||||
)
|
||||
mob_proto.image_mobject_data.height = mobject.height
|
||||
mob_proto.image_mobject_data.width = mobject.width
|
||||
|
|
@ -386,7 +399,8 @@ def serialize_mobject(mobject):
|
|||
def get(input_file_path):
|
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
|
||||
frameserver_pb2_grpc.add_FrameServerServicer_to_server(
|
||||
FrameServer(server, input_file_path), server
|
||||
FrameServer(server, input_file_path),
|
||||
server,
|
||||
)
|
||||
server.add_insecure_port("localhost:50051")
|
||||
return server
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ service FrameServer {
|
|||
|
||||
// Returns a list of the names and durations of all animations in the scene.
|
||||
rpc FetchSceneData (EmptyRequest) returns (FetchSceneDataResponse);
|
||||
|
||||
|
||||
// Returns when the manim script changes
|
||||
rpc ScriptUpdated (EmptyRequest) returns (EmptyResponse);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ def configure_pygui(renderer, widgets, update=True):
|
|||
dpg.add_separator()
|
||||
if len(widgets) != 0:
|
||||
with dpg.collapsing_header(
|
||||
label=f"{config['scene_names'][0]} widgets", default_open=True
|
||||
label=f"{config['scene_names'][0]} widgets",
|
||||
default_open=True,
|
||||
):
|
||||
for widget_config in widgets:
|
||||
widget_config_copy = widget_config.copy()
|
||||
|
|
|
|||
|
|
@ -138,7 +138,9 @@ class TracedPath(VMobject, metaclass=ConvertToOpenGL):
|
|||
"""
|
||||
|
||||
@deprecated_params(
|
||||
params="min_distance_to_new_point", since="v0.10.0", until="v0.12.0"
|
||||
params="min_distance_to_new_point",
|
||||
since="v0.10.0",
|
||||
until="v0.12.0",
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -302,11 +302,7 @@ class CoordinateSystem:
|
|||
The label.
|
||||
"""
|
||||
|
||||
if (
|
||||
isinstance(label_tex, float)
|
||||
or isinstance(label_tex, int)
|
||||
or isinstance(label_tex, str)
|
||||
):
|
||||
if isinstance(label_tex, (float, int, str)):
|
||||
label_tex = MathTex(label_tex)
|
||||
return label_tex
|
||||
|
||||
|
|
@ -393,7 +389,8 @@ class CoordinateSystem:
|
|||
def add_coordinates(
|
||||
self,
|
||||
*axes_numbers: Union[
|
||||
Optional[Iterable[float]], Union[Dict[float, Union[str, float, "Mobject"]]]
|
||||
Optional[Iterable[float]],
|
||||
Union[Dict[float, Union[str, float, "Mobject"]]],
|
||||
],
|
||||
**kwargs,
|
||||
):
|
||||
|
|
@ -992,7 +989,7 @@ class CoordinateSystem:
|
|||
self.coords_to_point(x + width_scale_factor * dx, y_point),
|
||||
graph_point,
|
||||
],
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -1085,7 +1082,10 @@ class CoordinateSystem:
|
|||
).set_opacity(opacity=opacity)
|
||||
|
||||
def angle_of_tangent(
|
||||
self, x: float, graph: "ParametricFunction", dx: float = 1e-8
|
||||
self,
|
||||
x: float,
|
||||
graph: "ParametricFunction",
|
||||
dx: float = 1e-8,
|
||||
) -> float:
|
||||
"""Returns the angle to the x-axis of the tangent
|
||||
to the plotted curve at a particular x-value.
|
||||
|
|
@ -1311,20 +1311,24 @@ class CoordinateSystem:
|
|||
|
||||
if dx_label is not None:
|
||||
group.dx_label.next_to(
|
||||
group.dx_line, np.sign(dx) * DOWN, buff=group.dx_label.height / 2
|
||||
group.dx_line,
|
||||
np.sign(dx) * DOWN,
|
||||
buff=group.dx_label.height / 2,
|
||||
)
|
||||
group.dx_label.set_color(group.dx_line.get_color())
|
||||
|
||||
if dy_label is not None:
|
||||
group.df_label.next_to(
|
||||
group.df_line, np.sign(dx) * RIGHT, buff=group.df_label.height / 2
|
||||
group.df_line,
|
||||
np.sign(dx) * RIGHT,
|
||||
buff=group.df_label.height / 2,
|
||||
)
|
||||
group.df_label.set_color(group.df_line.get_color())
|
||||
|
||||
if include_secant_line:
|
||||
group.secant_line = Line(p1, p2, color=secant_line_color)
|
||||
group.secant_line.scale_in_place(
|
||||
secant_line_length / group.secant_line.get_length()
|
||||
secant_line_length / group.secant_line.get_length(),
|
||||
)
|
||||
group.add(group.secant_line)
|
||||
return group
|
||||
|
|
@ -1443,7 +1447,8 @@ class CoordinateSystem:
|
|||
|
||||
T_label_group = VGroup()
|
||||
triangle = RegularPolygon(n=3, start_angle=np.pi / 2, stroke_width=0).set_fill(
|
||||
color=triangle_color, opacity=1
|
||||
color=triangle_color,
|
||||
opacity=1,
|
||||
)
|
||||
triangle.height = triangle_size
|
||||
triangle.move_to(self.coords_to_point(x_val, 0), UP)
|
||||
|
|
@ -1453,7 +1458,9 @@ class CoordinateSystem:
|
|||
T_label_group.add(t_label)
|
||||
|
||||
v_line = self.get_vertical_line(
|
||||
self.i2gp(x_val, graph), color=line_color, line_func=line_func
|
||||
self.i2gp(x_val, graph),
|
||||
color=line_color,
|
||||
line_func=line_func,
|
||||
)
|
||||
|
||||
T_label_group.add(triangle, v_line)
|
||||
|
|
@ -1515,10 +1522,12 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
|
|||
)
|
||||
|
||||
self.x_axis_config = merge_dicts_recursively(
|
||||
self.axis_config, self.x_axis_config
|
||||
self.axis_config,
|
||||
self.x_axis_config,
|
||||
)
|
||||
self.y_axis_config = merge_dicts_recursively(
|
||||
self.axis_config, self.y_axis_config
|
||||
self.axis_config,
|
||||
self.y_axis_config,
|
||||
)
|
||||
|
||||
self.x_axis = self._create_axis(self.x_range, self.x_axis_config, self.x_length)
|
||||
|
|
@ -1832,7 +1841,8 @@ class ThreeDAxes(Axes):
|
|||
self.z_axis_config = {}
|
||||
self._update_default_configs((self.z_axis_config,), (z_axis_config,))
|
||||
self.z_axis_config = merge_dicts_recursively(
|
||||
self.axis_config, self.z_axis_config
|
||||
self.axis_config,
|
||||
self.z_axis_config,
|
||||
)
|
||||
|
||||
self.z_normal = z_normal
|
||||
|
|
@ -1852,7 +1862,7 @@ class ThreeDAxes(Axes):
|
|||
self.add(z_axis)
|
||||
self.z_axis = z_axis
|
||||
|
||||
if not config.renderer == "opengl":
|
||||
if config.renderer != "opengl":
|
||||
self._add_3d_pieces()
|
||||
self._set_axis_shading()
|
||||
|
||||
|
|
@ -2299,7 +2309,7 @@ class PolarPlane(Axes):
|
|||
self.azimuth_units = azimuth_units
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invalid azimuth units. Expected one of: PI radians, TAU radians, degrees, gradians or None."
|
||||
"Invalid azimuth units. Expected one of: PI radians, TAU radians, degrees, gradians or None.",
|
||||
)
|
||||
|
||||
if azimuth_direction in ["CW", "CCW"]:
|
||||
|
|
@ -2552,7 +2562,7 @@ class PolarPlane(Axes):
|
|||
self.get_right()[0]
|
||||
* np.sin(d * (i * TAU) + self.azimuth_offset),
|
||||
0,
|
||||
]
|
||||
],
|
||||
),
|
||||
}
|
||||
for i in a_values
|
||||
|
|
@ -2560,7 +2570,8 @@ class PolarPlane(Axes):
|
|||
if self.azimuth_units == "PI radians" or self.azimuth_units == "TAU radians":
|
||||
a_tex = [
|
||||
self.get_radian_label(
|
||||
i["label"], font_size=self.azimuth_label_font_size
|
||||
i["label"],
|
||||
font_size=self.azimuth_label_font_size,
|
||||
).next_to(
|
||||
i["point"],
|
||||
direction=i["point"],
|
||||
|
|
@ -2598,7 +2609,8 @@ class PolarPlane(Axes):
|
|||
elif self.azimuth_units is None:
|
||||
a_tex = [
|
||||
MathTex(
|
||||
f'{i["label"]:g}', font_size=self.azimuth_label_font_size
|
||||
f'{i["label"]:g}',
|
||||
font_size=self.azimuth_label_font_size,
|
||||
).next_to(
|
||||
i["point"],
|
||||
direction=i["point"],
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|||
def generate_points(self):
|
||||
|
||||
discontinuities = filter(
|
||||
lambda t: self.t_min <= t <= self.t_max, self.discontinuities
|
||||
lambda t: self.t_min <= t <= self.t_max,
|
||||
self.discontinuities,
|
||||
)
|
||||
discontinuities = np.array(list(discontinuities))
|
||||
boundary_times = np.array(
|
||||
|
|
@ -86,7 +87,7 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|||
self.t_max,
|
||||
*(discontinuities - self.dt),
|
||||
*(discontinuities + self.dt),
|
||||
]
|
||||
],
|
||||
)
|
||||
boundary_times.sort()
|
||||
for t1, t2 in zip(boundary_times[0::2], boundary_times[1::2]):
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ class TipableVMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
anchor = self.get_end()
|
||||
angles = cartesian_to_spherical(handle - anchor)
|
||||
tip.rotate(
|
||||
angles[2] - PI - tip.tip_angle
|
||||
angles[2] - PI - tip.tip_angle,
|
||||
) # Rotates the tip along the azimuthal
|
||||
axis = [
|
||||
np.sin(angles[2]),
|
||||
|
|
@ -187,7 +187,8 @@ class TipableVMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
0,
|
||||
] # Obtains the perpendicular of the tip
|
||||
tip.rotate(
|
||||
-angles[1] + PI / 2, axis=axis
|
||||
-angles[1] + PI / 2,
|
||||
axis=axis,
|
||||
) # Rotates the tip along the vertical wrt the axis
|
||||
tip.shift(anchor - tip.tip_point)
|
||||
return tip
|
||||
|
|
@ -327,7 +328,7 @@ class Arc(TipableVMobject):
|
|||
angle=self.angle,
|
||||
start_angle=self.start_angle,
|
||||
n_components=self.num_components,
|
||||
)
|
||||
),
|
||||
)
|
||||
self.scale(self.radius, about_point=ORIGIN)
|
||||
self.shift(self.arc_center)
|
||||
|
|
@ -342,7 +343,7 @@ class Arc(TipableVMobject):
|
|||
start_angle + angle,
|
||||
2 * n_components + 1,
|
||||
)
|
||||
]
|
||||
],
|
||||
)
|
||||
theta = angle / n_components
|
||||
samples[1::2] /= np.cos(theta / 2)
|
||||
|
|
@ -358,9 +359,11 @@ class Arc(TipableVMobject):
|
|||
[
|
||||
np.cos(a) * RIGHT + np.sin(a) * UP
|
||||
for a in np.linspace(
|
||||
self.start_angle, self.start_angle + self.angle, self.num_components
|
||||
self.start_angle,
|
||||
self.start_angle + self.angle,
|
||||
self.num_components,
|
||||
)
|
||||
]
|
||||
],
|
||||
)
|
||||
# Figure out which control points will give the
|
||||
# Appropriate tangent lines to the circle
|
||||
|
|
@ -441,7 +444,7 @@ class ArcBetweenPoints(Arc):
|
|||
if radius < halfdist:
|
||||
raise ValueError(
|
||||
"""ArcBetweenPoints called with a radius that is
|
||||
smaller than half the distance between the points."""
|
||||
smaller than half the distance between the points.""",
|
||||
)
|
||||
arc_height = radius - math.sqrt(radius ** 2 - halfdist ** 2)
|
||||
angle = math.acos((radius - arc_height) / radius) * sign
|
||||
|
|
@ -957,7 +960,10 @@ class Line(TipableVMobject):
|
|||
|
||||
def generate_points(self):
|
||||
self.set_points_by_ends(
|
||||
start=self.start, end=self.end, buff=self.buff, path_arc=self.path_arc
|
||||
start=self.start,
|
||||
end=self.end,
|
||||
buff=self.buff,
|
||||
path_arc=self.path_arc,
|
||||
)
|
||||
|
||||
def set_points_by_ends(self, start, end, buff=0, path_arc=0):
|
||||
|
|
@ -1140,7 +1146,8 @@ class DashedLine(Line):
|
|||
**kwargs,
|
||||
):
|
||||
self.dash_spacing = kwargs.pop(
|
||||
"dash_spacing", None
|
||||
"dash_spacing",
|
||||
None,
|
||||
) # Unused param, remove with deprecation warning
|
||||
self.dash_length = dash_length
|
||||
self.dashed_ratio = dashed_ratio
|
||||
|
|
@ -1166,7 +1173,8 @@ class DashedLine(Line):
|
|||
|
||||
# Minimum number of dashes has to be 2
|
||||
return max(
|
||||
2, int(np.ceil((self.get_length() / self.dash_length) * self.dashed_ratio))
|
||||
2,
|
||||
int(np.ceil((self.get_length() / self.dash_length) * self.dashed_ratio)),
|
||||
)
|
||||
|
||||
def get_start(self) -> np.ndarray:
|
||||
|
|
@ -1557,7 +1565,10 @@ class Vector(Arrow):
|
|||
super().__init__(ORIGIN, direction, buff=buff, **kwargs)
|
||||
|
||||
def coordinate_label(
|
||||
self, integer_labels: bool = True, n_dim: int = 2, color: str = WHITE
|
||||
self,
|
||||
integer_labels: bool = True,
|
||||
n_dim: int = 2,
|
||||
color: str = WHITE,
|
||||
):
|
||||
"""Creates a label based on the coordinates of the vector.
|
||||
|
||||
|
|
@ -1737,7 +1748,7 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|||
|
||||
self.start_new_path(first_vertex)
|
||||
self.add_points_as_corners(
|
||||
[*(np.array(vertex) for vertex in vertices), first_vertex]
|
||||
[*(np.array(vertex) for vertex in vertices), first_vertex],
|
||||
)
|
||||
|
||||
def get_vertices(self) -> np.ndarray:
|
||||
|
|
@ -1973,7 +1984,9 @@ class RegularPolygram(Polygram):
|
|||
# polygon vertices.
|
||||
def gen_polygon_vertices(start_angle):
|
||||
reg_vertices, start_angle = regular_vertices(
|
||||
num_vertices, radius=radius, start_angle=start_angle
|
||||
num_vertices,
|
||||
radius=radius,
|
||||
start_angle=start_angle,
|
||||
)
|
||||
|
||||
vertices = []
|
||||
|
|
@ -2108,7 +2121,7 @@ class Star(Polygon):
|
|||
|
||||
if density <= 0 or density >= n / 2:
|
||||
raise ValueError(
|
||||
f"Incompatible density {density} for number of points {n}"
|
||||
f"Incompatible density {density} for number of points {n}",
|
||||
)
|
||||
|
||||
outer_angle = TAU * density / n
|
||||
|
|
@ -2119,10 +2132,14 @@ class Star(Polygon):
|
|||
inner_radius = outer_radius / (np.cos(inner_angle) * inverse_x)
|
||||
|
||||
outer_vertices, self.start_angle = regular_vertices(
|
||||
n, radius=outer_radius, start_angle=start_angle
|
||||
n,
|
||||
radius=outer_radius,
|
||||
start_angle=start_angle,
|
||||
)
|
||||
inner_vertices, _ = regular_vertices(
|
||||
n, radius=inner_radius, start_angle=self.start_angle + inner_angle
|
||||
n,
|
||||
radius=inner_radius,
|
||||
start_angle=self.start_angle + inner_angle,
|
||||
)
|
||||
|
||||
vertices = []
|
||||
|
|
@ -2350,7 +2367,7 @@ class ArcPolygonFromArcs(VMobject, metaclass=ConvertToOpenGL):
|
|||
def __init__(self, *arcs, **kwargs):
|
||||
if not all(isinstance(m, (Arc, ArcBetweenPoints)) for m in arcs):
|
||||
raise ValueError(
|
||||
"All ArcPolygon submobjects must be of type Arc/ArcBetweenPoints"
|
||||
"All ArcPolygon submobjects must be of type Arc/ArcBetweenPoints",
|
||||
)
|
||||
super().__init__(**kwargs)
|
||||
# Adding the arcs like this makes ArcPolygonFromArcs double as a VGroup.
|
||||
|
|
@ -2952,7 +2969,8 @@ class Angle(VMobject, metaclass=ConvertToOpenGL):
|
|||
self.dot_distance = dot_distance
|
||||
self.elbow = elbow
|
||||
inter = line_intersection(
|
||||
[line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()]
|
||||
[line1.get_start(), line1.get_end()],
|
||||
[line2.get_start(), line2.get_end()],
|
||||
)
|
||||
|
||||
if radius is None:
|
||||
|
|
@ -2982,7 +3000,7 @@ class Angle(VMobject, metaclass=ConvertToOpenGL):
|
|||
)
|
||||
angle_mobject = Elbow(**kwargs)
|
||||
angle_mobject.set_points_as_corners(
|
||||
[anchor_angle_1, anchor_middle, anchor_angle_2]
|
||||
[anchor_angle_1, anchor_middle, anchor_angle_2],
|
||||
)
|
||||
else:
|
||||
angle_1 = angle_of_vector(anchor_angle_1 - inter)
|
||||
|
|
|
|||
|
|
@ -64,14 +64,14 @@ def _determine_graph_layout(
|
|||
elif layout == "partite":
|
||||
if partitions is None or len(partitions) == 0:
|
||||
raise ValueError(
|
||||
"The partite layout requires the 'partitions' parameter to contain the partition of the vertices"
|
||||
"The partite layout requires the 'partitions' parameter to contain the partition of the vertices",
|
||||
)
|
||||
partition_count = len(partitions)
|
||||
for i in range(partition_count):
|
||||
for v in partitions[i]:
|
||||
if nx_graph.nodes[v] is None:
|
||||
raise ValueError(
|
||||
"The partition must contain arrays of vertices in the graph"
|
||||
"The partition must contain arrays of vertices in the graph",
|
||||
)
|
||||
nx_graph.nodes[v]["subset"] = i
|
||||
# Add missing vertices to their own side
|
||||
|
|
@ -93,7 +93,7 @@ def _determine_graph_layout(
|
|||
else:
|
||||
raise ValueError(
|
||||
f"The layout '{layout}' is neither a recognized automatic layout, "
|
||||
"nor a vertex placement dictionary."
|
||||
"nor a vertex placement dictionary.",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ def _tree_layout(
|
|||
else:
|
||||
for i in range(new_row_length):
|
||||
result[new_row[i]] = np.array(
|
||||
[-1 + 2 * i / (new_row_length - 1), current_height, 0]
|
||||
[-1 + 2 * i / (new_row_length - 1), current_height, 0],
|
||||
)
|
||||
|
||||
_recursive_position_for_row(
|
||||
|
|
@ -144,7 +144,11 @@ def _tree_layout(
|
|||
)
|
||||
|
||||
_recursive_position_for_row(
|
||||
G, result, two_rows_before=[], last_row=[root_vertex], current_height=1
|
||||
G,
|
||||
result,
|
||||
two_rows_before=[],
|
||||
last_row=[root_vertex],
|
||||
current_height=1,
|
||||
)
|
||||
|
||||
height = max(map(lambda v: result[v][1], result))
|
||||
|
|
@ -507,7 +511,7 @@ class Graph(VMobject, metaclass=ConvertToOpenGL):
|
|||
|
||||
if vertex in self.vertices:
|
||||
raise ValueError(
|
||||
f"Vertex identifier '{vertex}' is already used for a vertex in this graph."
|
||||
f"Vertex identifier '{vertex}' is already used for a vertex in this graph.",
|
||||
)
|
||||
|
||||
self._graph.add_node(vertex)
|
||||
|
|
@ -601,7 +605,7 @@ class Graph(VMobject, metaclass=ConvertToOpenGL):
|
|||
assert isinstance(vertex_config, dict)
|
||||
base_vertex_config = copy(self.default_vertex_config)
|
||||
base_vertex_config.update(
|
||||
{key: val for key, val in vertex_config.items() if key not in vertices}
|
||||
{key: val for key, val in vertex_config.items() if key not in vertices},
|
||||
)
|
||||
vertex_config = {
|
||||
v: (vertex_config[v] if v in vertex_config else copy(base_vertex_config))
|
||||
|
|
@ -649,7 +653,7 @@ class Graph(VMobject, metaclass=ConvertToOpenGL):
|
|||
"""
|
||||
if vertex not in self.vertices:
|
||||
raise ValueError(
|
||||
f"The graph does not contain a vertex with identifier '{vertex}'"
|
||||
f"The graph does not contain a vertex with identifier '{vertex}'",
|
||||
)
|
||||
|
||||
self._graph.remove_node(vertex)
|
||||
|
|
@ -796,7 +800,9 @@ class Graph(VMobject, metaclass=ConvertToOpenGL):
|
|||
added_mobjects = sum(
|
||||
(
|
||||
self._add_edge(
|
||||
edge, edge_type=edge_type, edge_config=edge_config[edge]
|
||||
edge,
|
||||
edge_type=edge_type,
|
||||
edge_config=edge_config[edge],
|
||||
).submobjects
|
||||
for edge in edges
|
||||
),
|
||||
|
|
|
|||
|
|
@ -145,7 +145,10 @@ class ManimBanner(VGroup):
|
|||
|
||||
return AnimationGroup(
|
||||
UpdateFromAlphaFunc(
|
||||
self.shapes, spiral_updater, run_time=run_time, rate_func=ease_out_sine
|
||||
self.shapes,
|
||||
spiral_updater,
|
||||
run_time=run_time,
|
||||
rate_func=ease_out_sine,
|
||||
),
|
||||
FadeIn(self.M, run_time=run_time / 2),
|
||||
lag_ratio=0.1,
|
||||
|
|
@ -257,6 +260,9 @@ class ManimBanner(VGroup):
|
|||
rate_func=ease_in_out_cubic,
|
||||
),
|
||||
UpdateFromAlphaFunc(
|
||||
self, slide_back, run_time=run_time * 1 / 3, rate_func=smooth
|
||||
self,
|
||||
slide_back,
|
||||
run_time=run_time * 1 / 3,
|
||||
rate_func=smooth,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -532,7 +532,10 @@ class MobjectMatrix(Matrix):
|
|||
|
||||
|
||||
def get_det_text(
|
||||
matrix, determinant=None, background_rect=False, initial_scale_factor=2
|
||||
matrix,
|
||||
determinant=None,
|
||||
background_rect=False,
|
||||
initial_scale_factor=2,
|
||||
):
|
||||
r"""Helper function to create determinant.
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ from ..utils.color import (
|
|||
color_gradient,
|
||||
interpolate_color,
|
||||
)
|
||||
from ..utils.deprecation import deprecated
|
||||
from ..utils.exceptions import MultiAnimationOverrideException
|
||||
from ..utils.iterables import list_update, remove_list_redundancies
|
||||
from ..utils.paths import straight_path
|
||||
|
|
@ -89,7 +90,8 @@ class Mobject:
|
|||
super().__init_subclass__(**kwargs)
|
||||
|
||||
cls.animation_overrides: Dict[
|
||||
Type["Animation"], Callable[["Mobject"], "Animation"]
|
||||
Type["Animation"],
|
||||
Callable[["Mobject"], "Animation"],
|
||||
] = {}
|
||||
cls._add_intrinsic_animation_overrides()
|
||||
|
||||
|
|
@ -109,7 +111,8 @@ class Mobject:
|
|||
|
||||
@classmethod
|
||||
def animation_override_for(
|
||||
cls, animation_class: Type["Animation"]
|
||||
cls,
|
||||
animation_class: Type["Animation"],
|
||||
) -> "Optional[Callable[[Mobject, ...], Animation]]":
|
||||
"""Returns the function defining a specific animation override for this class.
|
||||
|
||||
|
|
@ -174,7 +177,7 @@ class Mobject:
|
|||
f"The animation {animation_class.__name__} for "
|
||||
f"{cls.__name__} is overridden by more than one method: "
|
||||
f"{cls.animation_overrides[animation_class].__qualname__} and "
|
||||
f"{override_func.__qualname__}."
|
||||
f"{override_func.__qualname__}.",
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
@ -684,7 +687,7 @@ class Mobject:
|
|||
"""Saves an image of only this :class:`Mobject` at its position to a png
|
||||
file."""
|
||||
self.get_image().save(
|
||||
Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png")
|
||||
Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"),
|
||||
)
|
||||
|
||||
def copy(self: T) -> T:
|
||||
|
|
@ -781,10 +784,7 @@ class Mobject:
|
|||
:meth:`get_time_based_updaters`
|
||||
|
||||
"""
|
||||
for updater in self.updaters:
|
||||
if "dt" in get_parameters(updater):
|
||||
return True
|
||||
return False
|
||||
return any("dt" in get_parameters(updater) for updater in self.updaters)
|
||||
|
||||
def get_updaters(self) -> List[Updater]:
|
||||
"""Return all updaters.
|
||||
|
|
@ -1253,7 +1253,10 @@ class Mobject:
|
|||
# above methods
|
||||
|
||||
def apply_points_function_about_point(
|
||||
self, func, about_point=None, about_edge=None
|
||||
self,
|
||||
func,
|
||||
about_point=None,
|
||||
about_edge=None,
|
||||
):
|
||||
if about_point is None:
|
||||
if about_edge is None:
|
||||
|
|
@ -1536,7 +1539,10 @@ class Mobject:
|
|||
return self
|
||||
|
||||
def move_to(
|
||||
self, point_or_mobject, aligned_edge=ORIGIN, coor_mask=np.array([1, 1, 1])
|
||||
self,
|
||||
point_or_mobject,
|
||||
aligned_edge=ORIGIN,
|
||||
coor_mask=np.array([1, 1, 1]),
|
||||
):
|
||||
"""Move center of the :class:`~.Mobject` to certain coordinate."""
|
||||
if isinstance(point_or_mobject, Mobject):
|
||||
|
|
@ -1555,13 +1561,19 @@ class Mobject:
|
|||
self.stretch_to_fit_height(mobject.height)
|
||||
else:
|
||||
self.rescale_to_fit(
|
||||
mobject.length_over_dim(dim_to_match), dim_to_match, stretch=False
|
||||
mobject.length_over_dim(dim_to_match),
|
||||
dim_to_match,
|
||||
stretch=False,
|
||||
)
|
||||
self.shift(mobject.get_center() - self.get_center())
|
||||
return self
|
||||
|
||||
def surround(
|
||||
self, mobject: "Mobject", dim_to_match=0, stretch=False, buff=MED_SMALL_BUFF
|
||||
self,
|
||||
mobject: "Mobject",
|
||||
dim_to_match=0,
|
||||
stretch=False,
|
||||
buff=MED_SMALL_BUFF,
|
||||
):
|
||||
self.replace(mobject, dim_to_match, stretch)
|
||||
length = mobject.length_over_dim(dim_to_match)
|
||||
|
|
@ -1662,10 +1674,17 @@ class Mobject:
|
|||
return self
|
||||
|
||||
def set_colors_by_radial_gradient(
|
||||
self, center=None, radius=1, inner_color=WHITE, outer_color=BLACK
|
||||
self,
|
||||
center=None,
|
||||
radius=1,
|
||||
inner_color=WHITE,
|
||||
outer_color=BLACK,
|
||||
):
|
||||
self.set_submobject_colors_by_radial_gradient(
|
||||
center, radius, inner_color, outer_color
|
||||
center,
|
||||
radius,
|
||||
inner_color,
|
||||
outer_color,
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1683,7 +1702,11 @@ class Mobject:
|
|||
return self
|
||||
|
||||
def set_submobject_colors_by_radial_gradient(
|
||||
self, center=None, radius=1, inner_color=WHITE, outer_color=BLACK
|
||||
self,
|
||||
center=None,
|
||||
radius=1,
|
||||
inner_color=WHITE,
|
||||
outer_color=BLACK,
|
||||
):
|
||||
if center is None:
|
||||
center = self.get_center()
|
||||
|
|
@ -1805,7 +1828,9 @@ class Mobject:
|
|||
return result
|
||||
for dim in range(self.dim):
|
||||
result[dim] = self.get_extremum_along_dim(
|
||||
all_points, dim=dim, key=direction[dim]
|
||||
all_points,
|
||||
dim=dim,
|
||||
key=direction[dim],
|
||||
)
|
||||
return result
|
||||
|
||||
|
|
@ -1880,9 +1905,14 @@ class Mobject:
|
|||
|
||||
def length_over_dim(self, dim):
|
||||
"""Measure the length of an :class:`~.Mobject` in a certain direction."""
|
||||
return self.reduce_across_dimension(
|
||||
np.max, np.max, dim
|
||||
) - self.reduce_across_dimension(np.min, np.min, dim)
|
||||
return (
|
||||
self.reduce_across_dimension(
|
||||
np.max,
|
||||
np.max,
|
||||
dim,
|
||||
)
|
||||
- self.reduce_across_dimension(np.min, np.min, dim)
|
||||
)
|
||||
|
||||
def get_coord(self, dim, direction=ORIGIN):
|
||||
"""Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
|
||||
|
|
@ -2223,10 +2253,18 @@ class Mobject:
|
|||
return alignments
|
||||
|
||||
row_alignments = init_alignments(
|
||||
row_alignments, rows, {"u": UP, "c": ORIGIN, "d": DOWN}, "row", RIGHT
|
||||
row_alignments,
|
||||
rows,
|
||||
{"u": UP, "c": ORIGIN, "d": DOWN},
|
||||
"row",
|
||||
RIGHT,
|
||||
)
|
||||
col_alignments = init_alignments(
|
||||
col_alignments, cols, {"l": LEFT, "c": ORIGIN, "r": RIGHT}, "col", UP
|
||||
col_alignments,
|
||||
cols,
|
||||
{"l": LEFT, "c": ORIGIN, "r": RIGHT},
|
||||
"col",
|
||||
UP,
|
||||
)
|
||||
# Now row_alignment[r] + col_alignment[c] is the alignment in cell [r][c]
|
||||
|
||||
|
|
@ -2242,7 +2280,7 @@ class Mobject:
|
|||
}
|
||||
if flow_order not in mapper:
|
||||
raise ValueError(
|
||||
'flow_order must be one of the following values: "dr", "rd", "ld" "dl", "ru", "ur", "lu", "ul".'
|
||||
'flow_order must be one of the following values: "dr", "rd", "ld" "dl", "ru", "ur", "lu", "ul".',
|
||||
)
|
||||
flow_order = mapper[flow_order]
|
||||
|
||||
|
|
@ -2552,7 +2590,7 @@ class Mobject:
|
|||
if self.has_no_points():
|
||||
caller_name = sys._getframe(1).f_code.co_name
|
||||
raise Exception(
|
||||
f"Cannot call Mobject.{caller_name} for a Mobject with no points"
|
||||
f"Cannot call Mobject.{caller_name} for a Mobject with no points",
|
||||
)
|
||||
|
||||
# About z-index
|
||||
|
|
@ -2636,7 +2674,7 @@ class _AnimationBuilder:
|
|||
def __call__(self, **kwargs):
|
||||
if self.cannot_pass_args:
|
||||
raise ValueError(
|
||||
"Animation arguments must be passed before accessing methods and can only be passed once"
|
||||
"Animation arguments must be passed before accessing methods and can only be passed once",
|
||||
)
|
||||
|
||||
self.anim_args = kwargs
|
||||
|
|
@ -2652,7 +2690,7 @@ class _AnimationBuilder:
|
|||
if (self.is_chaining and has_overridden_animation) or self.overridden_animation:
|
||||
raise NotImplementedError(
|
||||
"Method chaining is currently not supported for "
|
||||
"overridden animations"
|
||||
"overridden animations",
|
||||
)
|
||||
|
||||
def update_target(*method_args, **method_kwargs):
|
||||
|
|
|
|||
|
|
@ -331,7 +331,8 @@ class NumberLine(Line):
|
|||
**number_config,
|
||||
) -> DecimalNumber:
|
||||
number_config = merge_dicts_recursively(
|
||||
self.decimal_number_config, number_config
|
||||
self.decimal_number_config,
|
||||
number_config,
|
||||
)
|
||||
if direction is None:
|
||||
direction = self.label_direction
|
||||
|
|
@ -422,7 +423,7 @@ class NumberLine(Line):
|
|||
The label.
|
||||
"""
|
||||
|
||||
if isinstance(label_tex, float) or isinstance(label_tex, int):
|
||||
if isinstance(label_tex, (float, int)):
|
||||
label_tex = MathTex(label_tex)
|
||||
elif isinstance(label_tex, str):
|
||||
label_tex = Tex(label_tex)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
"font_size": font_size,
|
||||
"stroke_width": stroke_width,
|
||||
"fill_opacity": fill_opacity,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
self.set_submobjects_from_number(number)
|
||||
|
|
@ -123,7 +123,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
# Add non-numerical bits
|
||||
if self.show_ellipsis:
|
||||
self.add(
|
||||
self.string_to_mob("\\dots", SingleStringMathTex, color=self.color)
|
||||
self.string_to_mob("\\dots", SingleStringMathTex, color=self.color),
|
||||
)
|
||||
|
||||
if self.unit is not None:
|
||||
|
|
@ -131,7 +131,8 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
self.add(self.unit_sign)
|
||||
|
||||
self.arrange(
|
||||
buff=self.digit_buff_per_font_unit * self._font_size, aligned_edge=DOWN
|
||||
buff=self.digit_buff_per_font_unit * self._font_size,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
|
||||
# Handle alignment of parts that should be aligned
|
||||
|
|
@ -204,7 +205,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
str(config["num_decimal_places"]),
|
||||
"f",
|
||||
"}",
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
def get_complex_formatter(self):
|
||||
|
|
@ -213,7 +214,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
self.get_formatter(field_name="0.real"),
|
||||
self.get_formatter(field_name="0.imag", include_sign=True),
|
||||
"i",
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
def set_value(self, number: float):
|
||||
|
|
@ -400,13 +401,15 @@ class Variable(VMobject, metaclass=ConvertToOpenGL):
|
|||
|
||||
if var_type == DecimalNumber:
|
||||
self.value = DecimalNumber(
|
||||
self.tracker.get_value(), num_decimal_places=num_decimal_places
|
||||
self.tracker.get_value(),
|
||||
num_decimal_places=num_decimal_places,
|
||||
)
|
||||
elif var_type == Integer:
|
||||
self.value = Integer(self.tracker.get_value())
|
||||
|
||||
self.value.add_updater(lambda v: v.set_value(self.tracker.get_value())).next_to(
|
||||
self.label, RIGHT
|
||||
self.label,
|
||||
RIGHT,
|
||||
)
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class OpenGLArc(OpenGLTipableVMobject):
|
|||
angle=self.angle,
|
||||
start_angle=self.start_angle,
|
||||
n_components=self.n_components,
|
||||
)
|
||||
),
|
||||
)
|
||||
# To maintain proper orientation for fill shaders.
|
||||
self.scale(self.radius, about_point=ORIGIN)
|
||||
|
|
@ -235,7 +235,7 @@ class OpenGLArc(OpenGLTipableVMobject):
|
|||
start_angle + angle,
|
||||
2 * n_components + 1,
|
||||
)
|
||||
]
|
||||
],
|
||||
)
|
||||
theta = angle / n_components
|
||||
samples[1::2] /= np.cos(theta / 2)
|
||||
|
|
@ -541,14 +541,17 @@ class OpenGLDashedLine(OpenGLLine):
|
|||
dashed_ratio = self.dashed_ratio
|
||||
num_dashes = self.calculate_num_dashes(dashed_ratio)
|
||||
dashes = OpenGLDashedVMobject(
|
||||
self, num_dashes=num_dashes, dashed_ratio=dashed_ratio
|
||||
self,
|
||||
num_dashes=num_dashes,
|
||||
dashed_ratio=dashed_ratio,
|
||||
)
|
||||
self.clear_points()
|
||||
self.add(*dashes)
|
||||
|
||||
def calculate_num_dashes(self, dashed_ratio):
|
||||
return max(
|
||||
2, int(np.ceil((self.get_length() / self.dash_length) * dashed_ratio))
|
||||
2,
|
||||
int(np.ceil((self.get_length() / self.dash_length) * dashed_ratio)),
|
||||
)
|
||||
|
||||
def get_start(self):
|
||||
|
|
@ -688,7 +691,9 @@ class OpenGLArrow(OpenGLLine):
|
|||
|
||||
def reset_points_around_ends(self):
|
||||
self.set_points_by_ends(
|
||||
self.get_start(), self.get_end(), path_arc=self.path_arc
|
||||
self.get_start(),
|
||||
self.get_end(),
|
||||
path_arc=self.path_arc,
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
|
|||
|
|
@ -285,7 +285,11 @@ class OpenGLMobject:
|
|||
return self.point_from_proportion(0.5)
|
||||
|
||||
def apply_points_function(
|
||||
self, func, about_point=None, about_edge=ORIGIN, works_on_bounding_box=False
|
||||
self,
|
||||
func,
|
||||
about_point=None,
|
||||
about_edge=ORIGIN,
|
||||
works_on_bounding_box=False,
|
||||
):
|
||||
if about_point is None and about_edge is not None:
|
||||
about_point = self.get_bounding_box_point(about_edge)
|
||||
|
|
@ -349,7 +353,7 @@ class OpenGLMobject:
|
|||
for mob in self.get_family()[1:]
|
||||
if mob.has_points()
|
||||
),
|
||||
]
|
||||
],
|
||||
)
|
||||
if len(all_points) == 0:
|
||||
return np.zeros((3, self.dim))
|
||||
|
|
@ -654,10 +658,18 @@ class OpenGLMobject:
|
|||
return alignments
|
||||
|
||||
row_alignments = init_alignments(
|
||||
row_alignments, rows, {"u": UP, "c": ORIGIN, "d": DOWN}, "row", RIGHT
|
||||
row_alignments,
|
||||
rows,
|
||||
{"u": UP, "c": ORIGIN, "d": DOWN},
|
||||
"row",
|
||||
RIGHT,
|
||||
)
|
||||
col_alignments = init_alignments(
|
||||
col_alignments, cols, {"l": LEFT, "c": ORIGIN, "r": RIGHT}, "col", UP
|
||||
col_alignments,
|
||||
cols,
|
||||
{"l": LEFT, "c": ORIGIN, "r": RIGHT},
|
||||
"col",
|
||||
UP,
|
||||
)
|
||||
# Now row_alignment[r] + col_alignment[c] is the alignment in cell [r][c]
|
||||
|
||||
|
|
@ -673,7 +685,7 @@ class OpenGLMobject:
|
|||
}
|
||||
if flow_order not in mapper:
|
||||
raise ValueError(
|
||||
'flow_order must be one of the following values: "dr", "rd", "ld" "dl", "ru", "ur", "lu", "ul".'
|
||||
'flow_order must be one of the following values: "dr", "rd", "ld" "dl", "ru", "ur", "lu", "ul".',
|
||||
)
|
||||
flow_order = mapper[flow_order]
|
||||
|
||||
|
|
@ -1047,7 +1059,7 @@ class OpenGLMobject:
|
|||
+ np.dot(
|
||||
alphas.reshape((len(alphas), 1)),
|
||||
np.array(direction).reshape((1, mob.dim)),
|
||||
)
|
||||
),
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1096,7 +1108,7 @@ class OpenGLMobject:
|
|||
else:
|
||||
target_aligner = mob
|
||||
target_point = target_aligner.get_bounding_box_point(
|
||||
aligned_edge + direction
|
||||
aligned_edge + direction,
|
||||
)
|
||||
else:
|
||||
target_point = mobject_or_point
|
||||
|
|
@ -1194,7 +1206,10 @@ class OpenGLMobject:
|
|||
return self
|
||||
|
||||
def move_to(
|
||||
self, point_or_mobject, aligned_edge=ORIGIN, coor_mask=np.array([1, 1, 1])
|
||||
self,
|
||||
point_or_mobject,
|
||||
aligned_edge=ORIGIN,
|
||||
coor_mask=np.array([1, 1, 1]),
|
||||
):
|
||||
if isinstance(point_or_mobject, OpenGLMobject):
|
||||
target = point_or_mobject.get_bounding_box_point(aligned_edge)
|
||||
|
|
@ -1213,7 +1228,9 @@ class OpenGLMobject:
|
|||
self.rescale_to_fit(mobject.length_over_dim(i), i, stretch=True)
|
||||
else:
|
||||
self.rescale_to_fit(
|
||||
mobject.length_over_dim(dim_to_match), dim_to_match, stretch=False
|
||||
mobject.length_over_dim(dim_to_match),
|
||||
dim_to_match,
|
||||
stretch=False,
|
||||
)
|
||||
self.shift(mobject.get_center() - self.get_center())
|
||||
return self
|
||||
|
|
@ -1410,8 +1427,8 @@ class OpenGLMobject:
|
|||
corner_vect,
|
||||
out=np.zeros(len(direction)),
|
||||
where=((corner_vect) != 0),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
def get_top(self):
|
||||
|
|
@ -1647,7 +1664,9 @@ class OpenGLMobject:
|
|||
self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha)
|
||||
for key in self.uniforms:
|
||||
self.uniforms[key] = interpolate(
|
||||
mobject1.uniforms[key], mobject2.uniforms[key], alpha
|
||||
mobject1.uniforms[key],
|
||||
mobject2.uniforms[key],
|
||||
alpha,
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1690,7 +1709,9 @@ class OpenGLMobject:
|
|||
|
||||
def lock_matching_data(self, mobject1, mobject2):
|
||||
for sm, sm1, sm2 in zip(
|
||||
self.get_family(), mobject1.get_family(), mobject2.get_family()
|
||||
self.get_family(),
|
||||
mobject1.get_family(),
|
||||
mobject2.get_family(),
|
||||
):
|
||||
keys = sm.data.keys() & sm1.data.keys() & sm2.data.keys()
|
||||
sm.lock_data(
|
||||
|
|
@ -1698,8 +1719,8 @@ class OpenGLMobject:
|
|||
filter(
|
||||
lambda key: np.all(sm1.data[key] == sm2.data[key]),
|
||||
keys,
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1760,7 +1781,11 @@ class OpenGLMobject:
|
|||
return self
|
||||
|
||||
def set_color_by_xyz_func(
|
||||
self, glsl_snippet, min_value=-5.0, max_value=5.0, colormap="viridis"
|
||||
self,
|
||||
glsl_snippet,
|
||||
min_value=-5.0,
|
||||
max_value=5.0,
|
||||
colormap="viridis",
|
||||
):
|
||||
"""
|
||||
Pass in a glsl expression in terms of x, y and z which returns
|
||||
|
|
@ -1777,7 +1802,7 @@ class OpenGLMobject:
|
|||
float(min_value),
|
||||
float(max_value),
|
||||
get_colormap_code(rgb_list),
|
||||
)
|
||||
),
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1825,7 +1850,8 @@ class OpenGLMobject:
|
|||
d_len = len(self.data[data_key])
|
||||
if d_len != 1 and d_len != len(array):
|
||||
self.data[data_key] = resize_with_interpolation(
|
||||
self.data[data_key], len(array)
|
||||
self.data[data_key],
|
||||
len(array),
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1999,7 +2025,7 @@ class _AnimationBuilder:
|
|||
def __call__(self, **kwargs):
|
||||
if self.cannot_pass_args:
|
||||
raise ValueError(
|
||||
"Animation arguments must be passed before accessing methods and can only be passed once"
|
||||
"Animation arguments must be passed before accessing methods and can only be passed once",
|
||||
)
|
||||
|
||||
self.anim_args = kwargs
|
||||
|
|
@ -2015,7 +2041,7 @@ class _AnimationBuilder:
|
|||
if (self.is_chaining and has_overridden_animation) or self.overridden_animation:
|
||||
raise NotImplementedError(
|
||||
"Method chaining is currently not supported for "
|
||||
"overridden animations"
|
||||
"overridden animations",
|
||||
)
|
||||
|
||||
def update_target(*method_args, **method_kwargs):
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ class Polyhedron(VGroup):
|
|||
return edges
|
||||
|
||||
def create_faces(
|
||||
self, face_coords: List[List[Union[List, np.ndarray]]]
|
||||
self,
|
||||
face_coords: List[List[Union[List, np.ndarray]]],
|
||||
) -> "VGroup":
|
||||
"""Creates VGroup of faces from a list of face coordinates."""
|
||||
face_group = VGroup()
|
||||
|
|
|
|||
|
|
@ -119,7 +119,12 @@ class SampleSpace(Rectangle):
|
|||
self.add(self.vertical_parts)
|
||||
|
||||
def get_subdivision_braces_and_labels(
|
||||
self, parts, labels, direction, buff=SMALL_BUFF, min_num_quads=1
|
||||
self,
|
||||
parts,
|
||||
labels,
|
||||
direction,
|
||||
buff=SMALL_BUFF,
|
||||
min_num_quads=1,
|
||||
):
|
||||
label_mobs = VGroup()
|
||||
braces = VGroup()
|
||||
|
|
|
|||
|
|
@ -93,11 +93,13 @@ class Brace(SVGPathMobject):
|
|||
right = mobject.get_corner(DOWN + RIGHT)
|
||||
target_width = right[0] - left[0]
|
||||
linear_section_length = max(
|
||||
0, (target_width * sharpness - default_min_width) / 2
|
||||
0,
|
||||
(target_width * sharpness - default_min_width) / 2,
|
||||
)
|
||||
|
||||
path = path_string_template.format(
|
||||
linear_section_length, -linear_section_length
|
||||
linear_section_length,
|
||||
-linear_section_length,
|
||||
)
|
||||
|
||||
SVGPathMobject.__init__(
|
||||
|
|
@ -179,7 +181,7 @@ class BraceLabel(VMobject, metaclass=ConvertToOpenGL):
|
|||
obj = self.get_group_class()(*obj)
|
||||
self.brace = Brace(obj, brace_direction, buff, **kwargs)
|
||||
|
||||
if isinstance(text, tuple) or isinstance(text, list):
|
||||
if isinstance(text, (tuple, list)):
|
||||
self.label = self.label_constructor(font_size=font_size, *text, **kwargs)
|
||||
else:
|
||||
self.label = self.label_constructor(str(text), font_size=font_size)
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class Code(VGroup):
|
|||
self.code_string = code
|
||||
else:
|
||||
raise ValueError(
|
||||
"Neither a code file nor a code string have been specified."
|
||||
"Neither a code file nor a code string have been specified.",
|
||||
)
|
||||
if isinstance(self.style, str):
|
||||
self.style = self.style.lower()
|
||||
|
|
@ -269,7 +269,7 @@ class Code(VGroup):
|
|||
buttons = VGroup(red_button, yellow_button, green_button)
|
||||
buttons.shift(
|
||||
UP * (height / 2 - 0.1 * 2 - 0.05)
|
||||
+ LEFT * (width / 2 - 0.1 * 5 - self.corner_radius / 2 - 0.05)
|
||||
+ LEFT * (width / 2 - 0.1 * 5 - self.corner_radius / 2 - 0.05),
|
||||
)
|
||||
|
||||
self.background_mobject = VGroup(rect, buttons)
|
||||
|
|
@ -380,16 +380,19 @@ class Code(VGroup):
|
|||
|
||||
if self.generate_html_file:
|
||||
os.makedirs(
|
||||
os.path.join("assets", "codes", "generated_html_files"), exist_ok=True
|
||||
os.path.join("assets", "codes", "generated_html_files"),
|
||||
exist_ok=True,
|
||||
)
|
||||
file = open(
|
||||
with open(
|
||||
os.path.join(
|
||||
"assets", "codes", "generated_html_files", self.file_name + ".html"
|
||||
"assets",
|
||||
"codes",
|
||||
"generated_html_files",
|
||||
self.file_name + ".html",
|
||||
),
|
||||
"w",
|
||||
)
|
||||
file.write(self.html_string)
|
||||
file.close()
|
||||
) as file:
|
||||
file.write(self.html_string)
|
||||
|
||||
def gen_code_json(self):
|
||||
"""Function to background_color, generate code_json and tab_spaces from html_string.
|
||||
|
|
@ -413,7 +416,8 @@ class Code(VGroup):
|
|||
self.html_string = self.html_string.replace("</" + " " * i, "</")
|
||||
for i in range(10, -1, -1):
|
||||
self.html_string = self.html_string.replace(
|
||||
"</span>" + " " * i, " " * i + "</span>"
|
||||
"</span>" + " " * i,
|
||||
" " * i + "</span>",
|
||||
)
|
||||
self.html_string = self.html_string.replace("background-color:", "background:")
|
||||
|
||||
|
|
@ -440,7 +444,7 @@ class Code(VGroup):
|
|||
start_point = lines[line_index].find("<")
|
||||
starting_string = lines[line_index][:start_point]
|
||||
indentation_chars_count = lines[line_index][:start_point].count(
|
||||
self.indentation_chars
|
||||
self.indentation_chars,
|
||||
)
|
||||
if (
|
||||
starting_string.__len__()
|
||||
|
|
@ -538,7 +542,13 @@ class Code(VGroup):
|
|||
|
||||
|
||||
def hilite_me(
|
||||
code, language, style, insert_line_no, divstyles, file_path, line_no_from
|
||||
code,
|
||||
language,
|
||||
style,
|
||||
insert_line_no,
|
||||
divstyles,
|
||||
file_path,
|
||||
line_no_from,
|
||||
):
|
||||
"""Function to highlight code from string to html.
|
||||
|
||||
|
|
@ -575,7 +585,7 @@ def hilite_me(
|
|||
html = highlight(code, lexer, formatter)
|
||||
elif language is None:
|
||||
raise ValueError(
|
||||
"The code language has to be specified when rendering a code string"
|
||||
"The code language has to be specified when rendering a code string",
|
||||
)
|
||||
else:
|
||||
html = highlight(code, get_lexer_by_name(language, **{}), formatter)
|
||||
|
|
@ -612,6 +622,7 @@ def insert_line_numbers_in_html(html, line_no_from):
|
|||
format_lines = "%" + str(len(str(numbers[-1]))) + "i"
|
||||
lines = "\n".join(format_lines % i for i in numbers)
|
||||
html = html.replace(
|
||||
pre_open, "<table><tr><td>" + pre_open + lines + "</pre></td><td>" + pre_open
|
||||
pre_open,
|
||||
"<table><tr><td>" + pre_open + lines + "</pre></td><td>" + pre_open,
|
||||
)
|
||||
return html
|
||||
|
|
|
|||
|
|
@ -414,7 +414,8 @@ class OpenGLMathTex(OpenGLSingleStringMathTex):
|
|||
|
||||
def break_up_tex_strings(self, tex_strings):
|
||||
substrings_to_isolate = op.add(
|
||||
self.substrings_to_isolate, list(self.tex_to_color_map.keys())
|
||||
self.substrings_to_isolate,
|
||||
list(self.tex_to_color_map.keys()),
|
||||
)
|
||||
split_list = split_string_list_to_isolate_substrings(
|
||||
tex_strings, *substrings_to_isolate
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
char_index_counter : char_index_counter
|
||||
+ lines_str_list[line_index].__len__()
|
||||
+ 1
|
||||
]
|
||||
],
|
||||
)
|
||||
char_index_counter += lines_str_list[line_index].__len__() + 1
|
||||
self.lines = []
|
||||
|
|
@ -160,7 +160,7 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
self.lines_initial_positions.append(self.lines[0][line_no].get_center())
|
||||
self.lines.append([])
|
||||
self.lines[1].extend(
|
||||
[self.alignment for _ in range(chars_lines_text_list.__len__())]
|
||||
[self.alignment for _ in range(chars_lines_text_list.__len__())],
|
||||
)
|
||||
OpenGLVGroup.__init__(
|
||||
self, *(self.lines[0][i] for i in range(self.lines[0].__len__())), **config
|
||||
|
|
@ -226,7 +226,7 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
self.lines[1] = [None for _ in range(self.lines[0].__len__())]
|
||||
for line_no in range(0, self.lines[0].__len__()):
|
||||
self[line_no].move_to(
|
||||
self.get_center() + self.lines_initial_positions[line_no]
|
||||
self.get_center() + self.lines_initial_positions[line_no],
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
self.lines[1][line_no] = alignment
|
||||
if self.lines[1][line_no] == "center":
|
||||
self[line_no].move_to(
|
||||
np.array([self.get_center()[0], self[line_no].get_center()[1], 0])
|
||||
np.array([self.get_center()[0], self[line_no].get_center()[1], 0]),
|
||||
)
|
||||
elif self.lines[1][line_no] == "right":
|
||||
self[line_no].move_to(
|
||||
|
|
@ -264,8 +264,8 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
self.get_right()[0] - self[line_no].width / 2,
|
||||
self[line_no].get_center()[1],
|
||||
0,
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
elif self.lines[1][line_no] == "left":
|
||||
self[line_no].move_to(
|
||||
|
|
@ -274,8 +274,8 @@ class OpenGLParagraph(OpenGLVGroup):
|
|||
self.get_left()[0] + self[line_no].width / 2,
|
||||
self[line_no].get_center()[1],
|
||||
0,
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ class OpenGLText(OpenGLSVGMobject):
|
|||
space.move_to(self.submobjects[submobjects_char_index].get_center())
|
||||
else:
|
||||
space.move_to(
|
||||
self.submobjects[submobjects_char_index - 1].get_center()
|
||||
self.submobjects[submobjects_char_index - 1].get_center(),
|
||||
)
|
||||
chars.add(space)
|
||||
else:
|
||||
|
|
@ -931,7 +931,7 @@ class OpenGLMarkupText(OpenGLSVGMobject):
|
|||
colormap = self.extract_color_tags()
|
||||
if len(colormap) > 0:
|
||||
logger.warning(
|
||||
'Using <color> tags in MarkupText is deprecated. Please use <span foreground="..."> instead.'
|
||||
'Using <color> tags in MarkupText is deprecated. Please use <span foreground="..."> instead.',
|
||||
)
|
||||
gradientmap = self.extract_gradient_tags()
|
||||
|
||||
|
|
@ -939,7 +939,7 @@ class OpenGLMarkupText(OpenGLSVGMobject):
|
|||
raise ValueError(
|
||||
f"Pango cannot parse your markup in {self.text}. "
|
||||
"Please check for typos, unmatched tags or unescaped "
|
||||
"special chars like < and &."
|
||||
"special chars like < and &.",
|
||||
)
|
||||
|
||||
if self.line_spacing == -1:
|
||||
|
|
@ -1095,7 +1095,7 @@ class OpenGLMarkupText(OpenGLSVGMobject):
|
|||
"to": tag.group(2),
|
||||
"start_offset": start_offset,
|
||||
"end_offset": end_offset,
|
||||
}
|
||||
},
|
||||
)
|
||||
self.text = re.sub("<gradient[^>]+>(.+?)</gradient>", r"\1", self.text, 0, re.S)
|
||||
return gradientmap
|
||||
|
|
@ -1137,7 +1137,7 @@ class OpenGLMarkupText(OpenGLSVGMobject):
|
|||
"color": tag.group(1),
|
||||
"start_offset": start_offset,
|
||||
"end_offset": end_offset,
|
||||
}
|
||||
},
|
||||
)
|
||||
self.text = re.sub("<color[^>]+>(.+?)</color>", r"\1", self.text, 0, re.S)
|
||||
return colormap
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ SVG_DEFAULT_ATTRIBUTES: Dict[str, str] = {
|
|||
|
||||
|
||||
def cascade_element_style(
|
||||
element: MinidomElement, inherited: Dict[str, str]
|
||||
element: MinidomElement,
|
||||
inherited: Dict[str, str],
|
||||
) -> Dict[str, str]:
|
||||
"""Collect the element's style attributes based upon both its inheritance and its own attributes.
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
class Sample(Scene):
|
||||
def construct(self):
|
||||
self.play(FadeIn(SVGMobject("manim-logo-sidebar.svg")))
|
||||
|
||||
Parameters
|
||||
--------
|
||||
file_name : :class:`str`
|
||||
|
|
@ -183,7 +184,9 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
result += it.chain(
|
||||
*(
|
||||
self.get_mobjects_from(
|
||||
child, style, within_defs=within_defs or is_defs
|
||||
child,
|
||||
style,
|
||||
within_defs=within_defs or is_defs,
|
||||
)
|
||||
for child in element.childNodes
|
||||
)
|
||||
|
|
@ -272,12 +275,14 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
A float representing the attribute string value.
|
||||
"""
|
||||
stripped_attr = "".join(
|
||||
[char for char in attr if char in string.digits + ".-e"]
|
||||
[char for char in attr if char in string.digits + ".-e"],
|
||||
)
|
||||
return float(stripped_attr)
|
||||
|
||||
def use_to_mobjects(
|
||||
self, use_element: MinidomElement, local_style: Dict
|
||||
self,
|
||||
use_element: MinidomElement,
|
||||
local_style: Dict,
|
||||
) -> List[VMobject]:
|
||||
"""Converts a SVG <use> element to a collection of VMobjects.
|
||||
|
||||
|
|
@ -543,7 +548,8 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
# TODO: handle rotate, skewX and skewY
|
||||
# for now adding a warning message
|
||||
logger.warning(
|
||||
"Handling of %s transform is not supported yet!", op_name
|
||||
"Handling of %s transform is not supported yet!",
|
||||
op_name,
|
||||
)
|
||||
|
||||
def flatten(self, input_list):
|
||||
|
|
|
|||
|
|
@ -121,7 +121,15 @@ def elliptical_arc_to_cubic_bezier(x1, y1, rx, ry, phi, fA, fS, x2, y2):
|
|||
|
||||
# Convert from endpoint to center parameterization.
|
||||
cx, cy, theta1, dtheta = get_elliptical_arc_center_parameters(
|
||||
x1, y1, rx, ry, phi, fA, fS, x2, y2
|
||||
x1,
|
||||
y1,
|
||||
rx,
|
||||
ry,
|
||||
phi,
|
||||
fA,
|
||||
fS,
|
||||
x2,
|
||||
y2,
|
||||
)
|
||||
|
||||
# For a given arc we should "chop" it up into segments if it is too big
|
||||
|
|
@ -257,7 +265,7 @@ class SVGPathMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
zip(
|
||||
re.findall(pattern, self.path_string),
|
||||
re.split(pattern, self.path_string)[1:],
|
||||
)
|
||||
),
|
||||
)
|
||||
# Which mobject should new points be added to
|
||||
prev_command = None
|
||||
|
|
@ -291,7 +299,10 @@ class SVGPathMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
|
||||
# Produce the (absolute) coordinates of the controls and handles
|
||||
new_points = self.string_to_points(
|
||||
command, is_relative, coord_string, start_point
|
||||
command,
|
||||
is_relative,
|
||||
coord_string,
|
||||
start_point,
|
||||
)
|
||||
|
||||
if command == "M": # moveto
|
||||
|
|
@ -322,7 +333,9 @@ class SVGPathMobject(VMobject, metaclass=ConvertToOpenGL):
|
|||
for i in range(0, len(new_points), 2):
|
||||
new_handle = 2 * start_point - prev_handle
|
||||
self.add_cubic_bezier_curve_to(
|
||||
new_handle, new_points[i], new_points[i + 1]
|
||||
new_handle,
|
||||
new_points[i],
|
||||
new_points[i + 1],
|
||||
)
|
||||
start_point = new_points[i + 1]
|
||||
prev_handle = new_points[i]
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue