manim 0.18.0__py3-none-any.whl → 0.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of manim might be problematic. Click here for more details.

Files changed (115) hide show
  1. manim/__init__.py +3 -6
  2. manim/__main__.py +18 -10
  3. manim/_config/__init__.py +5 -2
  4. manim/_config/cli_colors.py +12 -8
  5. manim/_config/default.cfg +1 -1
  6. manim/_config/logger_utils.py +9 -8
  7. manim/_config/utils.py +637 -449
  8. manim/animation/animation.py +9 -2
  9. manim/animation/composition.py +78 -40
  10. manim/animation/creation.py +12 -6
  11. manim/animation/fading.py +0 -1
  12. manim/animation/indication.py +10 -21
  13. manim/animation/movement.py +1 -2
  14. manim/animation/rotation.py +1 -1
  15. manim/animation/specialized.py +1 -1
  16. manim/animation/speedmodifier.py +7 -2
  17. manim/animation/transform_matching_parts.py +1 -1
  18. manim/camera/camera.py +13 -4
  19. manim/cli/cfg/group.py +18 -8
  20. manim/cli/checkhealth/checks.py +2 -0
  21. manim/cli/checkhealth/commands.py +2 -0
  22. manim/cli/default_group.py +13 -5
  23. manim/cli/init/commands.py +4 -1
  24. manim/cli/plugins/commands.py +3 -0
  25. manim/cli/render/commands.py +27 -20
  26. manim/cli/render/ease_of_access_options.py +4 -3
  27. manim/cli/render/global_options.py +9 -7
  28. manim/cli/render/output_options.py +6 -5
  29. manim/cli/render/render_options.py +13 -13
  30. manim/constants.py +54 -15
  31. manim/gui/gui.py +2 -0
  32. manim/mobject/geometry/arc.py +4 -4
  33. manim/mobject/geometry/boolean_ops.py +13 -9
  34. manim/mobject/geometry/line.py +16 -8
  35. manim/mobject/geometry/polygram.py +17 -5
  36. manim/mobject/geometry/tips.py +2 -2
  37. manim/mobject/graph.py +379 -106
  38. manim/mobject/graphing/coordinate_systems.py +17 -20
  39. manim/mobject/graphing/functions.py +14 -10
  40. manim/mobject/graphing/number_line.py +1 -1
  41. manim/mobject/mobject.py +175 -72
  42. manim/mobject/opengl/opengl_compatibility.py +2 -0
  43. manim/mobject/opengl/opengl_geometry.py +26 -1
  44. manim/mobject/opengl/opengl_image_mobject.py +2 -0
  45. manim/mobject/opengl/opengl_mobject.py +3 -0
  46. manim/mobject/opengl/opengl_point_cloud_mobject.py +2 -0
  47. manim/mobject/opengl/opengl_surface.py +2 -0
  48. manim/mobject/opengl/opengl_three_dimensions.py +2 -0
  49. manim/mobject/opengl/opengl_vectorized_mobject.py +19 -14
  50. manim/mobject/svg/brace.py +2 -0
  51. manim/mobject/svg/svg_mobject.py +10 -12
  52. manim/mobject/table.py +0 -1
  53. manim/mobject/text/code_mobject.py +2 -0
  54. manim/mobject/text/numbers.py +2 -0
  55. manim/mobject/text/tex_mobject.py +1 -1
  56. manim/mobject/text/text_mobject.py +43 -6
  57. manim/mobject/three_d/three_d_utils.py +4 -4
  58. manim/mobject/three_d/three_dimensions.py +4 -4
  59. manim/mobject/types/image_mobject.py +5 -1
  60. manim/mobject/types/point_cloud_mobject.py +2 -0
  61. manim/mobject/types/vectorized_mobject.py +124 -29
  62. manim/mobject/value_tracker.py +3 -3
  63. manim/mobject/vector_field.py +3 -1
  64. manim/plugins/__init__.py +15 -1
  65. manim/plugins/plugins_flags.py +11 -5
  66. manim/renderer/cairo_renderer.py +12 -2
  67. manim/renderer/opengl_renderer.py +2 -3
  68. manim/renderer/opengl_renderer_window.py +2 -0
  69. manim/renderer/shader_wrapper.py +2 -0
  70. manim/renderer/vectorized_mobject_rendering.py +5 -0
  71. manim/scene/scene.py +22 -6
  72. manim/scene/scene_file_writer.py +3 -1
  73. manim/scene/section.py +2 -0
  74. manim/scene/three_d_scene.py +5 -6
  75. manim/scene/vector_space_scene.py +21 -5
  76. manim/typing.py +567 -67
  77. manim/utils/bezier.py +9 -18
  78. manim/utils/caching.py +2 -0
  79. manim/utils/color/BS381.py +1 -0
  80. manim/utils/color/XKCD.py +1 -0
  81. manim/utils/color/core.py +31 -13
  82. manim/utils/commands.py +8 -1
  83. manim/utils/debug.py +0 -1
  84. manim/utils/deprecation.py +3 -2
  85. manim/utils/docbuild/__init__.py +17 -0
  86. manim/utils/docbuild/autoaliasattr_directive.py +197 -0
  87. manim/utils/docbuild/autocolor_directive.py +9 -4
  88. manim/utils/docbuild/manim_directive.py +18 -9
  89. manim/utils/docbuild/module_parsing.py +198 -0
  90. manim/utils/exceptions.py +6 -0
  91. manim/utils/family.py +2 -0
  92. manim/utils/family_ops.py +5 -0
  93. manim/utils/file_ops.py +6 -2
  94. manim/utils/hashing.py +2 -0
  95. manim/utils/ipython_magic.py +2 -0
  96. manim/utils/module_ops.py +2 -0
  97. manim/utils/opengl.py +14 -0
  98. manim/utils/parameter_parsing.py +31 -0
  99. manim/utils/paths.py +12 -20
  100. manim/utils/rate_functions.py +6 -8
  101. manim/utils/space_ops.py +81 -36
  102. manim/utils/testing/__init__.py +17 -0
  103. manim/utils/testing/frames_comparison.py +7 -5
  104. manim/utils/tex.py +124 -196
  105. manim/utils/tex_file_writing.py +2 -0
  106. manim/utils/tex_templates.py +1 -0
  107. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
  108. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
  109. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/RECORD +112 -112
  110. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/WHEEL +1 -1
  111. manim/cli/new/__init__.py +0 -0
  112. manim/cli/new/group.py +0 -189
  113. manim/plugins/import_plugins.py +0 -43
  114. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/LICENSE +0 -0
  115. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/entry_points.txt +0 -0
