manim 0.18.0.post0__py3-none-any.whl → 0.19.0__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 (146) hide show
  1. manim/__init__.py +3 -6
  2. manim/__main__.py +61 -20
  3. manim/_config/__init__.py +6 -3
  4. manim/_config/cli_colors.py +16 -8
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +14 -8
  7. manim/_config/utils.py +651 -472
  8. manim/animation/animation.py +152 -5
  9. manim/animation/composition.py +80 -39
  10. manim/animation/creation.py +196 -14
  11. manim/animation/fading.py +5 -9
  12. manim/animation/indication.py +103 -47
  13. manim/animation/movement.py +22 -5
  14. manim/animation/rotation.py +3 -2
  15. manim/animation/specialized.py +4 -6
  16. manim/animation/speedmodifier.py +10 -5
  17. manim/animation/transform.py +4 -5
  18. manim/animation/transform_matching_parts.py +1 -1
  19. manim/animation/updaters/mobject_update_utils.py +17 -14
  20. manim/camera/camera.py +15 -6
  21. manim/cli/__init__.py +17 -0
  22. manim/cli/cfg/group.py +70 -44
  23. manim/cli/checkhealth/checks.py +93 -75
  24. manim/cli/checkhealth/commands.py +14 -5
  25. manim/cli/default_group.py +157 -25
  26. manim/cli/init/commands.py +32 -24
  27. manim/cli/plugins/commands.py +16 -3
  28. manim/cli/render/commands.py +72 -60
  29. manim/cli/render/ease_of_access_options.py +4 -3
  30. manim/cli/render/global_options.py +51 -15
  31. manim/cli/render/output_options.py +6 -5
  32. manim/cli/render/render_options.py +97 -32
  33. manim/constants.py +65 -19
  34. manim/gui/gui.py +2 -0
  35. manim/mobject/frame.py +0 -1
  36. manim/mobject/geometry/arc.py +112 -78
  37. manim/mobject/geometry/boolean_ops.py +32 -25
  38. manim/mobject/geometry/labeled.py +300 -77
  39. manim/mobject/geometry/line.py +132 -64
  40. manim/mobject/geometry/polygram.py +126 -30
  41. manim/mobject/geometry/shape_matchers.py +35 -15
  42. manim/mobject/geometry/tips.py +38 -29
  43. manim/mobject/graph.py +414 -133
  44. manim/mobject/graphing/coordinate_systems.py +126 -64
  45. manim/mobject/graphing/functions.py +25 -15
  46. manim/mobject/graphing/number_line.py +24 -10
  47. manim/mobject/graphing/probability.py +2 -10
  48. manim/mobject/graphing/scale.py +6 -5
  49. manim/mobject/matrix.py +17 -19
  50. manim/mobject/mobject.py +314 -165
  51. manim/mobject/opengl/opengl_compatibility.py +2 -0
  52. manim/mobject/opengl/opengl_geometry.py +30 -9
  53. manim/mobject/opengl/opengl_image_mobject.py +2 -0
  54. manim/mobject/opengl/opengl_mobject.py +509 -343
  55. manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
  56. manim/mobject/opengl/opengl_surface.py +3 -2
  57. manim/mobject/opengl/opengl_three_dimensions.py +2 -0
  58. manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
  59. manim/mobject/svg/brace.py +63 -13
  60. manim/mobject/svg/svg_mobject.py +4 -3
  61. manim/mobject/table.py +11 -13
  62. manim/mobject/text/code_mobject.py +186 -548
  63. manim/mobject/text/numbers.py +9 -7
  64. manim/mobject/text/tex_mobject.py +23 -14
  65. manim/mobject/text/text_mobject.py +70 -24
  66. manim/mobject/three_d/polyhedra.py +98 -1
  67. manim/mobject/three_d/three_d_utils.py +4 -4
  68. manim/mobject/three_d/three_dimensions.py +62 -34
  69. manim/mobject/types/image_mobject.py +42 -24
  70. manim/mobject/types/point_cloud_mobject.py +105 -67
  71. manim/mobject/types/vectorized_mobject.py +496 -228
  72. manim/mobject/value_tracker.py +5 -4
  73. manim/mobject/vector_field.py +5 -5
  74. manim/opengl/__init__.py +3 -3
  75. manim/plugins/__init__.py +14 -1
  76. manim/plugins/plugins_flags.py +14 -8
  77. manim/renderer/cairo_renderer.py +20 -10
  78. manim/renderer/opengl_renderer.py +21 -23
  79. manim/renderer/opengl_renderer_window.py +2 -0
  80. manim/renderer/shader.py +2 -3
  81. manim/renderer/shader_wrapper.py +5 -2
  82. manim/renderer/vectorized_mobject_rendering.py +5 -0
  83. manim/scene/moving_camera_scene.py +23 -0
  84. manim/scene/scene.py +90 -43
  85. manim/scene/scene_file_writer.py +316 -165
  86. manim/scene/section.py +17 -15
  87. manim/scene/three_d_scene.py +13 -21
  88. manim/scene/vector_space_scene.py +22 -9
  89. manim/typing.py +830 -70
  90. manim/utils/bezier.py +1667 -399
  91. manim/utils/caching.py +13 -5
  92. manim/utils/color/AS2700.py +2 -0
  93. manim/utils/color/BS381.py +3 -0
  94. manim/utils/color/DVIPSNAMES.py +96 -0
  95. manim/utils/color/SVGNAMES.py +179 -0
  96. manim/utils/color/X11.py +3 -0
  97. manim/utils/color/XKCD.py +3 -0
  98. manim/utils/color/__init__.py +8 -5
  99. manim/utils/color/core.py +844 -309
  100. manim/utils/color/manim_colors.py +7 -9
  101. manim/utils/commands.py +48 -20
  102. manim/utils/config_ops.py +18 -13
  103. manim/utils/debug.py +8 -7
  104. manim/utils/deprecation.py +90 -40
  105. manim/utils/docbuild/__init__.py +17 -0
  106. manim/utils/docbuild/autoaliasattr_directive.py +234 -0
  107. manim/utils/docbuild/autocolor_directive.py +21 -17
  108. manim/utils/docbuild/manim_directive.py +50 -35
  109. manim/utils/docbuild/module_parsing.py +245 -0
  110. manim/utils/exceptions.py +6 -0
  111. manim/utils/family.py +5 -3
  112. manim/utils/family_ops.py +17 -4
  113. manim/utils/file_ops.py +26 -16
  114. manim/utils/hashing.py +9 -7
  115. manim/utils/images.py +10 -4
  116. manim/utils/ipython_magic.py +14 -8
  117. manim/utils/iterables.py +161 -119
  118. manim/utils/module_ops.py +57 -19
  119. manim/utils/opengl.py +83 -24
  120. manim/utils/parameter_parsing.py +32 -0
  121. manim/utils/paths.py +21 -23
  122. manim/utils/polylabel.py +168 -0
  123. manim/utils/qhull.py +218 -0
  124. manim/utils/rate_functions.py +74 -39
  125. manim/utils/simple_functions.py +24 -15
  126. manim/utils/sounds.py +7 -1
  127. manim/utils/space_ops.py +125 -69
  128. manim/utils/testing/__init__.py +17 -0
  129. manim/utils/testing/_frames_testers.py +13 -8
  130. manim/utils/testing/_show_diff.py +5 -3
  131. manim/utils/testing/_test_class_makers.py +33 -18
  132. manim/utils/testing/frames_comparison.py +27 -19
  133. manim/utils/tex.py +127 -197
  134. manim/utils/tex_file_writing.py +47 -45
  135. manim/utils/tex_templates.py +2 -1
  136. manim/utils/unit.py +6 -5
  137. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
  138. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
  139. manim-0.19.0.dist-info/RECORD +221 -0
  140. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
  141. manim/cli/new/__init__.py +0 -0
  142. manim/cli/new/group.py +0 -189
  143. manim/plugins/import_plugins.py +0 -43
  144. manim-0.18.0.post0.dist-info/RECORD +0 -217
  145. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
  146. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
