Skip to content

Fix transformable label todo #4377

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 3 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
5 changes: 1 addition & 4 deletions manim/mobject/mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -3288,10 +3288,7 @@ def build(self) -> Animation:
_MethodAnimation,
)

if self.overridden_animation:
anim = self.overridden_animation
else:
anim = _MethodAnimation(self.mobject, self.methods)
anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods)

for attr, value in self.anim_args.items():
setattr(anim, attr, value)
Expand Down
5 changes: 1 addition & 4 deletions manim/mobject/opengl/opengl_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -2993,10 +2993,7 @@ def update_target(*method_args, **method_kwargs):
def build(self) -> _MethodAnimation:
from manim.animation.transform import _MethodAnimation

if self.overridden_animation:
anim = self.overridden_animation
else:
anim = _MethodAnimation(self.mobject, self.methods)
anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods)

for attr, value in self.anim_args.items():
setattr(anim, attr, value)
Expand Down
132 changes: 110 additions & 22 deletions manim/scene/vector_space_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,48 @@
Z_COLOR = BLUE_D


# Type definition for transformable labels
class TransformableLabel(MathTex):
"""A MathTex object with additional attributes for transformation tracking."""

target_text: str | MathTex
vector: Vector
original_kwargs: dict[str, Any]
transformation_name: str | MathTex
target: Mobject | None

def __init__(
self,
base_tex: str,
vector: Vector,
transformation_name: str | MathTex = "L",
new_label: str | MathTex | None = None,
**kwargs: Any,
):
# Clean kwargs for MathTex constructor
cleaned_kwargs = kwargs.copy()
if "animate" in cleaned_kwargs:
cleaned_kwargs.pop("animate")

super().__init__(base_tex, **cleaned_kwargs)

self.vector = vector
self.original_kwargs = kwargs # Store original for reference
self.transformation_name = transformation_name

# Process target text
if new_label is not None:
self.target_text = new_label
else:
# Handle MathTex transformation names
trans_str = (
transformation_name.get_tex_string()
if isinstance(transformation_name, MathTex)
else str(transformation_name)
)
self.target_text = f"{trans_str}({base_tex})"


# TODO: Much of this scene type seems dependent on the coordinate system chosen.
# That is, being centered at the origin with grid units corresponding to the
# arbitrary space units. Change it!
Expand Down Expand Up @@ -399,7 +441,29 @@ def position_x_coordinate(
x_coord: MathTex,
x_line: Line,
vector: Vector3DLike,
) -> MathTex: # TODO Write DocStrings for this.
) -> MathTex:
"""
Positions and styles the x-axis coordinate label relative to its projection line.

This will place `x_coord` just above or below `x_line` depending on the
sign of the y-component of the original vector, and color it with X_COLOR.

Parameters
----------
x_coord : MathTex
The coordinate label to position (e.g. “x” or “3”).
x_line : Line
The line segment representing the x-projection of the vector.
vector : Vector3DLike
The 3D vector whose x-projection is being labeled. Used only for
determining whether to place the label above (positive y) or
below (negative y) the projection line.

Returns
-------
MathTex
The same `x_coord` object, moved into place and colored.
"""
x_coord.next_to(x_line, -np.sign(vector[1]) * UP)
x_coord.set_color(X_COLOR)
return x_coord
Expand All @@ -409,7 +473,29 @@ def position_y_coordinate(
y_coord: MathTex,
y_line: Line,
vector: Vector3DLike,
) -> MathTex: # TODO Write DocStrings for this.
) -> MathTex:
"""
Positions and styles the y-axis coordinate label relative to its projection line.

This will place `y_coord` just to the left or right of `y_line` depending on the
sign of the x-component of the original vector, and color it with Y_COLOR.

Parameters
----------
y_coord : MathTex
The coordinate label to position (e.g. “y” or “5”).
y_line : Line
The line segment representing the y-projection of the vector.
vector : Vector3DLike
The 3D vector whose y-projection is being labeled. Used only for
determining whether to place the label to the right (positive x) or
left (negative x) of the projection line.

Returns
-------
MathTex
The same `y_coord` object, moved into place and colored.
"""
y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT)
y_coord.set_color(Y_COLOR)
return y_coord
Expand Down Expand Up @@ -697,7 +783,7 @@ def setup(self) -> None:
self.foreground_mobjects: list[Mobject] = []
self.transformable_mobjects: list[Mobject] = []
self.moving_vectors: list[Mobject] = []
self.transformable_labels: list[MathTex] = []
self.transformable_labels: list[TransformableLabel] = []
self.moving_mobjects: list[Mobject] = []

self.background_plane = NumberPlane(**self.background_plane_kwargs)
Expand Down Expand Up @@ -936,7 +1022,7 @@ def add_transformable_label(
transformation_name: str | MathTex = "L",
new_label: str | MathTex | None = None,
**kwargs: Any,
) -> MathTex:
) -> TransformableLabel:
"""
Method for creating, and animating the addition of
a transformable label for the vector.
Expand All @@ -960,23 +1046,25 @@ def add_transformable_label(

Returns
-------
:class:`~.MathTex`
The MathTex of the label.
:class:`~.TransformableLabel`
The TransformableLabel of the label.
"""
# TODO: Clear up types in this function. This is currently a mess.
label_mob = self.label_vector(vector, label, **kwargs)
if new_label:
label_mob.target_text = new_label # type: ignore[attr-defined]
else:
label_mob.target_text = ( # type: ignore[attr-defined]
f"{transformation_name}({label_mob.get_tex_string()})"
)
label_mob.vector = vector # type: ignore[attr-defined]
label_mob.kwargs = kwargs # type: ignore[attr-defined]
if "animate" in label_mob.kwargs: # type: ignore[attr-defined]
label_mob.kwargs.pop("animate") # type: ignore[attr-defined]
base_label = label if isinstance(label, MathTex) else MathTex(label)

# Create transformable label
label_mob = TransformableLabel(
base_tex=base_label.get_tex_string(),
vector=vector,
transformation_name=transformation_name,
new_label=new_label,
**kwargs,
)

# Position label and register
self.add(label_mob)
self.transformable_labels.append(label_mob)
return cast(MathTex, label_mob)

return label_mob

def add_title(
self,
Expand Down Expand Up @@ -1143,11 +1231,11 @@ def get_transformable_label_movement(self) -> Transform:
for label in self.transformable_labels:
# TODO: This location and lines 933 and 335 are the only locations in
# the code where the target_text property is referenced.
target_text: MathTex | str = label.target_text # type: ignore[assignment]
target_text: MathTex | str = label.target_text
label.target = self.get_vector_label(
label.vector.target, # type: ignore[attr-defined]
label.vector.target,
target_text,
**label.kwargs, # type: ignore[arg-type]
**label.original_kwargs,
)
return self.get_piece_movement(self.transformable_labels)

Expand Down
Loading