Skip to content

Added type annotations to mobject/svg/brace.py #4309

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 42 additions & 31 deletions manim/mobject/svg/brace.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@

__all__ = ["Brace", "BraceLabel", "ArcBrace", "BraceText", "BraceBetweenPoints"]

from collections.abc import Sequence
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

import numpy as np
import svgelements as se
from typing_extensions import Self

from manim._config import config
from manim.mobject.geometry.arc import Arc
from manim.mobject.geometry.line import Line
from manim.mobject.mobject import Mobject
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
from manim.mobject.text.tex_mobject import MathTex, Tex
from manim.mobject.text.tex_mobject import MathTex, SingleStringMathTex, Tex
from manim.mobject.text.text_mobject import Text

from ...animation.animation import Animation
from ...animation.composition import AnimationGroup
from ...animation.fading import FadeIn
from ...animation.growing import GrowFromCenter
Expand All @@ -26,11 +28,9 @@
from ..svg.svg_mobject import VMobjectFromSVGPath

if TYPE_CHECKING:
from manim.typing import Point3DLike, Vector3D
from manim.typing import Point3D, Point3DLike, Vector3D
from manim.utils.color.core import ParsableManimColor

__all__ = ["Brace", "BraceBetweenPoints", "BraceLabel", "ArcBrace"]


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change the value of the __all__ variable. This line made it impossible to use the BraceText object.

class Brace(VMobjectFromSVGPath):
"""Takes a mobject and draws a brace adjacent to it.
Expand Down Expand Up @@ -70,14 +70,14 @@ def construct(self):
def __init__(
self,
mobject: Mobject,
direction: Vector3D | None = DOWN,
direction: Point3DLike = DOWN,
buff: float = 0.2,
sharpness: float = 2,
stroke_width: float = 0,
fill_opacity: float = 1.0,
background_stroke_width: float = 0,
background_stroke_color: ParsableManimColor = BLACK,
**kwargs,
**kwargs: Any,
):
path_string_template = (
"m0.01216 0c-0.01152 0-0.01216 6.103e-4 -0.01216 0.01311v0.007762c0.06776 "
Expand Down Expand Up @@ -130,7 +130,7 @@ def __init__(
for mob in mobject, self:
mob.rotate(angle, about_point=ORIGIN)

def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs):
def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs: Any) -> Self:
"""Puts the given mobject at the brace tip.

Parameters
Expand All @@ -153,7 +153,7 @@ def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs):
mob.shift(self.get_direction() * shift_distance)
return self

def get_text(self, *text, **kwargs):
def get_text(self, *text: str, **kwargs: Any) -> Tex:
"""Places the text at the brace tip.

Parameters
Expand All @@ -172,7 +172,7 @@ def get_text(self, *text, **kwargs):
self.put_at_tip(text_mob, **kwargs)
return text_mob

def get_tex(self, *tex, **kwargs):
def get_tex(self, *tex: str, **kwargs: Any) -> MathTex:
"""Places the tex at the brace tip.

Parameters
Expand All @@ -191,15 +191,15 @@ def get_tex(self, *tex, **kwargs):
self.put_at_tip(tex_mob, **kwargs)
return tex_mob

def get_tip(self):
def get_tip(self) -> Point3D:
"""Returns the point at the brace tip."""
# Returns the position of the seventh point in the path, which is the tip.
if config["renderer"] == "opengl":
return self.points[34]

return self.points[28] # = 7*4