@@ -2,17 +2,116 @@ r"""Mobjects that inherit from lines and contain a label along the length."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __all__ = ["LabeledLine", "LabeledArrow"]
5
+ __all__ = ["Label", "LabeledLine", "LabeledArrow", "LabeledPolygram"]
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ import numpy as np
6
10
 
7
11
  from manim.constants import *
8
12
  from manim.mobject.geometry.line import Arrow, Line
13
+ from manim.mobject.geometry.polygram import Polygram
9
14
  from manim.mobject.geometry.shape_matchers import (
10
15
  BackgroundRectangle,
11
16
  SurroundingRectangle,
12
17
  )
13
18
  from manim.mobject.text.tex_mobject import MathTex, Tex
14
19
  from manim.mobject.text.text_mobject import Text
15
- from manim.utils.color import WHITE, ManimColor, ParsableManimColor
20
+ from manim.mobject.types.vectorized_mobject import VGroup
21
+ from manim.utils.color import WHITE
22
+ from manim.utils.polylabel import polylabel
23
+
24
+ if TYPE_CHECKING:
25
+ from typing import Any
26
+
27
+ from manim.typing import Point3DLike_Array
28
+
29
+
30
+ class Label(VGroup):
31
+ """A Label consisting of text surrounded by a frame.
32
+
33
+ Parameters
34
+ ----------
35
+ label
36
+ Label that will be displayed.
37
+ label_config
38
+ A dictionary containing the configuration for the label.
39
+ This is only applied if ``label`` is of type ``str``.
40
+ box_config
41
+ A dictionary containing the configuration for the background box.
42
+ frame_config
43
+ A dictionary containing the configuration for the frame.
44
+
45
+ Examples
46
+ --------
47
+ .. manim:: LabelExample
48
+ :save_last_frame:
49
+ :quality: high
50
+
51
+ class LabelExample(Scene):
52
+ def construct(self):
53
+ label = Label(
54
+ label=Text('Label Text', font='sans-serif'),
55
+ box_config = {
56
+ "color" : BLUE,
57
+ "fill_opacity" : 0.75
58
+ }
59
+ )
60
+ label.scale(3)
61
+ self.add(label)
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ label: str | Tex | MathTex | Text,
67
+ label_config: dict[str, Any] | None = None,
68
+ box_config: dict[str, Any] | None = None,
69
+ frame_config: dict[str, Any] | None = None,
70
+ **kwargs: Any,
71
+ ) -> None:
72
+ super().__init__(**kwargs)
73
+
74
+ # Setup Defaults
75
+ default_label_config: dict[str, Any] = {
76
+ "color": WHITE,
77
+ "font_size": DEFAULT_FONT_SIZE,
78
+ }
79
+
80
+ default_box_config: dict[str, Any] = {
81
+ "color": None,
82
+ "buff": 0.05,
83
+ "fill_opacity": 1,
84
+ "stroke_width": 0.5,
85
+ }
86
+
87
+ default_frame_config: dict[str, Any] = {
88
+ "color": WHITE,
89
+ "buff": 0.05,
90
+ "stroke_width": 0.5,
91
+ }
92
+
93
+ # Merge Defaults
94
+ label_config = default_label_config | (label_config or {})
95
+ box_config = default_box_config | (box_config or {})
96
+ frame_config = default_frame_config | (frame_config or {})
97
+
98
+ # Determine the type of label and instantiate the appropriate object
99
+ self.rendered_label: MathTex | Tex | Text
100
+ if isinstance(label, str):
101
+ self.rendered_label = MathTex(label, **label_config)
102
+ elif isinstance(label, (MathTex, Tex, Text)):
103
+ self.rendered_label = label
104
+ else:
105
+ raise TypeError("Unsupported label type. Must be MathTex, Tex, or Text.")
106
+
107
+ # Add a background box
108
+ self.background_rect = BackgroundRectangle(self.rendered_label, **box_config)
109
+
110
+ # Add a frame around the label
111
+ self.frame = SurroundingRectangle(self.rendered_label, **frame_config)
112
+
113
+ # Add components to the VGroup
114
+ self.add(self.background_rect, self.rendered_label, self.frame)
16
115
 