@@ -441,9 +441,9 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
441
441
  if self.should_center:
442
442
  self.center()
443
443
  if self.svg_height is not None:
444
- self.set_height(self.svg_height)
444
+ self.set(height=self.svg_height)
445
445
  if self.svg_width is not None:
446
- self.set_width(self.svg_width)
446
+ self.set(width=self.svg_width)
447
447
 
448
448
 
449
449
  class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
@@ -510,17 +510,15 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
510
510
  all_points: list[np.ndarray] = []
511
511
  last_move = None
512
512
  curve_start = None
513
+ last_true_move = None
513
514
 
514
- # These lambdas behave the same as similar functions in
515
- # vectorized_mobject, except they add to a list of points instead
516
- # of updating this Mobject's numpy array of points. This way,
517
- # we don't observe O(n^2) behavior for complex paths due to
518
- # numpy's need to re-allocate memory on every append.
519
- def move_pen(pt):
520
- nonlocal last_move, curve_start
515
+ def move_pen(pt, *, true_move: bool = False):
516
+ nonlocal last_move, curve_start, last_true_move
521
517
  last_move = pt
522
518
  if curve_start is None:
523
519
  curve_start = last_move
520
+ if true_move:
521
+ last_true_move = last_move
524
522
 
525
523
  if self.n_points_per_curve == 4:
526
524
 
@@ -568,7 +566,7 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
568
566
  for segment in self.path_obj:
569
567
  segment_class = segment.__class__
570
568
  if segment_class == se.Move:
571
- move_pen(_convert_point_to_3d(*segment.end))
569
+ move_pen(_convert_point_to_3d(*segment.end), true_move=True)
572
570
  elif segment_class == se.Line:
573
571
  add_line(last_move, _convert_point_to_3d(*segment.end))
574
572
  elif segment_class == se.QuadraticBezier:
@@ -588,8 +586,8 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
588
586
  # If the SVG path naturally ends at the beginning of the curve,
589
587
  # we do *not* need to draw a closing line. To account for floating
590
588
  # point precision, we use a small value to compare the two points.
591
- if abs(np.linalg.norm(last_move - curve_start)) > 0.0001:
592
- add_line(last_move, curve_start)
589
+ if abs(np.linalg.norm(last_move - last_true_move)) > 0.0001:
590
+ add_line(last_move, last_true_move)
593
591
  curve_start = None
594
592
  else:
595
593
  raise AssertionError(f"Not implemented: {segment_class}")