def get_direction(self):
def get_direction(self) -> Vector3D:
"""Returns the direction from the center to the brace tip."""
vect = self.get_tip() - self.get_center()
return vect / np.linalg.norm(vect)
Expand Down Expand Up @@ -233,12 +233,12 @@ def __init__(
self,
obj: Mobject,
text: str,
brace_direction: np.ndarray = DOWN,
label_constructor: type = MathTex,
brace_direction: Point3DLike = DOWN,
label_constructor: type[SingleStringMathTex | Text] = MathTex,
font_size: float = DEFAULT_FONT_SIZE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label_constructor above could be typed as type[SingleStringMathTex | Text] to allow passing both TeX and Cairo-rendered texts. SingleStringMathTex is the parent of MathTex, which is the parent of Tex, which is the parent of BulletedList and Title.

Plus, the brace_direction could be typed as Point3DLike (in the future, Vector3DLike).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the type of label_constructor raises this error

manim/mobject/svg/brace.py:279: error: Argument 1 to "SingleStringMathTex" has incompatible type "*tuple[str, ...]"; expected "float"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "SingleStringMathTex" has incompatible type "*tuple[str, ...]"; expected "bool"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "SingleStringMathTex" has incompatible type "*tuple[str, ...]"; expected "float | None"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "SingleStringMathTex" has incompatible type "*tuple[str, ...]"; expected "TexTemplate | None"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "float"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "dict[str, str]"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "dict[str, tuple[Any, ...]]"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "tuple[Any, ...]"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "int"  [arg-type]
manim/mobject/svg/brace.py:279: error: Argument 1 to "Text" has incompatible type "*tuple[str, ...]"; expected "bool"  [arg-type]

buff: float = 0.2,
brace_config: dict | None = None,
**kwargs,
brace_config: dict[str, Any] | None = None,
**kwargs: Any,
):
self.label_constructor = label_constructor
super().__init__(**kwargs)
Expand All @@ -249,37 +249,48 @@ def __init__(
self.brace = Brace(obj, brace_direction, buff, **brace_config)

if isinstance(text, (tuple, list)):
self.label = self.label_constructor(*text, font_size=font_size, **kwargs)
self.label: VMobject = self.label_constructor(
*text, font_size=font_size, **kwargs
)
else:
self.label = self.label_constructor(str(text), font_size=font_size)

self.brace.put_at_tip(self.label)
self.add(self.brace, self.label)

def creation_anim(self, label_anim=FadeIn, brace_anim=GrowFromCenter):
def creation_anim(
self,
label_anim: type[Animation] = FadeIn,
brace_anim: type[Animation] = GrowFromCenter,
) -> AnimationGroup:
return AnimationGroup(brace_anim(self.brace), label_anim(self.label))

def shift_brace(self, obj, **kwargs):
def shift_brace(self, obj: Mobject, **kwargs: Any) -> Self:
if isinstance(obj, list):
obj = self.get_group_class()(*obj)
self.brace = Brace(obj, self.brace_direction, **kwargs)
self.brace.put_at_tip(self.label)
return self

def change_label(self, *text, **kwargs):
self.label = self.label_constructor(*text, **kwargs)

def change_label(self, *text: str, **kwargs: Any) -> Self:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created this small example to demonstrate the use of the change_label method, but apparently calling the method has no effect on the generated output.

from manim import *

class BraceExample(Scene):
    def construct(self):
        s1 = Square().move_to(2*LEFT)
        self.add(s1)
        br1 = BraceText(s1, "Label")
        self.add(br1)

        s2 = Square().move_to(2*RIGHT)
        self.add(s2)
        br2 = BraceText(s2, "Label")

        # I would expect this line to change the label
        # of the br2 brace to "new". But this is not seen 
        # in the output.
        br2.change_label("new")
        self.add(br2)

self.label = self.label_constructor(*text, **kwargs) # type: ignore[arg-type]
self.brace.put_at_tip(self.label)
return self

def change_brace_label(self, obj, *text, **kwargs):
def change_brace_label(self, obj: Mobject, *text: str, **kwargs: Any) -> Self:
self.shift_brace(obj)
self.change_label(*text, **kwargs)
return self


class BraceText(BraceLabel):
def __init__(self, obj, text, label_constructor=Tex, **kwargs):
def __init__(
self,
obj: Mobject,
text: str,
label_constructor: type[SingleStringMathTex | Text] = Text,
**kwargs: Any,
):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that the default label_constructor should be Text.

super().__init__(obj, text, label_constructor=label_constructor, **kwargs)


Expand Down Expand Up @@ -317,10 +328,10 @@ def construct(self):

def __init__(
self,
point_1: Point3DLike | None,
point_2: Point3DLike | None,
direction: Vector3D | None = ORIGIN,
**kwargs,
point_1: Point3DLike,
point_2: Point3DLike,
direction: Point3DLike = ORIGIN,
**kwargs: Any,
):
if all(direction == ORIGIN):
line_vector = np.array(point_2) - np.array(point_1)
Expand Down Expand Up @@ -386,8 +397,8 @@ def construct(self):
def __init__(
self,
arc: Arc | None = None,
direction: Sequence[float] = RIGHT,
**kwargs,
direction: Point3DLike = RIGHT,
**kwargs: Any,
):
if arc is None:
arc = Arc(start_angle=-1, angle=2, radius=1)
Expand Down
7 changes: 6 additions & 1 deletion manim/mobject/text/tex_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from collections.abc import Iterable
from functools import reduce
from textwrap import dedent
from typing import Any

from manim import config, logger
from manim.constants import *
Expand Down Expand Up @@ -447,7 +448,11 @@ class Tex(MathTex):
"""

def __init__(
self, *tex_strings, arg_separator="", tex_environment="center", **kwargs
self,
*tex_strings: str,
arg_separator: str = "",
tex_environment: str = "center",
**kwargs: Any,
):
super().__init__(
*tex_strings,
Expand Down
3 changes: 0 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ ignore_errors = True
[mypy-manim.mobject.opengl.opengl_vectorized_mobject]
ignore_errors = True

[mypy-manim.mobject.svg.brace]
ignore_errors = True

[mypy-manim.mobject.svg.svg_mobject]
ignore_errors = True

Expand Down