17
116
 
18
117
  class LabeledLine(Line):
@@ -20,42 +119,38 @@ class LabeledLine(Line):
20
119
 
21
120
  Parameters
22
121
  ----------
23
- label : str | Tex | MathTex | Text
122
+ label
24
123
  Label that will be displayed on the line.
25
- label_position : float | optional
124
+ label_position
26
125
  A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5.
27
- font_size : float | optional
28
- Control font size for the label. This parameter is only used when `label` is of type `str`.
29
- label_color: ParsableManimColor | optional
30
- The color of the label's text. This parameter is only used when `label` is of type `str`.
31
- label_frame : Bool | optional
32
- Add a `SurroundingRectangle` frame to the label box.
33
- frame_fill_color : ParsableManimColor | optional
34
- Background color to fill the label box. If no value is provided, the background color of the canvas will be used.
35
- frame_fill_opacity : float | optional
36
- Determine the opacity of the label box by passing a value in the range [0-1], where 0 indicates complete transparency and 1 means full opacity.
37
-
38
- .. seealso::
39
- :class:`LabeledArrow`
126
+ label_config
127
+ A dictionary containing the configuration for the label.
128
+ This is only applied if ``label`` is of type ``str``.
129
+ box_config
130
+ A dictionary containing the configuration for the background box.
131
+ frame_config
132
+ A dictionary containing the configuration for the frame.
133
+
134
+ .. seealso::
135
+ :class:`LabeledArrow`
40
136
 