manim/mobject/table.py CHANGED
@@ -74,7 +74,6 @@ from manim.mobject.text.numbers import DecimalNumber, Integer
74
74
  from manim.mobject.text.tex_mobject import MathTex
75
75
  from manim.mobject.text.text_mobject import Paragraph
76
76
 
77
- from .. import config
78
77
  from ..animation.animation import Animation
79
78
  from ..animation.composition import AnimationGroup
80
79
  from ..animation.creation import Create, Write
@@ -26,6 +26,8 @@ from manim.mobject.text.text_mobject import Paragraph
26
26
  from manim.mobject.types.vectorized_mobject import VGroup
27
27
  from manim.utils.color import WHITE
28
28
 
29
+ __all__ = ["Code"]
30
+
29
31
 
30
32
  class Code(VGroup):
31
33
  """A highlighted source code listing.
@@ -18,6 +18,8 @@ from manim.mobject.value_tracker import ValueTracker
18
18
 
19
19
  string_to_mob_map = {}
20
20
 
21
+ __all__ = ["DecimalNumber", "Integer", "Variable"]
22
+
21
23
 
22
24
  class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
23
25
  """An mobject representing a decimal number.
@@ -34,7 +34,7 @@ from manim import config, logger
34
34
  from manim.constants import *
35
35
  from manim.mobject.geometry.line import Line
36
36
  from manim.mobject.svg.svg_mobject import SVGMobject
37
- from manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject
37
+ from manim.mobject.types.vectorized_mobject import VGroup, VMobject
38
38
  from manim.utils.tex import TexTemplate
39
39
  from manim.utils.tex_file_writing import tex_to_svg_file
40
40
 
@@ -49,6 +49,8 @@ Examples
49
49
 
50
50
  from __future__ import annotations
51
51
 
52
+ import functools
53
+
52
54
  __all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
53
55
 
54
56
 
@@ -77,6 +79,8 @@ TEXT_MOB_SCALE_FACTOR = 0.05
77
79
  DEFAULT_LINE_SPACING_SCALE = 0.3
78
80
  TEXT2SVG_ADJUSTMENT_FACTOR = 4.8
79
81
 
82
+ __all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
83
+
80
84
 
81
85
  def remove_invisible_chars(mobject: SVGMobject) -> SVGMobject:
82
86
  """Function to remove unwanted invisible characters from some mobjects.
@@ -350,7 +354,7 @@ class Text(SVGMobject):
350
354
  )
351
355
  text6.scale(1.3).shift(DOWN)
352
356
  self.add(text1, text2, text3, text4, text5 , text6)
353
- Group(*self.mobjects).arrange(DOWN, buff=.8).set_height(config.frame_height-LARGE_BUFF)
357
+ Group(*self.mobjects).arrange(DOWN, buff=.8).set(height=config.frame_height-LARGE_BUFF)
354
358
 
355
359
  .. manim:: TextMoreCustomization
356
360
  :save_last_frame:
@@ -407,6 +411,11 @@ class Text(SVGMobject):
407
411
 
408
412
  """
409
413
 
414
+ @staticmethod
415
+ @functools.lru_cache(maxsize=None)
416
+ def font_list() -> list[str]:
417
+ return manimpango.list_fonts()
418
+
410
419
  def __init__(
411
420
  self,
412
421
  text: str,
@@ -431,13 +440,25 @@ class Text(SVGMobject):
431
440
  width: float = None,
432
441
  should_center: bool = True,
433
442
  disable_ligatures: bool = False,
443
+ use_svg_cache: bool = False,
434
444
  **kwargs,
435
445
  ) -> None:
436
446
  self.line_spacing = line_spacing
437
447
  if font and warn_missing_font:
438
- fonts_list = manimpango.list_fonts()
448
+ fonts_list = Text.font_list()
449
+ # handle special case of sans/sans-serif
450
+ if font.lower() == "sans-serif":
451
+ font = "sans"
439
452
  if font not in fonts_list:
440
- logger.warning(f"Font {font} not in {fonts_list}.")
453
+ # check if the capitalized version is in the supported fonts
454
+ if font.capitalize() in fonts_list:
455
+ font = font.capitalize()
456
+ elif font.lower() in fonts_list:
457
+ font = font.lower()
458
+ elif font.title() in fonts_list:
459
+ font = font.title()
460
+ else:
461
+ logger.warning(f"Font {font} not in {fonts_list}.")
441
462
  self.font = font
442
463
  self._font_size = float(font_size)
443
464
  # needs to be a float or else size is inflated when font_size = 24
