Merge branch 'main' of https://github.com/ManimCommunity/manim into experimental

This commit is contained in:
JasonGrace2282 2024-09-01 14:50:45 -04:00
commit 793e853ae8
No known key found for this signature in database
GPG key ID: 8D61FE3F93FB15FA
64 changed files with 185 additions and 374 deletions

View file

@ -12,11 +12,6 @@ repos:
- id: end-of-file-fixer
- id: check-toml
name: Validate Poetry
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: python-check-blanket-noqa
name: Precision flake ignores
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.2
hooks:
@ -26,17 +21,6 @@ repos:
args: [--exit-non-zero-on-fix]
- id: ruff-format
types: [python]
- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
hooks:
- id: flake8
additional_dependencies:
[
flake8-docstrings==1.6.0,
flake8-pytest-style==1.5.0,
flake8-rst-docstrings==0.2.3,
flake8-simplify==0.14.1,
]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
hooks:

View file

@ -23,7 +23,8 @@ def FrenchCursive(*tex_strings, **kwargs):
class TexFontTemplateManual(Scene):
"""An example scene that uses a manually defined TexTemplate() object to create
LaTeX output in French Cursive font"""
LaTeX output in French Cursive font
"""
def construct(self):
self.add(Tex("Tex Font Example").to_edge(UL))

View file

@ -2,7 +2,7 @@ from pathlib import Path
import manim.utils.opengl as opengl
from manim import *
from manim.opengl import * # type: ignore
from manim.opengl import *
# Copied from https://3b1b.github.io/manim/getting_started/example_scenes.html#surfaceexample.
# Lines that do not yet work with the Community Version are commented.

View file

@ -323,7 +323,6 @@ class ManimConfig(MutableMapping):
def _warn_about_config_options(self) -> None:
"""Warns about incorrect config options, or permutations of config options."""
logger = logging.getLogger("manim")
if self.format == "webm":
logger.warning(
@ -385,7 +384,6 @@ class ManimConfig(MutableMapping):
:meth:`~ManimConfig.digest_parser`
"""
if isinstance(obj, ManimConfig):
self._d.update(obj._d)
if obj.tex_template:

View file