41
137
  Examples
42
138
  --------
43
139
  .. manim:: LabeledLineExample
44
140
  :save_last_frame:
141
+ :quality: high
45
142
 
46
143
  class LabeledLineExample(Scene):
47
144
  def construct(self):
48
145
  line = LabeledLine(
49
146
  label = '0.5',
50
147
  label_position = 0.8,
51
- font_size = 20,
52
- label_color = WHITE,
53
- label_frame = True,
54
-
148
+ label_config = {
149
+ "font_size" : 20
150
+ },
55
151
  start=LEFT+DOWN,
56
152
  end=RIGHT+UP)
57
153
 
58
-
59
154
  line.set_length(line.get_length() * 2)
60
155
  self.add(line)
61
156
  """
@@ -64,50 +159,29 @@ class LabeledLine(Line):
64
159
  self,
65
160
  label: str | Tex | MathTex | Text,
66
161
  label_position: float = 0.5,
67
- font_size: float = DEFAULT_FONT_SIZE,
68
- label_color: ParsableManimColor = WHITE,
69
- label_frame: bool = True,
70
- frame_fill_color: ParsableManimColor = None,
71
- frame_fill_opacity: float = 1,
72
- *args,
73
- **kwargs,
162
+ label_config: dict[str, Any] | None = None,
163
+ box_config: dict[str, Any] | None = None,
164
+ frame_config: dict[str, Any] | None = None,
165
+ *args: Any,
166
+ **kwargs: Any,
74
167
  ) -> None:
75
- label_color = ManimColor(label_color)
76
- frame_fill_color = ManimColor(frame_fill_color)
77
- if isinstance(label, str):
78
- from manim import MathTex
79
-
80
- rendered_label = MathTex(label, color=label_color, font_size=font_size)
81
- else:
82
- rendered_label = label
83
-
84
168
  super().__init__(*args, **kwargs)
85
169
 
86
- # calculating the vector for the label position
170
+ # Create Label
171
+ self.label = Label(
172
+ label=label,
173
+ label_config=label_config,
174
+ box_config=box_config,
175
+ frame_config=frame_config,
176
+ )
177
+
178
+ # Compute Label Position
87
179
  line_start, line_end = self.get_start_and_end()
88
180
  new_vec = (line_end - line_start) * label_position
89
181
  label_coords = line_start + new_vec
90
182
 
91
- # rendered_label.move_to(self.get_vector() * label_position)
92
- rendered_label.move_to(label_coords)
93
-
94
- box = BackgroundRectangle(
95
- rendered_label,
96
- buff=0.05,
97
- color=frame_fill_color,
98
- fill_opacity=frame_fill_opacity,
99
- stroke_width=0.5,
100
- )
101
- self.add(box)
102
-
103
- if label_frame:
104
- box_frame = SurroundingRectangle(
105
- rendered_label, buff=0.05, color=label_color, stroke_width=0.5
106
- )
107
-
108
- self.add(box_frame)
109
-
110
- self.add(rendered_label)
183
+ self.label.move_to(label_coords)
184
+ self.add(self.label)
111
185
 
112
186
 
113
187
  class LabeledArrow(LabeledLine, Arrow):
@@ -116,29 +190,26 @@ class LabeledArrow(LabeledLine, Arrow):
116
190
 
117
191
  Parameters
118
192
  ----------
119
- label : str | Tex | MathTex | Text
120
- Label that will be displayed on the line.
121
- label_position : float | optional
193
+ label
194
+ Label that will be displayed on the Arrow.
195
+ label_position
122
196
  A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5.
123
- font_size : float | optional
124
- Control font size for the label. This parameter is only used when `label` is of type `str`.
125
- label_color: ParsableManimColor | optional
126
- The color of the label's text. This parameter is only used when `label` is of type `str`.
127
- label_frame : Bool | optional
128
- Add a `SurroundingRectangle` frame to the label box.
129
- frame_fill_color : ParsableManimColor | optional
130
- Background color to fill the label box. If no value is provided, the background color of the canvas will be used.
131
- frame_fill_opacity : float | optional
132
- Determine the opacity of the label box by passing a value in the range [0-1], where 0 indicates complete transparency and 1 means full opacity.
197
+ label_config
198
+ A dictionary containing the configuration for the label.
199
+ This is only applied if ``label`` is of type ``str``.
200
+ box_config
201
+ A dictionary containing the configuration for the background box.
202
+ frame_config
203
+ A dictionary containing the configuration for the frame.
133
204
 
134
-
135
- .. seealso::
136
- :class:`LabeledLine`
205
+ .. seealso::
206
+ :class:`LabeledLine`
137
207
 
138
208
  Examples
139
209
  --------
140
210
  .. manim:: LabeledArrowExample
141
211
  :save_last_frame:
212
+ :quality: high
142
213
 
143
214
  class LabeledArrowExample(Scene):
144
215
  def construct(self):
@@ -149,7 +220,159 @@ class LabeledArrow(LabeledLine, Arrow):
149
220
 
150
221
  def __init__(
151
222
  self,
152
- *args,
153
- **kwargs,
223
+ *args: Any,
224
+ **kwargs: Any,
154
225
  ) -> None:
155
226
  super().__init__(*args, **kwargs)
227
+
228
+
229
+ class LabeledPolygram(Polygram):
230
+ """Constructs a polygram containing a label box at its pole of inaccessibility.
231
+
232
+ Parameters
233
+ ----------
234
+ vertex_groups
235
+ Vertices passed to the :class:`~.Polygram` constructor.
236
+ label
237
+ Label that will be displayed on the Polygram.
238
+ precision
239
+ The precision used by the PolyLabel algorithm.
240
+ label_config
241
+ A dictionary containing the configuration for the label.
242
+ This is only applied if ``label`` is of type ``str``.
243
+ box_config
244
+ A dictionary containing the configuration for the background box.
245
+ frame_config
246
+ A dictionary containing the configuration for the frame.
247
+
248
+ .. note::
249
+ The PolyLabel Algorithm expects each vertex group to form a closed ring.
250
+ If the input is open, :class:`LabeledPolygram` will attempt to close it.
251
+ This may cause the polygon to intersect itself leading to unexpected results.
252
+
253
+ .. tip::
254
+ Make sure the precision corresponds to the scale of your inputs!
255
+ For instance, if the bounding box of your polygon stretches from 0 to 10,000, a precision of 1.0 or 10.0 should be sufficient.
256
+
257
+ Examples
258
+ --------
259
+ .. manim:: LabeledPolygramExample
260
+ :save_last_frame:
261
+ :quality: high
262
+
263
+ class LabeledPolygramExample(Scene):
264
+ def construct(self):
265
+ # Define Rings
266
+ ring1 = [
267
+ [-3.8, -2.4, 0], [-2.4, -2.5, 0], [-1.3, -1.6, 0], [-0.2, -1.7, 0],
268
+ [1.7, -2.5, 0], [2.9, -2.6, 0], [3.5, -1.5, 0], [4.9, -1.4, 0],
269
+ [4.5, 0.2, 0], [4.7, 1.6, 0], [3.5, 2.4, 0], [1.1, 2.5, 0],
270
+ [-0.1, 0.9, 0], [-1.2, 0.5, 0], [-1.6, 0.7, 0], [-1.4, 1.9, 0],
271
+ [-2.6, 2.6, 0], [-4.4, 1.2, 0], [-4.9, -0.8, 0], [-3.8, -2.4, 0]
272
+ ]
273
+ ring2 = [
274
+ [0.2, -1.2, 0], [0.9, -1.2, 0], [1.4, -2.0, 0], [2.1, -1.6, 0],
275
+ [2.2, -0.5, 0], [1.4, 0.0, 0], [0.4, -0.2, 0], [0.2, -1.2, 0]
276
+ ]
277
+ ring3 = [[-2.7, 1.4, 0], [-2.3, 1.7, 0], [-2.8, 1.9, 0], [-2.7, 1.4, 0]]
278
+
279
+ # Create Polygons (for reference)
280
+ p1 = Polygon(*ring1, fill_opacity=0.75)
281
+ p2 = Polygon(*ring2, fill_color=BLACK, fill_opacity=1)
282
+ p3 = Polygon(*ring3, fill_color=BLACK, fill_opacity=1)
283
+
284
+ # Create Labeled Polygram
285
+ polygram = LabeledPolygram(
286
+ *[ring1, ring2, ring3],
287
+ label=Text('Pole', font='sans-serif'),
288
+ precision=0.01,
289
+ )
290
+
291
+ # Display Circle (for reference)
292
+ circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole)
293
+
294
+ self.add(p1, p2, p3)
295
+ self.add(polygram)
296
+ self.add(circle)
297
+
298
+ .. manim:: LabeledCountryExample
299
+ :save_last_frame:
300
+ :quality: high
301
+
302
+ import requests
303
+ import json
304
+
305
+ class LabeledCountryExample(Scene):
306
+ def construct(self):
307
+ # Fetch JSON data and process arcs
308
+ data = requests.get('https://cdn.jsdelivr.net/npm/us-atlas@3/nation-10m.json').json()
309
+ arcs, transform = data['arcs'], data['transform']
310
+ sarcs = [np.cumsum(arc, axis=0) * transform['scale'] + transform['translate'] for arc in arcs]
311
+ ssarcs = sorted(sarcs, key=len, reverse=True)[:1]
312
+
313
+ # Compute Bounding Box
314
+ points = np.concatenate(ssarcs)
315
+ mins, maxs = np.min(points, axis=0), np.max(points, axis=0)
316
+
317
+ # Build Axes
318
+ ax = Axes(
319
+ x_range=[mins[0], maxs[0], maxs[0] - mins[0]], x_length=10,
320
+ y_range=[mins[1], maxs[1], maxs[1] - mins[1]], y_length=7,
321
+ tips=False
322
+ )
323
+
324
+ # Adjust Coordinates
325
+ array = [[ax.c2p(*point) for point in sarc] for sarc in ssarcs]
326
+
327
+ # Add Polygram
328
+ polygram = LabeledPolygram(
329
+ *array,
330
+ label=Text('USA', font='sans-serif'),
331
+ precision=0.01,
332
+ fill_color=BLUE,
333
+ stroke_width=0,
334
+ fill_opacity=0.75
335
+ )
336
+
337
+ # Display Circle (for reference)
338
+ circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole)
339
+
340
+ self.add(ax)
341
+ self.add(polygram)
342
+ self.add(circle)
343
+ """
344
+
345
+ def __init__(
346
+ self,
347
+ *vertex_groups: Point3DLike_Array,
348
+ label: str | Tex | MathTex | Text,
349
+ precision: float = 0.01,
350
+ label_config: dict[str, Any] | None = None,
351
+ box_config: dict[str, Any] | None = None,
352
+ frame_config: dict[str, Any] | None = None,
353
+ **kwargs: Any,
354
+ ) -> None:
355
+ # Initialize the Polygram with the vertex groups
356
+ super().__init__(*vertex_groups, **kwargs)
357
+
358
+ # Create Label
359
+ self.label = Label(
360
+ label=label,
361
+ label_config=label_config,
362
+ box_config=box_config,
363
+ frame_config=frame_config,
364
+ )
365
+
366
+ # Close Vertex Groups
367
+ rings = [
368
+ group if np.array_equal(group[0], group[-1]) else list(group) + [group[0]]
369
+ for group in vertex_groups
370
+ ]
371
+
372
+ # Compute the Pole of Inaccessibility
373
+ cell = polylabel(rings, precision=precision)
374
+ self.pole, self.radius = np.pad(cell.c, (0, 1), "constant"), cell.d
375
+
376
+ # Position the label at the pole
377
+ self.label.move_to(self.pole)
378
+ self.add(self.label)