@@ -491,7 +512,7 @@ class Text(SVGMobject):
491
512
  height=height,
492
513
  width=width,
493
514
  should_center=should_center,
494
- use_svg_cache=False,
515
+ use_svg_cache=use_svg_cache,
495
516
  **kwargs,
496
517
  )
497
518
  self.text = text
@@ -1133,6 +1154,11 @@ class MarkupText(SVGMobject):
1133
1154
 
1134
1155
  """
1135
1156
 
1157
+ @staticmethod
1158
+ @functools.lru_cache(maxsize=None)
1159
+ def font_list() -> list[str]:
1160
+ return manimpango.list_fonts()
1161
+
1136
1162
  def __init__(
1137
1163
  self,
1138
1164
  text: str,
@@ -1157,9 +1183,20 @@ class MarkupText(SVGMobject):
1157
1183
  self.text = text
1158
1184
  self.line_spacing = line_spacing
1159
1185
  if font and warn_missing_font:
1160
- fonts_list = manimpango.list_fonts()
1186
+ fonts_list = Text.font_list()
1187
+ # handle special case of sans/sans-serif
1188
+ if font.lower() == "sans-serif":
1189
+ font = "sans"
1161
1190
  if font not in fonts_list:
1162
- logger.warning(f"Font {font} not in {fonts_list}.")
1191
+ # check if the capitalized version is in the supported fonts
1192
+ if font.capitalize() in fonts_list:
1193
+ font = font.capitalize()
1194
+ elif font.lower() in fonts_list:
1195
+ font = font.lower()
1196
+ elif font.title() in fonts_list:
1197
+ font = font.title()
1198
+ else:
1199
+ logger.warning(f"Font {font} not in {fonts_list}.")
1163
1200
  self.font = font
1164
1201
  self._font_size = float(font_size)
1165
1202
  self.slant = slant
@@ -22,7 +22,7 @@ from manim.constants import ORIGIN, UP
22
22
  from manim.utils.space_ops import get_unit_normal
23
23
 
24
24
  if TYPE_CHECKING:
25
- from manim.typing import Point3D, Vector
25
+ from manim.typing import Point3D, Vector3D
26
26
 
27
27
 
28
28
  def get_3d_vmob_gradient_start_and_end_points(vmob) -> tuple[Point3D, Point3D]:
@@ -52,7 +52,7 @@ def get_3d_vmob_end_corner(vmob) -> Point3D:
52
52
  return vmob.points[get_3d_vmob_end_corner_index(vmob)]
53
53
 
54
54
 
55
- def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector:
55
+ def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector3D:
56
56
  n_points = vmob.get_num_points()
57
57
  if len(vmob.get_anchors()) <= 2:
58
58
  return np.array(UP)
@@ -68,9 +68,9 @@ def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector:
68
68
  return unit_normal
69
69
 
70
70
 
71
- def get_3d_vmob_start_corner_unit_normal(vmob) -> Vector:
71
+ def get_3d_vmob_start_corner_unit_normal(vmob) -> Vector3D:
72
72
  return get_3d_vmob_unit_normal(vmob, get_3d_vmob_start_corner_index(vmob))
73
73
 
74
74
 
75
- def get_3d_vmob_end_corner_unit_normal(vmob) -> Vector:
75
+ def get_3d_vmob_end_corner_unit_normal(vmob) -> Vector3D:
76
76
  return get_3d_vmob_unit_normal(vmob, get_3d_vmob_end_corner_index(vmob))
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from manim.typing import Point3D, Vector3
5
+ from manim.typing import Point3D, Vector3D
6
6
  from manim.utils.color import BLUE, BLUE_D, BLUE_E, LIGHT_GREY, WHITE, interpolate_color
7
7
 
8
8
  __all__ = [
@@ -953,7 +953,7 @@ class Line3D(Cylinder):
953
953
  def pointify(
954
954
  self,
955
955
  mob_or_point: Mobject | Point3D,
956
- direction: Vector3 = None,
956
+ direction: Vector3D = None,
957
957
  ) -> np.ndarray:
958
958
  """Gets a point representing the center of the :class:`Mobjects <.Mobject>`.
959
959
 
@@ -1001,7 +1001,7 @@ class Line3D(Cylinder):
1001
1001
  def parallel_to(
1002
1002
  cls,
1003
1003
  line: Line3D,
1004
- point: Vector3 = ORIGIN,
1004
+ point: Vector3D = ORIGIN,
1005
1005
  length: float = 5,
1006
1006
  **kwargs,
1007
1007
  ) -> Line3D:
@@ -1049,7 +1049,7 @@ class Line3D(Cylinder):
1049
1049
  def perpendicular_to(
1050
1050
  cls,
1051
1051
  line: Line3D,
1052
- point: Vector3 = ORIGIN,
1052
+ point: Vector3D = ORIGIN,
1053
1053
  length: float = 5,
1054
1054
  **kwargs,
1055
1055
  ) -> Line3D:
@@ -19,6 +19,8 @@ from ...utils.bezier import interpolate
19
19
  from ...utils.color import WHITE, ManimColor, color_to_int_rgb
20
20
  from ...utils.images import change_to_rgba_array, get_full_raster_image_path
21
21
 
22
+ __all__ = ["ImageMobject", "ImageMobjectFromCamera"]
23
+
22
24
 
23
25
  class AbstractImageMobject(Mobject):
24
26
  """
@@ -191,7 +193,9 @@ class ImageMobject(AbstractImageMobject):
191
193
  self.pixel_array, self.pixel_array_dtype
192
194
  )
193
195
  if self.invert:
194
- self.pixel_array[:, :, :3] = 255 - self.pixel_array[:, :, :3]
196
+ self.pixel_array[:, :, :3] = (
197
+ np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3]
198
+ )
195
199
  super().__init__(scale_to_resolution, **kwargs)
196
200
 
197
201
  def get_pixel_array(self):
@@ -23,6 +23,8 @@ from ...utils.color import (
23
23
  )
24
24
  from ...utils.iterables import stretch_array_to_length
25
25
 
26
+ __all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"]
27
+
26
28
 
27
29
  class PMobject(Mobject, metaclass=ConvertToOpenGL):
28
30
  """A disc made of a cloud of Dots
@@ -26,20 +26,17 @@ from typing import (
26
26
  )
27
27
 
28
28
  import numpy as np
29
- import numpy.typing as npt
30
29
  from PIL.Image import Image
31
- from typing_extensions import Self
32
30
 
31
+ from manim import config
32
+ from manim.constants import *
33
+ from manim.mobject.mobject import Mobject
33
34
  from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
34
35
  from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
35
36
  from manim.mobject.three_d.three_d_utils import (
36
37
  get_3d_vmob_gradient_start_and_end_points,
37
38
  )