@ -623,7 +623,6 @@ def override_animation(
self.play(FadeIn(MySquare()))
"""
_F = TypeVar("_F", bound=Callable)
def decorator(func: _F) -> _F:

View file

@ -98,7 +98,7 @@ class _Fade(Transform):
class FadeIn(_Fade):
"""Fade in :class:`~.OpenGLMobject` s.
r"""Fade in :class:`~.OpenGLMobject` s.
Parameters
----------
@ -123,7 +123,7 @@ class FadeIn(_Fade):
dot = Dot(UP * 2 + LEFT)
self.add(dot)
tex = Tex(
"FadeIn with ", "shift ", " or target\\_position", " and scale"
"FadeIn with ", "shift ", r" or target\_position", " and scale"
).scale(1)
animations = [
FadeIn(tex[0]),
@ -146,7 +146,7 @@ class FadeIn(_Fade):
class FadeOut(_Fade):
"""Fade out :class:`~.OpenGLMobject` s.
r"""Fade out :class:`~.OpenGLMobject` s.
Parameters
----------

View file

@ -269,7 +269,7 @@ class Flash(AnimationGroup):
class ShowPassingFlash(ShowPartial):
"""Show only a sliver of the VMobject each frame.
r"""Show only a sliver of the VMobject each frame.
Parameters
----------
@ -289,7 +289,7 @@ class ShowPassingFlash(ShowPartial):
self.add(p, lbl)
p = p.copy().set_color(BLUE)
for time_width in [0.2, 0.5, 1, 2]:
lbl.become(Tex(r"\\texttt{time\\_width={{%.1f}}}"%time_width))
lbl.become(Tex(r"\texttt{time\_width={{%.1f}}}"%time_width))
self.play(ShowPassingFlash(
p.copy().set_color(BLUE),
run_time=2,
@ -554,7 +554,7 @@ class Wiggle(Animation):
# TODO: get rid of this if condition madness
class Circumscribe(Succession):
"""Draw a temporary line surrounding the mobject.
r"""Draw a temporary line surrounding the mobject.
Parameters
----------
@ -585,7 +585,7 @@ class Circumscribe(Succession):
class UsingCircumscribe(Scene):
def construct(self):
lbl = Tex(r"Circum-\\\\scribe").scale(2)
lbl = Tex(r"Circum-\\scribe").scale(2)
self.add(lbl)
self.play(Circumscribe(lbl))
self.play(Circumscribe(lbl, Circle))

View file

@ -91,9 +91,7 @@ class ComplexHomotopy(Homotopy):
def __init__(
self, complex_homotopy: Callable[[complex], float], mobject: Mobject, **kwargs
) -> None:
"""
Complex Homotopy a function Cx[0, 1] to C
"""
"""Complex Homotopy a function Cx[0, 1] to C"""
def homotopy(
x: float,

View file

@ -294,9 +294,7 @@ class ReplacementTransform(Transform):
class TransformFromCopy(Transform):
"""
Performs a reversed Transform
"""
"""Performs a reversed Transform"""
def __init__(
self, mobject: OpenGLMobject, target_mobject: OpenGLMobject, **kwargs

View file

@ -41,13 +41,6 @@ class Camera(OpenGLMobject):
def get_orientation(self):
return Rotation.from_quat(self.orientation)
def to_default_state(self):
self.center()
self.set_height(config.frame_width)
self.set_width(config.frame_height)
self.set_orientation(Rotation.identity())
return self
def get_euler_angles(self):
return self.get_orientation().as_euler("zxz")[::-1]
@ -63,8 +56,8 @@ class Camera(OpenGLMobject):
def get_inverse_camera_rotation_matrix(self):
return self.get_orientation().as_matrix().T
def rotate(self, angle: float, axis: np.ndarray = OUT, **kwargs): # type: ignore
rot = Rotation.from_rotvec(axis * normalize(axis)) # type: ignore
def rotate(self, angle: float, axis: np.ndarray = OUT, **kwargs):
rot = Rotation.from_rotvec(axis * normalize(axis))
self.set_orientation(rot * self.get_orientation())
def set_euler_angles(

View file

@ -1,5 +1,6 @@
"""Auxiliary module for the checkhealth subcommand, contains
the actual check implementations."""
the actual check implementations.
"""
from __future__ import annotations

View file

@ -42,7 +42,7 @@ __all__ = ["render"]
@cloup.argument("scene_names", required=False, nargs=-1)
@global_options
@output_options
@render_options # type: ignore
@render_options
@ease_of_access_options
def render(
**args,
@ -53,7 +53,6 @@ def render(
SCENES is an optional list of scenes in the file.
"""
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.",

View file

@ -74,7 +74,7 @@ render_options = option_group(
"--quality",
default=None,
type=Choice(
list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])), # type: ignore
reversed([q["flag"] for q in QUALITIES.values() if q["flag"]]), # type: ignore[arg-type]
case_sensitive=False,
),
help="Render quality at the follow resolution framerates, respectively: "

View file

@ -1,6 +1,4 @@
"""
Constant definitions.
"""
"""Constant definitions."""
from __future__ import annotations

View file

@ -246,15 +246,11 @@ class FileWriter(FileWriterProtocol):
# Sound
def init_audio(self) -> None:
"""
Preps the writer for adding audio to the movie.
"""
"""Preps the writer for adding audio to the movie."""
self.includes_sound = False
def create_audio_segment(self) -> None:
"""
Creates an empty, silent, Audio Segment.
"""
"""Creates an empty, silent, Audio Segment."""
self.audio_segment = AudioSegment.silent()
def add_audio_segment(
@ -390,9 +386,7 @@ class FileWriter(FileWriterProtocol):
self.num_plays += 1
def listen_and_write(self) -> None:
"""
For internal use only: blocks until new frame is available on the queue.
"""
"""For internal use only: blocks until new frame is available on the queue."""
while True:
num_frames, frame_data = self.queue.get()
if frame_data is None:
@ -794,7 +788,6 @@ class FileWriter(FileWriterProtocol):
def combine_to_section_videos(self) -> None:
"""Concatenate partial movie files for each section."""
self.finish_last_section()
sections_index: list[dict[str, Any]] = []
for section in self.sections:
@ -855,6 +848,5 @@ class FileWriter(FileWriterProtocol):
def print_file_ready_message(self, file_path: str | Path) -> None:
"""Prints the "File Ready" message to STDOUT."""
config.output_file = str(file_path)
logger.info(f"\nFile ready at {str(file_path)!r}\n")

View file

@ -129,7 +129,6 @@ class Manager(Generic[Scene_co]):
def setup(self) -> None:
"""Set up processes and manager"""
self.scene.setup()
# these are used for making sure it feels like the correct
@ -212,7 +211,6 @@ class Manager(Generic[Scene_co]):
def tear_down(self) -> None:
"""Tear down the scene and the window."""
self.scene.tear_down()
if self.window is not None:
@ -221,7 +219,6 @@ class Manager(Generic[Scene_co]):
def _interact(self) -> None:
"""Live interaction with the Window"""
if self.window is None:
return
logger.info(
@ -272,7 +269,6 @@ class Manager(Generic[Scene_co]):
slow the window down for the correct amount of time, such
as during a wait animation.
"""
if self.window is None:
return
@ -294,7 +290,6 @@ class Manager(Generic[Scene_co]):
def _play(self, *animations: AnimationProtocol) -> None:
"""Play a bunch of animations"""
self.scene.pre_play()
if self.window is not None:
@ -347,7 +342,6 @@ class Manager(Generic[Scene_co]):
self, total: float, description: str, **kwargs: Any
) -> contextlib.AbstractContextManager[ProgressBarProtocol]:
"""Create a progressbar"""
if not config.progress_bar:
return contextlib.nullcontext(NullProgressBar())
@ -450,7 +444,6 @@ class Manager(Generic[Scene_co]):
:meth:`.FileWriter.add_partial_movie_file` have not been called. Do NOT
use this to write a single frame!
"""
self.renderer.render(state)
should_write = write_frame if write_frame is not None else self._write_files
@ -459,14 +452,12 @@ class Manager(Generic[Scene_co]):
def write_frame(self) -> None:
"""Take a frame from the renderer and write it in the file writer."""
frame = self.renderer.get_pixels()
self.file_writer.write_frame(frame)
def _calc_time_progression(run_time: float) -> npt.NDArray[np.float64]:
"""Compute the time values at which to evaluate the animation"""
return np.arange(0, run_time, 1 / config.frame_rate)

View file

@ -24,7 +24,6 @@ class ScreenRectangle(Rectangle):
When set, the width is stretched to accommodate
the new aspect ratio.
"""
return self.width / self.height
@aspect_ratio.setter

View file

@ -247,7 +247,8 @@ class TipableVMobject(VMobject, metaclass=ConvertToOpenGL):
def get_tip(self):
"""Returns the TipableVMobject instance's (first) tip,
otherwise throws an exception."""
otherwise throws an exception.
"""
tips = self.get_tips()
if len(tips) == 0:
raise Exception("tip not found")
@ -572,7 +573,6 @@ class Circle(Arc):
group = Group(group1, group2, group3).arrange(buff=1)
self.add(group)
"""
# Ignores dim_to_match and stretch; result will always be a circle
# TODO: Perhaps create an ellipse class to handle single-dimension stretching
@ -612,7 +612,6 @@ class Circle(Arc):
self.add(circle, s1, s2)
"""
start_angle = angle_of_vector(self.points[0] - self.get_center())
proportion = (angle - start_angle) / TAU
proportion -= np.floor(proportion)

View file

@ -197,7 +197,6 @@ class Line(TipableVMobject):
point
The point to which the line is projected.
"""
start = self.get_start()
end = self.get_end()
unit_vect = normalize(end - start)
@ -283,7 +282,6 @@ class DashedLine(Line):
>>> DashedLine()._calculate_num_dashes()
20
"""
# Minimum number of dashes has to be 2
return max(
2,
@ -300,7 +298,6 @@ class DashedLine(Line):
>>> DashedLine().get_start()
array([-1., 0., 0.])
"""
if len(self.submobjects) > 0:
return self.submobjects[0].get_start()
else:
@ -316,7 +313,6 @@ class DashedLine(Line):
>>> DashedLine().get_end()
array([1., 0., 0.])
"""
if len(self.submobjects) > 0:
return self.submobjects[-1].get_end()
else:
@ -332,7 +328,6 @@ class DashedLine(Line):
>>> DashedLine().get_first_handle()
array([-0.98333333, 0. , 0. ])
"""
return self.submobjects[0].points[1]
def get_last_handle(self) -> Point3D:
@ -345,7 +340,6 @@ class DashedLine(Line):
>>> DashedLine().get_last_handle()
array([0.98333333, 0. , 0. ])
"""
return self.submobjects[-1].points[-2]
@ -606,7 +600,6 @@ class Arrow(Line):
>>> np.round(Arrow().get_normal_vector()) + 0. # add 0. to avoid negative 0 in output
array([ 0., 0., -1.])
"""
p0, p1, p2 = self.tip.get_start_anchors()[:3]
return normalize(np.cross(p2 - p1, p1 - p0))
@ -626,7 +619,6 @@ class Arrow(Line):
>>> Arrow().get_default_tip_length()
0.35
"""
max_ratio = self.max_tip_length_to_length_ratio
return min(self.tip_length, max_ratio * self.get_length())
@ -720,7 +712,6 @@ class Vector(Arrow):
self.add(plane, vec_1, vec_2, label_1, label_2)
"""
# avoiding circular imports
from ..matrix import Matrix
@ -1020,11 +1011,10 @@ class Angle(VMobject, metaclass=ConvertToOpenGL):
>>> angle.get_lines()
VGroup(Line, Line)
"""
return VGroup(*self.lines)
def get_value(self, degrees: bool = False) -> float:
"""Get the value of an angle of the :class:`Angle` class.
r"""Get the value of an angle of the :class:`Angle` class.
Parameters
----------
@ -1054,12 +1044,11 @@ class Angle(VMobject, metaclass=ConvertToOpenGL):
self.add(line1, line2, angle, value)
"""
return self.angle_value / DEGREES if degrees else self.angle_value
@staticmethod
def from_three_points(A: Point3D, B: Point3D, C: Point3D, **kwargs) -> Angle:
"""The angle between the lines AB and BC.
r"""The angle between the lines AB and BC.
This constructs the angle :math:`\\angle ABC`.

View file

@ -104,7 +104,6 @@ class Polygram(OpenGLVMobject):
[-1., -1., 0.],
[ 1., -1., 0.]])
"""
return self.get_start_anchors()
def get_vertex_groups(self) -> np.ndarray[Point3D_Array]:
@ -129,7 +128,6 @@ class Polygram(OpenGLVMobject):
[-1., 1., 0.],
[-2., 0., 0.]]])
"""
vertex_groups = []
group = []
@ -204,7 +202,6 @@ class Polygram(OpenGLVMobject):
shapes.arrange(RIGHT)
self.add(shapes)
"""
if radius == 0:
return self

View file

@ -334,7 +334,6 @@ class CoordinateSystem:
)
self.add(ax, y_label)
"""
return self._get_axis_label(
label, self.get_y_axis(), edge, direction, buff=buff, **kwargs
)
@ -367,7 +366,6 @@ class CoordinateSystem:
:class:`~.Mobject`
The positioned label along the given axis.
"""
label = self.x_axis._create_label_tex(label)
label.next_to(axis.get_edge_center(edge), direction=direction, buff=buff)
label.shift_onto_screen(buff=MED_SMALL_BUFF)
@ -421,7 +419,6 @@ class CoordinateSystem:
x_dict = dict(zip(x_pos, x_vals))
ax.add_coordinates(x_dict)
"""
self.coordinate_labels = VGroup()
# if nothing is passed to axes_numbers, produce axes with default labelling
if not axes_numbers:
@ -502,7 +499,6 @@ class CoordinateSystem:
:meth:`~.CoordinateSystem.get_vertical_line`
:meth:`~.CoordinateSystem.get_horizontal_line`
"""
line_config = line_config if line_config is not None else {}
if color is None:
@ -579,7 +575,6 @@ class CoordinateSystem:
self.add(ax, line, dot)
"""
return self.get_line_from_axis_to_point(1, point, **kwargs)
def get_lines_to_point(self, point: Sequence[float], **kwargs) -> VGroup:
@ -616,7 +611,6 @@ class CoordinateSystem:
lines_2 = ax.get_lines_to_point(circ.get_corner(DL), color=BLUE_B)
self.add(ax, lines_1, lines_2, circ)
"""
return VGroup(
self.get_horizontal_line(point, **kwargs),
self.get_vertical_line(point, **kwargs),
@ -709,7 +703,6 @@ class CoordinateSystem:
self.add(axes, curves)
"""
t_range = np.array(self.x_range, dtype=float)
if x_range is not None:
t_range[: len(x_range)] = x_range
@ -1036,7 +1029,6 @@ class CoordinateSystem:
self.add(ax, curve, sq)
"""
if hasattr(graph, "underlying_function"):
return graph.function(x)
else:
@ -1092,7 +1084,7 @@ class CoordinateSystem:
dot: bool = False,
dot_config: dict[str, Any] | None = None,
) -> Mobject:
"""Creates a properly positioned label for the passed graph, with an optional dot.
r"""Creates a properly positioned label for the passed graph, with an optional dot.
Parameters
----------
@ -1129,7 +1121,7 @@ class CoordinateSystem:
sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B)
label = ax.get_graph_label(
graph=sin,
label= MathTex(r"\\frac{\\pi}{2}"),
label= MathTex(r"\frac{\pi}{2}"),
x_val=PI / 2,
dot=True,
direction=UR,
@ -1137,7 +1129,6 @@ class CoordinateSystem:
self.add(ax, sin, label)
"""
if dot_config is None:
dot_config = {}
if color is None:
@ -1257,7 +1248,6 @@ class CoordinateSystem:
ax, bounding_line, quadratic, rects_right, rects_left, bounded_rects
)
"""
# setting up x_range, overwrite user's third input
if x_range is None:
if bounded_graph is None:
@ -1447,7 +1437,6 @@ class CoordinateSystem:
ax.angle_of_tangent(x=3, graph=curve)
# 1.4056476493802699
"""
p0 = np.array([*self.input_to_graph_coords(x, graph)])
p1 = np.array([*self.input_to_graph_coords(x + dx, graph)])
return angle_of_vector(p1 - p0)
@ -1479,7 +1468,6 @@ class CoordinateSystem:
ax.slope_of_tangent(x=-2, graph=curve)
# -3.5000000259052038
"""
return np.tan(self.angle_of_tangent(x, graph, **kwargs))
def plot_derivative_graph(
@ -1755,7 +1743,6 @@ class CoordinateSystem:
self.add(ax, curve, lines)
"""
x_range = x_range if x_range is not None else self.x_range
return VGroup(
@ -1817,7 +1804,6 @@ class CoordinateSystem:
t_label = axes.get_T_label(x_val=4, graph=func, label=Tex("x-value"))
self.add(axes, func, t_label)
"""
T_label_group = VGroup()
triangle = RegularPolygon(n=3, start_angle=np.pi / 2, stroke_width=0).set_fill(
color=triangle_color,
@ -2009,7 +1995,6 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
)
)
"""
for default_config, passed_config in zip(default_configs, passed_configs):
if passed_config is not None:
update_dict_recursively(default_config, passed_config)
@ -2254,7 +2239,6 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
)
self.add(ax, labels)
"""
self.axis_labels = VGroup(
self.get_x_axis_label(x_label),
self.get_y_axis_label(y_label),
@ -2542,7 +2526,6 @@ class ThreeDAxes(Axes):
self.set_camera_orientation(phi=2*PI/5, theta=PI/5)
self.add(ax, lab)
"""
positioned_label = self._get_axis_label(
label, self.get_y_axis(), edge, direction, buff=buff, **kwargs
)
@ -2593,7 +2576,6 @@ class ThreeDAxes(Axes):
self.set_camera_orientation(phi=2*PI/5, theta=PI/5)
self.add(ax, lab)
"""
positioned_label = self._get_axis_label(
label, self.get_z_axis(), edge, direction, buff=buff, **kwargs
)
@ -2647,7 +2629,6 @@ class ThreeDAxes(Axes):
)
self.add(axes, labels)
"""
self.axis_labels = VGroup(
self.get_x_axis_label(x_label),
self.get_y_axis_label(y_label),
@ -2871,7 +2852,6 @@ class NumberPlane(Axes):
The first (i.e the non-faded lines parallel to `axis_parallel_to`) and second
(i.e the faded lines parallel to `axis_parallel_to`) sets of lines, respectively.
"""
line = Line(axis_parallel_to.get_start(), axis_parallel_to.get_end())
if ratio_faded_lines == 0: # don't show faded lines
ratio_faded_lines = 1 # i.e. set ratio to 1
@ -3383,7 +3363,6 @@ class ComplexPlane(NumberPlane):
np.ndarray
The point on the plane.
"""
number = complex(number)
return self.coords_to_point(number.real, number.imag)
@ -3404,7 +3383,6 @@ class ComplexPlane(NumberPlane):
complex
A complex number consisting of real and imaginary components.
"""
x, y = self.point_to_coords(point)
return complex(x, y)
@ -3442,7 +3420,6 @@ class ComplexPlane(NumberPlane):
:class:`~.VGroup`
A :class:`~.VGroup` containing the positioned label mobjects.
"""
# TODO: Make this work the same as coord_sys.add_coordinates()
if len(numbers) == 0:
numbers = self._get_default_coordinate_values()
@ -3473,6 +3450,5 @@ class ComplexPlane(NumberPlane):
kwargs
Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`.
"""
self.add(self.get_coordinate_labels(*numbers, **kwargs))
return self

View file

@ -277,7 +277,8 @@ class NumberLine(Line):
def add_ticks(self):
"""Adds ticks to the number line. Ticks can be accessed after creation
via ``self.ticks``."""
via ``self.ticks``.
"""
ticks = VGroup()
elongated_tick_size = self.tick_size * self.longer_tick_multiple
elongated_tick_offsets = self.numbers_with_elongated_ticks - self.x_min
@ -580,7 +581,6 @@ class NumberLine(Line):
AttributeError
If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised.
"""
direction = self.label_direction if direction is None else direction
buff = self.line_to_number_buff if buff is None else buff
font_size = self.font_size if font_size is None else font_size

View file

@ -319,7 +319,6 @@ class BarChart(Axes):
Primarily used when the bars are initialized with ``self._add_bars``
or updated via ``self.change_bar_values``.
"""
self.bars.set_color_by_gradient(*self.bar_colors)
def _add_x_axis_labels(self):
@ -329,7 +328,6 @@ class BarChart(Axes):
UP for negative values and DOWN for positive values.
"""
val_range = np.arange(
0.5, len(self.bar_names), 1
) # 0.5 shifted so that labels are centered, not on ticks
@ -369,7 +367,6 @@ class BarChart(Axes):
Rectangle
A positioned rectangle representing a bar on the chart.
"""
# bar measurements relative to the axis
# distance from between the y-axis and the top of the bar
@ -432,7 +429,6 @@ class BarChart(Axes):
self.add(chart, c_bar_lbls)
"""
bar_labels = VGroup()
for bar, value in zip(self.bars, self.values):
bar_lbl = label_constructor(str(value))
@ -480,7 +476,6 @@ class BarChart(Axes):
chart.change_bar_values(list(reversed(values)))
self.add(chart.get_bar_labels(font_size=24))
"""
for i, (bar, value) in enumerate(zip(self.bars, values)):
chart_val = self.values[i]

View file

@ -90,7 +90,6 @@ class LinearBase(_ScaleBase):
scale_factor
The slope of the linear function, by default 1.0
"""
super().__init__()
self.scale_factor = scale_factor
@ -177,7 +176,6 @@ class LogBase(_ScaleBase):
base_config
Additional arguments to be passed to :class:`~.Integer`.
"""
# uses `format` syntax to control the number of decimal places.
tex_labels = [
Integer(

View file

@ -72,7 +72,7 @@ def matrix_to_mobject(matrix):
class Matrix(VMobject, metaclass=ConvertToOpenGL):
"""A mobject that displays a matrix on the screen.
r"""A mobject that displays a matrix on the screen.
Parameters
----------
@ -118,22 +118,22 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
class MatrixExamples(Scene):
def construct(self):
m0 = Matrix([[2, "\\pi"], [-1, 1]])
m0 = Matrix([[2, r"\pi"], [-1, 1]])
m1 = Matrix([[2, 0, 4], [-1, 1, 5]],
v_buff=1.3,
h_buff=0.8,
bracket_h_buff=SMALL_BUFF,
bracket_v_buff=SMALL_BUFF,
left_bracket="\\{",
right_bracket="\\}")
left_bracket=r"\{",
right_bracket=r"\}")
m1.add(SurroundingRectangle(m1.get_columns()[1]))
m2 = Matrix([[2, 1], [-1, 3]],
element_alignment_corner=UL,
left_bracket="(",
right_bracket=")")
m3 = Matrix([[2, 1], [-1, 3]],
left_bracket="\\\\langle",
right_bracket="\\\\rangle")
left_bracket=r"\langle",
right_bracket=r"\rangle")
m4 = Matrix([[2, 1], [-1, 3]],
).set_column_colors(RED, GREEN)
m5 = Matrix([[2, 1], [-1, 3]],
@ -241,7 +241,6 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
:class:`Matrix`
The current matrix object (self).
"""
# Height per row of LaTeX array with default settings
BRACKET_HEIGHT = 0.5977
@ -280,7 +279,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
return self
def get_columns(self):
"""Return columns of the matrix as VGroups.
r"""Return columns of the matrix as VGroups.
Returns
--------
@ -299,7 +298,6 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
m0.add(SurroundingRectangle(m0.get_columns()[1]))
self.add(m0)
"""
return VGroup(
*(
VGroup(*(row[i] for row in self.mob_matrix))
@ -308,7 +306,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
)
def set_column_colors(self, *colors: str):
"""Set individual colors for each columns of the matrix.
r"""Set individual colors for each columns of the matrix.
Parameters
----------
@ -338,7 +336,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
return self
def get_rows(self):
"""Return rows of the matrix as VGroups.
r"""Return rows of the matrix as VGroups.
Returns
--------
@ -360,7 +358,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
return VGroup(*(VGroup(*row) for row in self.mob_matrix))
def set_row_colors(self, *colors: str):
"""Set individual colors for each row of the matrix.
r"""Set individual colors for each row of the matrix.
Parameters
----------
@ -438,7 +436,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
return self.elements
def get_brackets(self):
"""Return the bracket mobjects.
r"""Return the bracket mobjects.
Returns
--------
@ -464,7 +462,7 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL):
class DecimalMatrix(Matrix):
"""A mobject that displays a matrix with decimal entries on the screen.
r"""A mobject that displays a matrix with decimal entries on the screen.
Examples
--------
@ -544,7 +542,7 @@ class IntegerMatrix(Matrix):
class MobjectMatrix(Matrix):
"""A mobject that displays a matrix of mobject entries on the screen.
r"""A mobject that displays a matrix of mobject entries on the screen.
Examples
--------

View file

@ -666,7 +666,6 @@ class Mobject:
>>> mob.foo
0
"""
for attr, value in kwargs.items():
setattr(self, attr, value)
@ -745,7 +744,6 @@ class Mobject:
:meth:`length_over_dim`
"""
# Get the length across the X dimension
return self.length_over_dim(0)
@ -782,7 +780,6 @@ class Mobject:
:meth:`length_over_dim`
"""
# Get the length across the Y dimension
return self.length_over_dim(1)
@ -803,7 +800,6 @@ class Mobject:
:meth:`length_over_dim`
"""
# Get the length across the Z dimension
return self.length_over_dim(2)
@ -835,7 +831,8 @@ class Mobject:
def save_image(self, name: str | None = None) -> None:
"""Saves an image of only this :class:`Mobject` at its position to a png
file."""
file.
"""
self.get_image().save(
Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"),
)
@ -1026,7 +1023,6 @@ class Mobject:
:meth:`remove_updater`
:class:`~.UpdateFromFunc`
"""
if index is None:
self.updaters.append(update_function)
else:
@ -1116,7 +1112,6 @@ class Mobject:
:meth:`clear_updaters`
"""
self.clear_updaters()
for updater in mobject.get_updaters():
self.add_updater(updater)
@ -1142,7 +1137,6 @@ class Mobject:
:meth:`add_updater`
"""
self.updating_suspended = True
if recursive:
for submob in self.submobjects:
@ -1217,7 +1211,6 @@ class Mobject:
--------
:meth:`move_to`
"""
total_vector = reduce(op.add, vectors)
for mob in self.family_members_with_points():
mob.points = mob.points.astype("float")
@ -1617,7 +1610,6 @@ class Mobject:
>>> sq.height
5.0
"""
return self.rescale_to_fit(width, 0, stretch=False, **kwargs)
def stretch_to_fit_width(self, width: float, **kwargs) -> Self:
@ -1643,7 +1635,6 @@ class Mobject:
>>> sq.height
2.0
"""
return self.rescale_to_fit(width, 0, stretch=True, **kwargs)
def scale_to_fit_height(self, height: float, **kwargs) -> Self:
@ -1669,7 +1660,6 @@ class Mobject:
>>> sq.width
5.0
"""
return self.rescale_to_fit(height, 1, stretch=False, **kwargs)
def stretch_to_fit_height(self, height: float, **kwargs) -> Self:
@ -1695,17 +1685,14 @@ class Mobject:
>>> sq.width
2.0
"""
return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
def scale_to_fit_depth(self, depth: float, **kwargs) -> Self:
"""Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional."""
return self.rescale_to_fit(depth, 2, stretch=False, **kwargs)
def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self:
"""Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional."""
return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
def set_coord(self, value, dim: int, direction: Vector3D = ORIGIN) -> Self:
@ -1832,7 +1819,6 @@ class Mobject:
:class:`~.BackgroundRectangle`
"""
# TODO, this does not behave well when the mobject has points,
# since it gets displayed on top
from manim.mobject.geometry.shape_matchers import BackgroundRectangle

View file

@ -187,7 +187,8 @@ class OpenGLTipableVMobject(OpenGLVMobject):
def get_tip(self):
"""Returns the TipableVMobject instance's (first) tip,
otherwise throws an exception."""
otherwise throws an exception.
"""
tips = self.get_tips()
if len(tips) == 0:
raise Exception("tip not found")
@ -516,9 +517,7 @@ class OpenGLLine(OpenGLTipableVMobject):
return angle_of_vector(self.get_vector())
def get_projection(self, point):
"""
Return projection of a point onto the line
"""
"""Return projection of a point onto the line"""
unit_vect = self.get_unit_vector()
start = self.get_start()
return start + np.dot(point - start, unit_vect) * unit_vect

View file

@ -24,7 +24,6 @@ from manim.event_handler.event_listener import EventListener
from manim.event_handler.event_type import EventType
from manim.utils.bezier import integer_interpolate, interpolate
from manim.utils.color import *
from manim.utils.deprecation import deprecated
# from ..utils.iterables import batch_by_property
from manim.utils.iterables import (
@ -261,17 +260,29 @@ class OpenGLMobject:
def init_colors(self):
"""Initializes the colors.
Gets called upon creation"""
Gets called upon creation
"""
self.set_color(self.color, self.opacity)
def init_points(self):
"""Initializes :attr:`points` and therefore the shape.
Gets called upon creation. This is an empty method that can be implemented by
subclasses."""
subclasses.
"""
# Typically implemented in subclass, unless purposefully left blank
pass
def set_data(self, data: dict[str, Any]) -> Self:
for key in data:
self.data[key] = data[key].copy()
return self
def set_uniforms(self, uniforms: dict[str, Any]) -> Self:
for key in uniforms:
self.uniforms[key] = uniforms[key] # Copy?
return self
# https://github.com/python/typing/issues/802
# so we hack around it by doing | Self
# but this causes issues in Scene.play which only
@ -486,7 +497,6 @@ class OpenGLMobject:
:meth:`length_over_dim`
"""
# Get the length across the X dimension
return self.length_over_dim(0)
@ -524,7 +534,6 @@ class OpenGLMobject:
:meth:`length_over_dim`
"""
# Get the length across the Y dimension
return self.length_over_dim(1)
@ -545,7 +554,6 @@ class OpenGLMobject:
:meth:`length_over_dim`
"""
# Get the length across the Z dimension
return self.length_over_dim(2)
@ -1664,7 +1672,7 @@ class OpenGLMobject:
return self
def _handle_scale_side_effects(self, scale_factor: float | np.ndarray) -> None:
"""In case subclasses, such as DecimalNumber, need to make
r"""In case subclasses, such as DecimalNumber, need to make
any other changes when the size gets altered by scaling.
This method can be overridden in subclasses.
@ -2798,10 +2806,6 @@ class OpenGLMobject:
caller_name = sys._getframe(1).f_code.co_name
raise Exception(message.format(caller_name))
@deprecated(
since="v0.17.2",
message="The usage of this method is discouraged please set attributes directly",
)
def set(self, **kwargs) -> Self:
"""Sets attributes.
@ -2830,7 +2834,6 @@ class OpenGLMobject:
"""
for attr, value in kwargs.items():
setattr(self, attr, value)

View file

@ -65,9 +65,7 @@ class OpenGLPMobject(OpenGLMobject):
return self
def thin_out(self, factor=5):
"""
Removes all but every nth point for n = factor
"""
"""Removes all but every nth point for n = factor"""
for mob in self.family_members_with_points():
num_points = mob.get_num_points()
@ -126,9 +124,7 @@ class OpenGLPMobject(OpenGLMobject):
return self
def sort_points(self, function=lambda p: p[0]):
"""
function is any map from R^3 to R
"""
"""function is any map from R^3 to R"""
for mob in self.family_members_with_points():
indices = np.argsort(np.apply_along_axis(function, 1, mob.points))
for key in mob.data:

View file

@ -414,9 +414,7 @@ class OpenGLVMobject(OpenGLMobject):
self.append_points(new_points)
def add_cubic_bezier_curve_to(self, handle1, handle2, anchor):
"""
Add cubic bezier curve to the path.
"""
"""Add cubic bezier curve to the path."""
self.throw_error_if_no_points()
quadratic_approx = get_quadratic_approximation_of_cubic(
self.get_last_point(),
@ -767,7 +765,6 @@ class OpenGLVMobject(OpenGLMobject):
length : :class:`float`
The length of the nth curve.
"""
if sample_points is None:
sample_points = 10
@ -814,7 +811,6 @@ class OpenGLVMobject(OpenGLMobject):
length : :class:`float`
The length of the nth curve.
"""
_, length = self.get_nth_curve_function_with_length(n, sample_points)
return length
@ -829,7 +825,6 @@ class OpenGLVMobject(OpenGLMobject):
Iterable[Callable[[float], np.ndarray]]
The functions for the curves.
"""
num_curves = self.get_num_curves()
for n in range(num_curves):
@ -879,7 +874,6 @@ class OpenGLVMobject(OpenGLMobject):
Iterable[Tuple[Callable[[float], np.ndarray], float]]
The functions and lengths of the curves.
"""
num_curves = self.get_num_curves()
for n in range(num_curves):
@ -905,7 +899,6 @@ class OpenGLVMobject(OpenGLMobject):
:exc:`Exception`
If the :class:`OpenGLVMobject` has no points.
"""
if alpha < 0 or alpha > 1:
raise ValueError(f"Alpha {alpha} not between 0 and 1.")
@ -1067,7 +1060,6 @@ class OpenGLVMobject(OpenGLMobject):
float
The length of the :class:`OpenGLVMobject`.
"""
if n_sample_points is None:
n_sample_points = 4 * self.get_num_curves() + 1
points = np.array(
@ -1238,7 +1230,6 @@ class OpenGLVMobject(OpenGLMobject):
np.ndarray
Points generated.
"""
if len(points) == 1:
nppc = self.n_points_per_curve
return np.repeat(points, nppc * n, 0)

View file

@ -84,7 +84,7 @@ from ..utils.color import BLACK, YELLOW, ManimColor, ParsableManimColor
class Table(VGroup):
"""A mobject that displays a table on the screen.
r"""A mobject that displays a table on the screen.
Parameters
----------
@ -682,7 +682,6 @@ class Table(VGroup):
item.set_color(random_bright_color())
self.add(table)
"""
return VGroup(*self.row_labels)
def get_col_labels(self) -> VGroup:
@ -711,7 +710,6 @@ class Table(VGroup):
item.set_color(random_bright_color())
self.add(table)
"""
return VGroup(*self.col_labels)
def get_labels(self) -> VGroup:
@ -1066,7 +1064,7 @@ class MobjectTable(Table):
class IntegerTable(Table):
"""A specialized :class:`~.Table` mobject for use with :class:`~.Integer`.
r"""A specialized :class:`~.Table` mobject for use with :class:`~.Integer`.
Examples
--------
@ -1080,14 +1078,14 @@ class IntegerTable(Table):
[[0,30,45,60,90],
[90,60,45,30,0]],
col_labels=[
MathTex("\\\\frac{\\sqrt{0}}{2}"),
MathTex("\\\\frac{\\sqrt{1}}{2}"),
MathTex("\\\\frac{\\sqrt{2}}{2}"),
MathTex("\\\\frac{\\sqrt{3}}{2}"),
MathTex("\\\\frac{\\sqrt{4}}{2}")],
row_labels=[MathTex("\\sin"), MathTex("\\cos")],
MathTex(r"\frac{\sqrt{0}}{2}"),
MathTex(r"\frac{\sqrt{1}}{2}"),
MathTex(r"\frac{\sqrt{2}}{2}"),
MathTex(r"\frac{\sqrt{3}}{2}"),
MathTex(r"\frac{\sqrt{4}}{2}")],
row_labels=[MathTex(r"\sin"), MathTex(r"\cos")],
h_buff=1,
element_to_mobject_config={"unit": "^{\\circ}"})
element_to_mobject_config={"unit": r"^{\circ}"})
self.add(t0)
"""

View file

@ -22,7 +22,7 @@ __all__ = ["DecimalNumber", "Integer", "Variable"]
class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
"""An mobject representing a decimal number.
r"""An mobject representing a decimal number.
Parameters
----------

View file

@ -12,7 +12,7 @@ r"""Mobjects representing text rendered using LaTeX.
from __future__ import annotations
from manim.utils.color import ManimColor
from manim.utils.color import BLACK, ManimColor, ParsableManimColor
__all__ = [
"SingleStringMathTex",
@ -62,6 +62,7 @@ class SingleStringMathTex(SVGMobject):
tex_environment: str = "align*",
tex_template: TexTemplate | None = None,
font_size: float = DEFAULT_FONT_SIZE,
color: ParsableManimColor | None = None,
**kwargs,
):
self._font_size = font_size
@ -83,6 +84,7 @@ class SingleStringMathTex(SVGMobject):
should_center=should_center,
stroke_width=stroke_width,
height=height,
color=color,
path_string_config={
"should_subdivide_sharp_curves": True,
"should_remove_null_curves": True,
@ -186,7 +188,6 @@ class SingleStringMathTex(SVGMobject):
This is important when the braces in the TeX code are spread over
multiple arguments as in, e.g., ``MathTex(r"e^{i", r"\tau} = 1")``.
"""
# "\{" does not count (it's a brace literal), but "\\{" counts (it's a new line and then brace)
num_lefts = tex.count("{") - tex.count("\\{") + tex.count("\\\\{")
num_rights = tex.count("}") - tex.count("\\}") + tex.count("\\\\}")
@ -205,6 +206,19 @@ class SingleStringMathTex(SVGMobject):
def get_tex_string(self):
return self.tex_string
def init_colors(self, propagate_colors=True):
for submobject in self.submobjects:
# needed to preserve original (non-black)
# TeX colors of individual submobjects
if submobject.color != BLACK:
continue
submobject.color = self.color
if config.renderer == RendererType.OPENGL:
submobject.init_colors()
elif config.renderer == RendererType.CAIRO:
submobject.init_colors(propagate_colors=propagate_colors)
return self
class MathTex(SingleStringMathTex):
r"""A string compiled with LaTeX in math mode.
@ -424,6 +438,10 @@ class MathTex(SingleStringMathTex):
class Tex(MathTex):
r"""A string compiled with LaTeX in normal mode.
The color can be set using
the ``color`` argument. Any parts of the ``tex_string`` that are colored by the
TeX commands ``\color`` or ``\textcolor`` will retain their original color.
Tests
-----

View file

@ -670,7 +670,8 @@ class Text(SVGMobject):
)
def _set_color_by_t2g(self, t2g=None):
"""Sets gradient colors for specified
strings. Behaves similarly to ``set_color_by_t2c``."""
strings. Behaves similarly to ``set_color_by_t2c``.
"""
t2g = t2g if t2g else self.t2g
for word, gradient in list(t2g.items()):
for start, end in self._find_indexes(word, self.text):
@ -1411,7 +1412,8 @@ class MarkupText(SVGMobject):
"""Counts characters that will be displayed.
This is needed for partial coloring or gradients, because space
counts to the text's `len`, but has no corresponding character."""
counts to the text's `len`, but has no corresponding character.
"""
count = 0
level = 0
# temporarily replace HTML entities by single char
@ -1546,7 +1548,6 @@ def register_font(font_file: str | Path):
This method is available for macOS for ``ManimPango>=v0.2.3``. Using this
method with previous releases will raise an :class:`AttributeError` on macOS.
"""
input_folder = Path(config.input_file).parent.resolve()
possible_paths = [
Path(font_file),

View file

@ -142,9 +142,7 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
return self
def thin_out(self, factor=5):
"""
Removes all but every nth point for n = factor
"""
"""Removes all but every nth point for n = factor"""
for mob in self.family_members_with_points():
num_points = self.get_num_points()
mob.apply_over_attr_arrays(
@ -153,9 +151,7 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
return self
def sort_points(self, function=lambda p: p[0]):
"""
Function is any map from R^3 to R
"""
"""Function is any map from R^3 to R"""
for mob in self.family_members_with_points():
indices = np.argsort(np.apply_along_axis(function, 1, mob.points))
mob.apply_over_attr_arrays(lambda arr, idx=indices: arr[idx])

View file

@ -589,7 +589,6 @@ class VMobject(Mobject):
:meth:`~.VMobject.set_sheen`
:meth:`~.VMobject.rotate_sheen_direction`
"""
direction = np.array(direction)
if family:
for submob in self.get_family():
@ -655,7 +654,6 @@ class VMobject(Mobject):
circle = Circle(fill_opacity=1).set_sheen(-0.3, DR)
self.add(circle)
"""
if family:
for submob in self.submobjects:
submob.set_sheen(factor, direction, family)
@ -1393,7 +1391,6 @@ class VMobject(Mobject):
length : :class:`float`
The length of the nth curve.
"""
_, length = self.get_nth_curve_function_with_length(n, sample_points)
return length
@ -1419,7 +1416,6 @@ class VMobject(Mobject):
length : :class:`float`
The length of the nth curve.
"""
curve = self.get_nth_curve_function(n)
norms = self.get_nth_curve_length_pieces(n, sample_points=sample_points)
length = np.sum(norms)
@ -1447,7 +1443,6 @@ class VMobject(Mobject):
Generator[Callable[[float], Point3D]]
The functions for the curves.
"""
num_curves = self.get_num_curves()
for n in range(num_curves):
@ -1468,7 +1463,6 @@ class VMobject(Mobject):
Generator[tuple[Callable[[float], Point3D], float]]
The functions and lengths of the curves.
"""
num_curves = self.get_num_curves()
for n in range(num_curves):
@ -1510,7 +1504,6 @@ class VMobject(Mobject):
line.point_from_proportion(proportion)
))
"""
if alpha < 0 or alpha > 1:
raise ValueError(f"Alpha {alpha} not between 0 and 1.")
@ -1662,7 +1655,6 @@ class VMobject(Mobject):
float
The length of the :class:`VMobject`.
"""
return sum(
length
for _, length in self.get_curve_functions_with_lengths(
@ -1782,7 +1774,6 @@ class VMobject(Mobject):
-------
Points generated.
"""
if len(points) == 1:
nppcc = self.n_points_per_cubic_curve
return np.repeat(points, nppcc * n, 0)

View file

@ -165,7 +165,8 @@ class ComplexValueTracker(ValueTracker):
"""Get the current value of this value tracker as a complex number.
The value is internally stored as a points array [a, b, 0]. This can be accessed directly
to represent the value geometrically, see the usage example."""
to represent the value geometrically, see the usage example.
"""
return complex(*self.points[0, :2])
def set_value(self, z):

View file

@ -352,7 +352,6 @@ class VectorField(VGroup):
This vector field.
"""
self.stop_submobject_movement()
self.submob_movement_updater = lambda mob, dt: mob.nudge_submobjects(
dt * speed,
@ -950,7 +949,6 @@ class StreamLines(VectorField):
self.wait(stream_lines.virtual_time / stream_lines.flow_speed)
"""
for line in self.stream_lines:
run_time = line.duration / flow_speed
line.anim = line_animation_class(
@ -1010,7 +1008,6 @@ class StreamLines(VectorField):
self.play(stream_lines.end_animation())
"""
if self.flow_animation is None:
raise ValueError("You have to start the animation before fading it out.")

View file

@ -140,13 +140,10 @@ class Scene:
)
def tear_down(self) -> None:
"""
This method is used to clean up scenes
"""
"""This method is used to clean up scenes"""
def find_sections(self) -> list[SceneSection]:
"""Find all sections in a :class:`.Scene`"""
sections: list[SceneSection] = [
bound
for _, bound in inspect.getmembers(

View file

@ -86,7 +86,6 @@ class ThreeDScene(Scene):
The new center of the camera frame in cartesian coordinates.
"""
if phi is not None:
self.renderer.camera.set_phi(phi)
if theta is not None:
@ -139,9 +138,7 @@ class ThreeDScene(Scene):
raise ValueError("Invalid ambient rotation angle.") from e
def stop_ambient_camera_rotation(self, about="theta"):
"""
This method stops all ambient camera rotation.
"""
"""This method stops all ambient camera rotation."""
about: str = about.lower()
try:
if config.renderer == RendererType.CAIRO:
@ -205,9 +202,7 @@ class ThreeDScene(Scene):
self.add(self.renderer.camera.phi_tracker)
def stop_3dillusion_camera_rotation(self):
"""
This method stops all illusion camera rotations.
"""
"""This method stops all illusion camera rotations."""
self.renderer.camera.theta_tracker.clear_updaters()
self.remove(self.renderer.camera.theta_tracker)
self.renderer.camera.phi_tracker.clear_updaters()
@ -546,7 +541,5 @@ class SpecialThreeDScene(ThreeDScene):
return self.default_angled_camera_position
def set_camera_to_default_position(self):
"""
Sets the camera to its default position.
"""
"""Sets the camera to its default position."""
self.set_camera_orientation(**self.default_angled_camera_position)

View file

@ -1002,7 +1002,6 @@ class LinearTransformationScene(VectorScene):
Animation
The animation of the movement.
"""
v_pieces = [piece for piece in pieces if isinstance(piece, VMobject)]
start = VGroup(*v_pieces)
target = VGroup(*(mob.target for mob in v_pieces))
@ -1093,7 +1092,6 @@ class LinearTransformationScene(VectorScene):
**kwargs
Any valid keyword argument of self.apply_transposed_matrix()
"""
self.apply_transposed_matrix(np.array(matrix).T, **kwargs)
def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs):

View file

@ -542,7 +542,6 @@ def split_bezier(points: BezierPoints, t: float) -> Point3D_Array:
:class:`~.Point3D_Array`
An array containing the control points defining the two Bézier curves.
"""
points = np.asarray(points)
N, dim = points.shape
degree = N - 1
@ -1115,7 +1114,7 @@ def match_interpolate(
return interpolate(
new_start,
new_end,
old_alpha, # type: ignore
old_alpha, # type: ignore[arg-type]
)
@ -1931,7 +1930,7 @@ def proportions_along_bezier_curve_for_point(
# Roots will be none, but in this specific instance, we don't need to consider that.
continue
bezier_polynom = np.polynomial.Polynomial(terms[::-1])
polynom_roots = bezier_polynom.roots() # type: ignore
polynom_roots = bezier_polynom.roots()
if len(polynom_roots) > 0:
polynom_roots = np.around(polynom_roots, int(np.log10(1 / round_to)))
roots.append(polynom_roots)
@ -1939,7 +1938,7 @@ def proportions_along_bezier_curve_for_point(
roots = [[root for root in rootlist if root.imag == 0] for rootlist in roots]
# Get common roots
# arg-type: ignore
roots = reduce(np.intersect1d, roots) # type: ignore
roots = reduce(np.intersect1d, roots)
result = np.asarray([r.real for r in roots if 0 <= r.real <= 1])
return result
@ -1971,7 +1970,6 @@ def point_lies_on_bezier(
bool
Whether the point lies on the curve.
"""
roots = proportions_along_bezier_curve_for_point(point, control_points, round_to)
return len(roots) > 0

View file

@ -22,7 +22,6 @@ def handle_caching_play(func: Callable[..., None]):
The play like function that has to be written to the video file stream.
Take the same parameters as `scene.play`.
"""
# NOTE : This is only kept for OpenGL renderer.
# The play logic of the cairo renderer as been refactored and does not need this function anymore.
# When OpenGL renderer will have a proper testing system,

View file

@ -163,9 +163,9 @@ class ManimColor:
length = len(value)
if all(isinstance(x, float) for x in value):
if length == 3:
self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore
self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore[arg-type]
elif length == 4:
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore[arg-type]
else:
raise ValueError(
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
@ -173,11 +173,11 @@ class ManimColor:
else:
if length == 3:
self._internal_value = ManimColor._internal_from_int_rgb(
value, # type: ignore
value, # type: ignore[arg-type]
alpha,
)
elif length == 4:
self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore
self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore[arg-type]
else:
raise ValueError(
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"

View file

@ -67,7 +67,6 @@ def index_labels(
self.add(text, indices)
"""
labels = VGroup()
for n, submob in enumerate(mobject):
label = Integer(n, **kwargs)

View file

@ -44,7 +44,6 @@ def smart_replace(base: str, alias: str, substitution: str) -> str:
str
The new string after the alias substitution.
"""
occurrences = []
len_alias = len(alias)
len_base = len(base)

View file

@ -93,7 +93,7 @@ from typing import TYPE_CHECKING, Any
import jinja2
from docutils import nodes
from docutils.parsers.rst import Directive, directives # type: ignore
from docutils.parsers.rst import Directive, directives
from docutils.statemachine import StringList
from manim import QUALITIES

View file

@ -192,7 +192,6 @@ def rotate_vector(
ValueError
If vector is not of dimension 2 or 3.
"""
if len(vector) > 3:
raise ValueError("Vector must have the correct dimensions.")
if len(vector) == 2:
@ -248,9 +247,7 @@ def rotation_matrix(
axis: np.ndarray,
homogeneous: bool = False,
) -> np.ndarray:
"""
Rotation in R^3 about a specified axis of rotation.
"""
"""Rotation in R^3 about a specified axis of rotation."""
inhomogeneous_rotation_matrix = Rotation.from_rotvec(
angle * normalize(np.array(axis))
).as_matrix()
@ -356,7 +353,6 @@ def angle_between_vectors(v1: np.ndarray, v2: np.ndarray) -> float:
float
The angle between the vectors.
"""
return 2 * np.arctan2(
np.linalg.norm(normalize(v1) - normalize(v2)),
np.linalg.norm(normalize(v1) + normalize(v2)),
@ -493,7 +489,6 @@ def regular_vertices(
start_angle : :class:`float`
The angle the vertices start at.
"""
if start_angle is None:
start_angle = 0 if n % 2 == 0 else TAU / 4
@ -734,7 +729,6 @@ def earclip_triangulation(verts: np.ndarray, ring_ends: list) -> list:
list
A list of indices giving a triangulation of a polygon.
"""
rings = [list(range(e0, e1)) for e0, e1 in zip([0, *ring_ends], ring_ends)]
def is_in(point, ring_id):

View file

@ -188,7 +188,6 @@ def _make_test_comparing_frames(
Callable[[], None]
The pytest test.
"""
if is_set_test_data_test:
frames_tester = _ControlDataWriter(file_path, size_frame=size_frame)
else:

View file

@ -181,7 +181,6 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]:
A pair of strings representing the opening and closing of the tex environment, e.g.
``\begin{tabular}{cccl}`` and ``\end{tabular}``
"""
environment.removeprefix(r"\begin").removeprefix("{")
# The \begin command takes everything and closes with a brace

View file

@ -35,7 +35,7 @@ def tex_to_svg_file(
environment: str | None = None,
tex_template: TexTemplate | None = None,
):
"""Takes a tex expression and returns the svg version of the compiled tex
r"""Takes a tex expression and returns the svg version of the compiled tex
Parameters
----------
@ -76,7 +76,7 @@ def generate_tex_file(
environment: str | None = None,
tex_template: TexTemplate | None = None,
) -> Path:
"""Takes a tex expression (and an optional tex environment),
r"""Takes a tex expression (and an optional tex environment),
and returns a fully formed tex file ready for compilation.
Parameters
@ -271,7 +271,6 @@ def delete_nonsvg_files(additional_endings: Iterable[str] = ()) -> None:
additional_endings
Additional endings to whitelist
"""
tex_dir = config.get_dir("tex_dir")
file_suffix_whitelist = {".svg", ".tex", *additional_endings}

91
poetry.lock generated
View file

@ -1008,13 +1008,13 @@ testing = ["hatch", "pre-commit", "pytest", "tox"]
[[package]]
name = "executing"
version = "2.0.1"
version = "2.1.0"
description = "Get the currently executing AST node of a frame, and other information"
optional = false
python-versions = ">=3.5"
python-versions = ">=3.8"
files = [
{file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"},
{file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"},
{file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"},
{file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"},
]
[package.extras]
@ -1050,37 +1050,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
typing = ["typing-extensions (>=4.8)"]
[[package]]
name = "flake8"
version = "6.1.0"
description = "the modular source code checker: pep8 pyflakes and co"
optional = false
python-versions = ">=3.8.1"
files = [
{file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
{file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
]
[package.dependencies]
mccabe = ">=0.7.0,<0.8.0"
pycodestyle = ">=2.11.0,<2.12.0"
pyflakes = ">=3.1.0,<3.2.0"
[[package]]
name = "flake8-docstrings"
version = "1.7.0"
description = "Extension for flake8 which uses pydocstyle to check docstrings"
optional = false
python-versions = ">=3.7"
files = [
{file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"},
{file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"},
]
[package.dependencies]
flake8 = ">=3"
pydocstyle = ">=2.1"
[[package]]
name = "fonttools"
version = "4.53.1"
@ -2159,17 +2128,6 @@ files = [
[package.dependencies]
traitlets = "*"
[[package]]
name = "mccabe"
version = "0.7.0"
description = "McCabe checker, plugin for flake8"
optional = false
python-versions = ">=3.6"
files = [
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]
[[package]]
name = "mdit-py-plugins"
version = "0.4.1"
@ -2889,17 +2847,6 @@ files = [
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
]
[[package]]
name = "pycodestyle"
version = "2.11.1"
description = "Python style guide checker"
optional = false
python-versions = ">=3.8"
files = [
{file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
{file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
]
[[package]]
name = "pycparser"
version = "2.22"
@ -3031,23 +2978,6 @@ files = [
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pydocstyle"
version = "6.3.0"
description = "Python docstring style checker"
optional = false
python-versions = ">=3.6"
files = [
{file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"},
{file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"},
]
[package.dependencies]
snowballstemmer = ">=2.2.0"
[package.extras]
toml = ["tomli (>=1.2.3)"]
[[package]]
name = "pydub"
version = "0.25.1"
@ -3059,17 +2989,6 @@ files = [
{file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"},
]
[[package]]
name = "pyflakes"
version = "3.1.0"
description = "passive checker of Python programs"
optional = false
python-versions = ">=3.8"
files = [
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
]
[[package]]
name = "pygithub"
version = "2.4.0"
@ -4634,4 +4553,4 @@ jupyterlab = ["jupyterlab", "notebook"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.10,<3.13"
content-hash = "d5fe13e0bc943b0145374cbd92156bffbce1198bfbfd2de31203a9fdef8c8d66"
content-hash = "bbb339bd2fb2a6161e6accdb7369cf9a0652a280c8ef27a98fddd261a0ff5e7f"

View file

@ -62,8 +62,6 @@ jupyterlab = ["jupyterlab", "notebook"]
gui = ["dearpygui"]
[tool.poetry.group.dev.dependencies]
flake8 = "^6.1.0"
flake8-docstrings = "^1.7.0"
furo = "^2023.09.10"
gitpython = "^3"
isort = "^5.12.0"
@ -133,9 +131,11 @@ select = [
"A",
"B",
"C4",
"D",
"E",
"F",
"I",
"PGH",
"PT",
"SIM",
"UP",
@ -147,14 +147,24 @@ ignore = [
# No function calls in defaults
# ignored because np.array() and straight_path()
"B008",
# docstring ignores - mostly stylistic
"D1",
"D203",
"D205",
"D212",
"D4",
# due to the import * used in manim
"F403",
"F405",
# generic type: ignore
"PGH003",
# fixtures not returning anything should have leading underscore
"PT004",
# Exception too broad (this would require lots of changes + re.escape) for little benefit
"PT011",
# as recommended by https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
"D206",
"D300",
"E111",
"E114",
"E117",
@ -192,9 +202,8 @@ required-imports = ["from __future__ import annotations"]
fixture-parentheses = false
mark-parentheses = false
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.format]
docstring-code-format = true
[tool.codespell]
write-changes = true
ignore-words-list = ["medias", "nam"]

View file

@ -217,7 +217,6 @@ def main(token, prior, tag, additional, outfile):
ADDITIONAL includes additional PR(s) that have not been recognized automatically.
"""
lst_release, cur_release = prior, tag
github = Github(token)

View file

@ -8,7 +8,8 @@ from manim.mobject.text.numbers import Integer
def test_unit_vector():
"""Check if the magnitude of unit vector along
the NumberLine is equal to its unit_size."""
the NumberLine is equal to its unit_size.
"""
axis1 = NumberLine(unit_size=0.4)
axis2 = NumberLine(x_range=[-2, 5], length=12)
for axis in (axis1, axis2):
@ -17,7 +18,8 @@ def test_unit_vector():
def test_decimal_determined_by_step():
"""Checks that step size is considered when determining the number of decimal
places."""
places.
"""
axis = NumberLine(x_range=[-2, 2, 0.5])
expected_decimal_places = 1
actual_decimal_places = axis.decimal_number_config["num_decimal_places"]

View file

@ -5,7 +5,8 @@ from manim import RED, DecimalNumber, Integer
def test_font_size():
"""Test that DecimalNumber returns the correct font_size value
after being scaled."""
after being scaled.
"""
num = DecimalNumber(0).scale(0.3)
assert round(num.font_size, 5) == 14.4
@ -39,7 +40,8 @@ def test_set_value_size():
def test_color_when_number_of_digits_changes():
"""Test that all digits of an Integer are colored correctly when
the number of digits changes."""
the number of digits changes.
"""
mob = Integer(color=RED)
mob.set_value(42)
assert all(

View file

@ -123,7 +123,8 @@ def test_tex_size():
def test_font_size():
"""Test that tex_mobject classes return
the correct font_size value after being scaled."""
the correct font_size value after being scaled.
"""
string = MathTex(0).scale(0.3)
assert round(string.font_size, 5) == 14.4

View file

@ -8,7 +8,8 @@ from manim.mobject.text.text_mobject import MarkupText, Text
def test_font_size():
"""Test that Text and MarkupText return the
correct font_size value after being scaled."""
correct font_size value after being scaled.
"""
text_string = Text("0").scale(0.3)
markuptext_string = MarkupText("0").scale(0.3)

View file

@ -165,7 +165,6 @@ class Top:
@deprecated(since="0.8.0", message="This method is useless.")
def mid_func(self):
"""Middle function in Top."""
pass
@deprecated(until="1.4.0", replacement="Top.NewNested")
@ -180,7 +179,6 @@ class Top:
@deprecated(since="1.0.0", until="12/25/2025")
def nested_func(self):
"""Nested function in Top.NewNested."""
pass
class Bottom:

View file

@ -58,7 +58,6 @@ class MyScene(Scene):
def test_transparent(config):
"""Test the 'transparent' config option."""
config.verbosity = "ERROR"
config.dry_run = True
@ -89,7 +88,6 @@ def test_transparent_by_background_opacity(config, dry_run):
def test_background_color(config):
"""Test the 'background_color' config option."""
config.background_color = WHITE
config.verbosity = "ERROR"
config.dry_run = True
@ -217,7 +215,6 @@ def test_temporary_dry_run(config):
def test_dry_run_with_png_format(config, dry_run):
"""Test that there are no exceptions when running a png without output"""
config.write_to_movie = False
config.disable_caching = True
assert config.dry_run is True

View file

@ -7,8 +7,8 @@ __module_test__ = "tex_mobject"
@frames_comparison
def test_color_inheritance(scene):
"""Test that Text and MarkupText correctly inherit colour from
their parent class."""
their parent class.
"""
VMobject.set_default(color=RED)
tex = Tex("test color inheritance")
mathtex = MathTex("test color inheritance")
@ -24,3 +24,33 @@ def test_set_opacity_by_tex(scene):
tex = MathTex("f(x) = y", substrings_to_isolate=["f(x)"])
tex.set_opacity_by_tex("f(x)", 0.2, 0.5)
scene.add(tex)
def test_preserve_tex_color():
"""Test that Tex preserves original tex colors."""
template = TexTemplate(preamble=r"\usepackage{xcolor}")
Tex.set_default(tex_template=template)
txt = Tex(r"\textcolor{red}{Hello} World")
assert len(txt[0].submobjects) == 10
assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello"
assert all(
char.fill_color.to_hex() == WHITE.to_hex() for char in txt[0][-5:]
) # "World"
txt = Tex(r"\textcolor{red}{Hello} World", color=BLUE)
assert len(txt[0].submobjects) == 10
assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello"
assert all(
char.fill_color.to_hex() == BLUE.to_hex() for char in txt[0][-5:]
) # "World"
Tex.set_default(color=GREEN)
txt = Tex(r"\textcolor{red}{Hello} World")
assert len(txt[0].submobjects) == 10
assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello"
assert all(
char.fill_color.to_hex() == GREEN.to_hex() for char in txt[0][-5:]
) # "World"
Tex.set_default()

View file

@ -20,7 +20,8 @@ def test_Text2Color():
def test_text_color_inheritance():
"""Test that Text and MarkupText correctly inherit colour from
their parent class."""
their parent class.
"""
VMobject.set_default(color=RED)
# set both to a singular font so that the tests agree.
text = Text("test_color_inheritance", font="Sans")

View file

@ -66,7 +66,6 @@ def logs_comparison(
Callable[[Any], Any]
The test wrapped with which we are going to make the comparison.
"""
control_data_file = Path(control_data_file)
log_path_from_media_dir = Path(log_path_from_media_dir)

View file

@ -90,7 +90,6 @@ def video_comparison(
--------
tests/helpers/video_utils.py : create control data
"""
control_data_file = Path(control_data_file)
scene_path_from_media_dir = Path(scene_path_from_media_dir)