Skip to content

Commit fdb4e37

Browse files
JasonGrace2282pre-commit-ci[bot]chopan050
authored
docs(contributing): add manim.typing guide (#3669)
* docs: add manim.typing guide * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add colors * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add another example for when to typehint as Vector * Add docs for images+functions * write Beziers * Improve based on feedback * type -> Type --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Francisco Manríquez Novoa <49853152+chopan050@users.noreply.github.com>
1 parent 89d5ed4 commit fdb4e37

File tree

3 files changed

+138
-3
lines changed

3 files changed

+138
-3
lines changed

docs/source/contributing/docs.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,4 @@ Index
8181
docs/examples
8282
docs/references
8383
docs/typings
84+
docs/types
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
===================
2+
Choosing Type Hints
3+
===================
4+
In order to provide the best user experience,
5+
it's important that type hints are chosen correctly.
6+
With the large variety of types provided by Manim, choosing
7+
which one to use can be difficult. This guide aims to
8+
aid you in the process of choosing the right type for the scenario.
9+
10+
11+
The first step is figuring out which category your type hint fits into.
12+
13+
Coordinates
14+
-----------
15+
Coordinates encompass two main categories: points, and vectors.
16+
17+
18+
Points
19+
~~~~~~
20+
The purpose of points is pretty straightforward: they represent a point
21+
in space. For example:
22+
23+
.. code-block:: python
24+
25+
def status2D(coord: Point2D) -> None:
26+
x, y = coord
27+
print(f"Point at {x=},{y=}")
28+
29+
30+
def status3D(coord: Point3D) -> None:
31+
x, y, z = coord
32+
print(f"Point at {x=},{y=},{z=}")
33+
34+
35+
def get_statuses(coords: Point2D_Array | Point3D_Array) -> None:
36+
for coord in coords:
37+
if len(coord) == 2:
38+
# it's a Point2D
39+
status2D(coord)
40+
else:
41+
# it's a point3D
42+
status3D(coord)
43+
44+
It's important to realize that the status functions accepted both
45+
tuples/lists of the correct length, and ``NDArray``'s of the correct shape.
46+
If they only accepted ``NDArray``'s, we would use their ``Internal`` counterparts:
47+
:class:`~.typing.InternalPoint2D`, :class:`~.typing.InternalPoint3D`, :class:`~.typing.InternalPoint2D_Array` and :class:`~.typing.InternalPoint3D_Array`.
48+
49+
In general, the type aliases prefixed with ``Internal`` should never be used on
50+
user-facing classes and functions, but should be reserved for internal behavior.
51+
52+
Vectors
53+
~~~~~~~
54+
Vectors share many similarities to points. However, they have a different
55+
connotation. Vectors should be used to represent direction. For example,
56+
consider this slightly contrived function:
57+
58+
.. code-block:: python
59+
60+
def shift_mobject(mob: Mobject, direction: Vector3D, scale_factor: float = 1) -> mob:
61+
return mob.shift(direction * scale_factor)
62+
63+
Here we see an important example of the difference. ``direction`` can not, and
64+
should not, be typed as a :class:`~.typing.Point3D` because the function does not accept tuples/lists,
65+
like ``direction=(0, 1, 0)``. You could type it as :class:`~.typing.InternalPoint3D` and
66+
the type checker and linter would be happy; however, this makes the code harder
67+
to understand.
68+
69+
As a general rule, if a parameter is called ``direction`` or ``axis``,
70+
it should be type hinted as some form of :class:`~.VectorND`.
71+
72+
.. warning::
73+
74+
This is not always true. For example, as of Manim 0.18.0, the direction
75+
parameter of the :class:`.Vector` Mobject should be ``Point2D | Point3D``,
76+
as it can also accept ``tuple[float, float]`` and ``tuple[float, float, float]``.
77+
78+
Colors
79+
------
80+
The interface Manim provides for working with colors is :class:`.ManimColor`.
81+
The main color types Manim supports are RGB, RGBA, and HSV. You will want
82+
to add type hints to a function depending on which type it uses. If any color will work,
83+
you will need something like:
84+
85+
.. code-block:: python
86+
87+
if TYPE_CHECKING:
88+
from manim.utils.color import ParsableManimColor
89+
90+
# type hint stuff with ParsableManimColor
91+
92+
93+
94+
Béziers
95+
-------
96+
Manim internally represents a :class:`.Mobject` by a collection of points. In the case of :class:`.VMobject`,
97+
the most commonly used subclass of :class:`.Mobject`, these points represent Bézier curves,
98+
which are a way of representing a curve using a sequence of points.
99+
100+
.. note::
101+
102+
To learn more about Béziers, take a look at https://pomax.github.io/bezierinfo/
103+
104+
105+
Manim supports two different renderers, which each have different representations of
106+
Béziers: Cairo uses cubic Bézier curves, while OpenGL uses quadratic Bézier curves.
107+
108+
Type hints like :class:`~.typing.BezierPoints` represent a single bezier curve, and :class:`~.typing.BezierPath`
109+
represents multiple Bézier curves. A :class:`~.typing.Spline` is when the Bézier curves in a :class:`~.typing.BezierPath`
110+
forms a single connected curve. Manim also provides more specific type aliases when working with
111+
quadratic or cubic curves, and they are prefixed with their respective type (e.g. :class:`~.typing.CubicBezierPoints`,
112+
is a :class:`~.typing.BezierPoints` consisting of exactly 4 points representing a cubic Bézier curve).
113+
114+
115+
Functions
116+
---------
117+
Throughout the codebase, many different types of functions are used. The most obvious example
118+
is a rate function, which takes in a float and outputs a float (``Callable[[float], float]``).
119+
Another example is for overriding animations. One will often need to map a :class:`.Mobject`
120+
to an overridden :class:`.Animation`, and for that we have the :class:`~.typing.FunctionOverride` type hint.
121+
122+
:class:`~.typing.PathFuncType` and :class:`~.typing.MappingFunction` are more niche, but are related to moving objects
123+
along a path, or applying functions. If you need to use it, you'll know.
124+
125+
126+
Images
127+
------
128+
There are several representations of images in Manim. The most common is
129+
the representation as a NumPy array of floats representing the pixels of an image.
130+
This is especially common when it comes to the OpenGL renderer.
131+
132+
This is the use case of the :class:`~.typing.Image` type hint. Sometimes, Manim may use ``PIL.Image``,
133+
in which case one should use that type hint instead.
134+
Of course, if a more specific type of image is needed, it can be annotated as such.

docs/source/contributing/docs/typings.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
==============
2-
Adding Typings
3-
==============
1+
==================
2+
Typing Conventions
3+
==================
44

55
.. warning::
66
This section is still a work in progress.

0 commit comments

Comments
 (0)