38
-
39
- from ... import config
40
- from ...constants import *
41
- from ...mobject.mobject import Mobject
42
- from ...utils.bezier import (
39
+ from manim.utils.bezier import (
43
40
  bezier,
44
41
  get_smooth_handle_points,
45
42
  integer_interpolate,
@@ -47,11 +44,19 @@ from ...utils.bezier import (
47
44
  partial_bezier_points,
48
45
  proportions_along_bezier_curve_for_point,
49
46
  )
50
- from ...utils.color import BLACK, WHITE, ManimColor, ParsableManimColor
51
- from ...utils.iterables import make_even, resize_array, stretch_array_to_length, tuplify
52
- from ...utils.space_ops import rotate_vector, shoelace_direction
47
+ from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor
48
+ from manim.utils.iterables import (
49
+ make_even,
50
+ resize_array,
51
+ stretch_array_to_length,
52
+ tuplify,
53
+ )
54
+ from manim.utils.space_ops import rotate_vector, shoelace_direction
53
55
 
54
56
  if TYPE_CHECKING:
57
+ import numpy.typing as npt
58
+ from typing_extensions import Self
59
+
55
60
  from manim.typing import (
56
61
  BezierPoints,
57
62
  CubicBezierPoints,
@@ -62,7 +67,7 @@ if TYPE_CHECKING:
62
67
  Point3D_Array,
63
68
  QuadraticBezierPoints,
64
69
  RGBA_Array_Float,
65
- Vector3,
70
+ Vector3D,
66
71
  Zeros,
67
72
  )
68
73
 
@@ -74,6 +79,16 @@ if TYPE_CHECKING:
74
79
  # - Think about length of self.points. Always 0 or 1 mod 4?
75
80
  # That's kind of weird.
76
81
 
82
+ __all__ = [
83
+ "VMobject",
84
+ "VGroup",
85
+ "VDict",
86
+ "VectorizedPoint",
87
+ "CurvesAsSubmobjects",
88
+ "VectorizedPoint",
89
+ "DashedVMobject",
90
+ ]
91
+
77
92
 
78
93
  class VMobject(Mobject):
79
94
  """A vectorized mobject.
@@ -114,7 +129,7 @@ class VMobject(Mobject):
114
129
  background_stroke_width: float = 0,
115
130
  sheen_factor: float = 0.0,
116
131
  joint_type: LineJointType | None = None,
117
- sheen_direction: Vector3 = UL,
132
+ sheen_direction: Vector3D = UL,
118
133
  close_new_points: bool = False,
119
134
  pre_function_handle_to_anchor_scale_factor: float = 0.01,
120
135
  make_smooth_after_applying_functions: bool = False,
@@ -123,6 +138,7 @@ class VMobject(Mobject):
123
138
  # TODO, do we care about accounting for varying zoom levels?
124
139
  tolerance_for_point_equality: float = 1e-6,
125
140
  n_points_per_cubic_curve: int = 4,
141
+ cap_style: CapStyleType = CapStyleType.AUTO,
126
142
  **kwargs,
127
143
  ):
128
144
  self.fill_opacity = fill_opacity
@@ -138,7 +154,7 @@ class VMobject(Mobject):
138
154
  self.joint_type: LineJointType = (
139
155
  LineJointType.AUTO if joint_type is None else joint_type
140
156
  )
141
- self.sheen_direction: Vector3 = sheen_direction
157
+ self.sheen_direction: Vector3D = sheen_direction
142
158
  self.close_new_points: bool = close_new_points
143
159
  self.pre_function_handle_to_anchor_scale_factor: float = (
144
160
  pre_function_handle_to_anchor_scale_factor
@@ -150,6 +166,7 @@ class VMobject(Mobject):
150
166
  self.shade_in_3d: bool = shade_in_3d
151
167
  self.tolerance_for_point_equality: float = tolerance_for_point_equality
152
168
  self.n_points_per_cubic_curve: int = n_points_per_cubic_curve
169
+ self.cap_style: CapStyleType = cap_style
153
170
  super().__init__(**kwargs)
154
171
  self.submobjects: list[VMobject]
155
172
 
@@ -335,11 +352,39 @@ class VMobject(Mobject):
335
352
  setattr(self, opacity_name, opacity)
336
353
  if color is not None and background:
337
354
  if isinstance(color, (list, tuple)):
338
- self.background_stroke_color = color
355
+ self.background_stroke_color = ManimColor.parse(color)
339
356
  else:
340
357
  self.background_stroke_color = ManimColor(color)
341
358
  return self
342
359
 
360
+ def set_cap_style(self, cap_style: CapStyleType) -> Self:
361
+ """
362
+ Sets the cap style of the :class:`VMobject`.
363
+
364
+ Parameters
365
+ ----------
366
+ cap_style
367
+ The cap style to be set. See :class:`.CapStyleType` for options.
368
+
369
+ Returns
370
+ -------
371
+ :class:`VMobject`
372
+ ``self``
373
+
374
+ Examples
375
+ --------
376
+ .. manim:: CapStyleExample
377
+ :save_last_frame:
378
+
379
+ class CapStyleExample(Scene):
380
+ def construct(self):
381
+ line = Line(LEFT, RIGHT, color=YELLOW, stroke_width=20)
382
+ line.set_cap_style(CapStyleType.ROUND)
383
+ self.add(line)
384
+ """
385
+ self.cap_style = cap_style
386
+ return self
387
+
343
388
  def set_background_stroke(self, **kwargs) -> Self:
344
389
  kwargs["background"] = True
345
390
  self.set_stroke(**kwargs)
@@ -356,7 +401,7 @@ class VMobject(Mobject):
356
401
  background_stroke_width: float | None = None,
357
402
  background_stroke_opacity: float | None = None,
358
403
  sheen_factor: float | None = None,
359
- sheen_direction: Vector3 | None = None,
404
+ sheen_direction: Vector3D | None = None,
360
405
  background_image: Image | str | None = None,
361
406
  family: bool = True,
362
407
  ) -> Self:
@@ -523,7 +568,7 @@ class VMobject(Mobject):
523
568
 
524
569
  color = property(get_color, set_color)
525
570
 
526
- def set_sheen_direction(self, direction: Vector3, family: bool = True) -> Self:
571
+ def set_sheen_direction(self, direction: Vector3D, family: bool = True) -> Self:
527
572
  """Sets the direction of the applied sheen.
528
573
 
529
574
  Parameters
@@ -548,11 +593,11 @@ class VMobject(Mobject):
548
593
  for submob in self.get_family():
549
594
  submob.sheen_direction = direction
550
595
  else:
551
- self.sheen_direction: Vector3 = direction
596
+ self.sheen_direction: Vector3D = direction
552
597
  return self
553
598
 
554
599
  def rotate_sheen_direction(
555
- self, angle: float, axis: Vector3 = OUT, family: bool = True
600
+ self, angle: float, axis: Vector3D = OUT, family: bool = True
556
601
  ) -> Self:
557
602
  """Rotates the direction of the applied sheen.
558
603
 
@@ -585,7 +630,7 @@ class VMobject(Mobject):
585
630
  return self
586
631
 
587
632
  def set_sheen(
588
- self, factor: float, direction: Vector3 | None = None, family: bool = True
633
+ self, factor: float, direction: Vector3D | None = None, family: bool = True
589
634
  ) -> Self:
590
635
  """Applies a color gradient from a direction.
591
636
 
@@ -623,7 +668,7 @@ class VMobject(Mobject):
623
668
  self.set_fill(self.get_fill_color(), family=family)
624
669
  return self
625
670
 
626
- def get_sheen_direction(self) -> Vector3:
671
+ def get_sheen_direction(self) -> Vector3D:
627
672
  return np.array(self.sheen_direction)
628
673
 
629
674
  def get_sheen_factor(self) -> float:
@@ -917,6 +962,27 @@ class VMobject(Mobject):
917
962
  -------
918
963
  :class:`VMobject`
919
964
  ``self``
965
+
966
+
967
+ Examples
968
+ --------
969
+ .. manim:: PointsAsCornersExample
970
+ :save_last_frame:
971
+
972
+ class PointsAsCornersExample(Scene):
973
+ def construct(self):
974
+ corners = (
975
+ # create square
976
+ UR, UL,
977
+ DL, DR,
978
+ UR,
979
+ # create crosses
980
+ DL, UL,
981
+ DR
982
+ )
983
+ vmob = VMobject(stroke_color=RED)
984
+ vmob.set_points_as_corners(corners).scale(2)
985
+ self.add(vmob)
920
986
  """
921
987
  nppcc = self.n_points_per_cubic_curve
922
988
  points = np.array(points)
@@ -998,7 +1064,7 @@ class VMobject(Mobject):
998
1064
  def rotate(
999
1065
  self,
1000
1066
  angle: float,
1001
- axis: Vector3 = OUT,
1067
+ axis: Vector3D = OUT,
1002
1068
  about_point: Point3D | None = None,
1003
1069
  **kwargs,
1004
1070
  ) -> Self:
@@ -1342,6 +1408,22 @@ class VMobject(Mobject):
1342
1408
  If ``alpha`` is not between 0 and 1.
1343
1409
  :exc:`Exception`
1344
1410
  If the :class:`VMobject` has no points.
1411
+
1412
+ Example
1413
+ -------
1414
+ .. manim:: PointFromProportion
1415
+ :save_last_frame:
1416
+
1417
+ class PointFromProportion(Scene):
1418
+ def construct(self):
1419
+ line = Line(2*DL, 2*UR)
1420
+ self.add(line)
1421
+ colors = (RED, BLUE, YELLOW)
1422
+ proportions = (1/4, 1/2, 3/4)
1423
+ for color, proportion in zip(colors, proportions):
1424
+ self.add(Dot(color=color).move_to(
1425
+ line.point_from_proportion(proportion)
1426
+ ))
1345
1427
  """
1346
1428
 
1347
1429
  if alpha < 0 or alpha > 1:
@@ -1366,6 +1448,9 @@ class VMobject(Mobject):
1366
1448
  return curve(residue)
1367
1449
 
1368
1450
  current_length += length
1451
+ raise Exception(
1452
+ "Not sure how you reached here, please file a bug report at https://github.com/ManimCommunity/manim/issues/new/choose"
1453
+ )
1369
1454
 
1370
1455
  def proportion_from_point(
1371
1456
  self,
@@ -1468,9 +1553,10 @@ class VMobject(Mobject):
1468
1553
  """
1469
1554
  if self.points.shape[0] == 1:
1470
1555
  return self.points
1471
- return np.array(
1472
- tuple(it.chain(*zip(self.get_start_anchors(), self.get_end_anchors()))),
1473
- )
1556
+
1557
+ s = self.get_start_anchors()
1558
+ e = self.get_end_anchors()
1559
+ return list(it.chain.from_iterable(zip(s, e)))
1474
1560
 
1475
1561
  def get_points_defining_boundary(self) -> Point3D_Array:
1476
1562
  # Probably returns all anchors, but this is weird regarding the name of the method.
@@ -1690,7 +1776,10 @@ class VMobject(Mobject):
1690
1776
  interpolate(getattr(mobject1, attr), getattr(mobject2, attr), alpha),
1691
1777
  )
1692
1778
  if alpha == 1.0:
1693
- setattr(self, attr, getattr(mobject2, attr))
1779
+ val = getattr(mobject2, attr)
1780
+ if isinstance(val, np.ndarray):
1781
+ val = val.copy()
1782
+ setattr(self, attr, val)
1694
1783
 
1695
1784
  def pointwise_become_partial(
1696
1785
  self,
@@ -1963,8 +2052,14 @@ class VGroup(VMobject, metaclass=ConvertToOpenGL):
1963
2052
  (gr-circle_red).animate.shift(RIGHT)
1964
2053
  )
1965
2054
  """
1966
- if not all(isinstance(m, (VMobject, OpenGLVMobject)) for m in vmobjects):
1967
- raise TypeError("All submobjects must be of type VMobject")
2055
+ for m in vmobjects:
2056
+ if not isinstance(m, (VMobject, OpenGLVMobject)):
2057
+ raise TypeError(
2058
+ f"All submobjects of {self.__class__.__name__} must be of type VMobject. "
2059
+ f"Got {repr(m)} ({type(m).__name__}) instead. "
2060
+ "You can try using `Group` instead."
2061
+ )
2062
+
1968
2063
  return super().add(*vmobjects)
1969
2064
 
1970
2065
  def __add__(self, vmobject: VMobject) -> Self:
@@ -2458,7 +2553,7 @@ class CurvesAsSubmobjects(VGroup):
2458
2553
  if len(self.submobjects) == 0:
2459
2554
  caller_name = sys._getframe(1).f_code.co_name
2460
2555
  raise Exception(
2461
- f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject with no submobjects"
2556
+ f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject with no submobjects"
2462
2557
  )
2463
2558
 
2464
2559
  def _get_submobjects_with_points(self):
@@ -2468,7 +2563,7 @@ class CurvesAsSubmobjects(VGroup):
2468
2563
  if len(submobjs_with_pts) == 0:
2469
2564
  caller_name = sys._getframe(1).f_code.co_name
2470
2565
  raise Exception(
2471
- f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject whose submobjects have no points"
2566
+ f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject whose submobjects have no points"
2472
2567
  )
2473
2568
  return submobjs_with_pts
2474
2569
 
@@ -45,7 +45,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
45
45
  self.wait(1)
46
46
  tracker -= 4
47
47
  self.wait(0.5)
48
- self.play(tracker.animate.set_value(5)),
48
+ self.play(tracker.animate.set_value(5))
49
49
  self.wait(0.5)
50
50
  self.play(tracker.animate.set_value(3))
51
51
  self.play(tracker.animate.increment_value(-2))
@@ -71,7 +71,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
71
71
 
72
72
  def __init__(self, value=0, **kwargs):
73
73
  super().__init__(**kwargs)
74
- self.set_points(np.zeros((1, 3)))
74
+ self.set(points=np.zeros((1, 3)))
75
75
  self.set_value(value)
76
76
 
77
77
  def get_value(self) -> float:
@@ -132,7 +132,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
132
132
  Turns self into an interpolation between mobject1
133
133
  and mobject2.
134
134
  """
135
- self.set_points(path_func(mobject1.points, mobject2.points, alpha))
135
+ self.set(points=path_func(mobject1.points, mobject2.points, alpha))
136
136
  return self
137
137
 
138
138
 
@@ -829,7 +829,9 @@ class StreamLines(VectorField):
829
829
  step = max(1, int(len(points) / self.max_anchors_per_line))
830
830
  line.set_points_smoothly(points[::step])
831
831
  if self.single_color:
832
- line.set_stroke(self.color)
832
+ line.set_stroke(
833
+ color=self.color, width=self.stroke_width, opacity=opacity
834
+ )
833
835
  else:
834
836
  if config.renderer == RendererType.OPENGL:
835
837
  # scaled for compatibility with cairo
manim/plugins/__init__.py CHANGED
@@ -1,3 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- from .import_plugins import *
3
+ from manim import config, logger
4
+
5
+ from .plugins_flags import get_plugins, list_plugins
6
+
7
+ __all__ = [
8
+ "get_plugins",
9
+ "list_plugins",
10
+ ]
11
+
12
+ requested_plugins: set[str] = set(config["plugins"])
13
+ missing_plugins = requested_plugins - set(get_plugins().keys())
14
+
15
+
16
+ if missing_plugins:
17
+ logger.warning("Missing Plugins: %s", missing_plugins)