Repository: ManimCommunity/manim Branch: main Commit: 21cf9998cc7a Files: 1305 Total size: 5.3 MB Directory structure: gitextract_kmopyg5o/ ├── .codecov.yml ├── .codespell_ignorewords ├── .codespellrc ├── .dockerignore ├── .flake8 ├── .git-blame-ignore-revs ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── installation_issue.md │ ├── PULL_REQUEST_TEMPLATE/ │ │ ├── bugfix.md │ │ ├── documentation.md │ │ └── hackathon.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── codeql.yml │ ├── dependabot.yml │ ├── manimdependency.json │ ├── release.yml │ ├── scripts/ │ │ └── ci_build_cairo.py │ └── workflows/ │ ├── cffconvert.yml │ ├── ci.yml │ ├── codeql.yml │ ├── dependent-issues.yml │ ├── publish-docker.yml │ ├── python-publish.yml │ └── release-publish-documentation.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .pylintrc ├── .readthedocs.yml ├── CITATION.cff ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.community ├── README.md ├── crowdin.yml ├── docker/ │ ├── Dockerfile │ ├── readme.md │ └── texlive-profile.txt ├── docs/ │ ├── Makefile │ ├── html │ ├── i18n/ │ │ ├── fr/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── index.po │ │ │ └── installation.po │ │ ├── gettext/ │ │ │ ├── changelog/ │ │ │ │ ├── 0.1.0-changelog.pot │ │ │ │ ├── 0.1.1-changelog.pot │ │ │ │ ├── 0.10.0-changelog.pot │ │ │ │ ├── 0.11.0-changelog.pot │ │ │ │ ├── 0.12.0-changelog.pot │ │ │ │ ├── 0.13.0-changelog.pot │ │ │ │ ├── 0.13.1-changelog.pot │ │ │ │ ├── 0.14.0-changelog.pot │ │ │ │ ├── 0.15.0-changelog.pot │ │ │ │ ├── 0.15.1-changelog.pot │ │ │ │ ├── 0.15.2-changelog.pot │ │ │ │ ├── 0.16.0-changelog.pot │ │ │ │ ├── 0.2.0-changelog.pot │ │ │ │ ├── 0.3.0-changelog.pot │ │ │ │ ├── 0.4.0-changelog.pot │ │ │ │ ├── 0.5.0-changelog.pot │ │ │ │ ├── 0.6.0-changelog.pot │ │ │ │ ├── 0.7.0-changelog.pot │ │ │ │ ├── 0.8.0-changelog.pot │ │ │ │ └── 0.9.0-changelog.pot │ │ │ ├── changelog.pot │ │ │ ├── conduct.pot │ │ │ ├── contributing/ │ │ │ │ ├── admonitions.pot │ │ │ │ ├── development.pot │ │ │ │ ├── docstrings.pot │ │ │ │ ├── examples.pot │ │ │ │ ├── internationalization.pot │ │ │ │ ├── performance.pot │ │ │ │ ├── references.pot │ │ │ │ ├── testing.pot │ │ │ │ └── typings.pot │ │ │ ├── contributing.pot │ │ │ ├── examples.pot │ │ │ ├── faq/ │ │ │ │ ├── general.pot │ │ │ │ ├── help.pot │ │ │ │ ├── index.pot │ │ │ │ ├── installation.pot │ │ │ │ ├── internals.pot │ │ │ │ └── opengl.pot │ │ │ ├── guides/ │ │ │ │ ├── configuration.pot │ │ │ │ ├── deep_dive.pot │ │ │ │ ├── index.pot │ │ │ │ └── using_text.pot │ │ │ ├── index.pot │ │ │ ├── installation/ │ │ │ │ ├── docker.pot │ │ │ │ ├── jupyter.pot │ │ │ │ ├── linux.pot │ │ │ │ ├── macos.pot │ │ │ │ ├── troubleshooting.pot │ │ │ │ ├── versions.pot │ │ │ │ └── windows.pot │ │ │ ├── installation.pot │ │ │ ├── internals.pot │ │ │ ├── plugins.pot │ │ │ ├── reference/ │ │ │ │ ├── manim._config.logger_utils.JSONFormatter.pot │ │ │ │ ├── manim._config.logger_utils.pot │ │ │ │ ├── manim._config.pot │ │ │ │ ├── manim._config.utils.ManimConfig.pot │ │ │ │ ├── manim._config.utils.ManimFrame.pot │ │ │ │ ├── manim._config.utils.pot │ │ │ │ ├── manim.animation.animation.Animation.pot │ │ │ │ ├── manim.animation.animation.Wait.pot │ │ │ │ ├── manim.animation.animation.pot │ │ │ │ ├── manim.animation.changing.AnimatedBoundary.pot │ │ │ │ ├── manim.animation.changing.TracedPath.pot │ │ │ │ ├── manim.animation.changing.pot │ │ │ │ ├── manim.animation.composition.AnimationGroup.pot │ │ │ │ ├── manim.animation.composition.LaggedStart.pot │ │ │ │ ├── manim.animation.composition.LaggedStartMap.pot │ │ │ │ ├── manim.animation.composition.Succession.pot │ │ │ │ ├── manim.animation.composition.pot │ │ │ │ ├── manim.animation.creation.AddTextLetterByLetter.pot │ │ │ │ ├── manim.animation.creation.AddTextWordByWord.pot │ │ │ │ ├── manim.animation.creation.Create.pot │ │ │ │ ├── manim.animation.creation.DrawBorderThenFill.pot │ │ │ │ ├── manim.animation.creation.ShowIncreasingSubsets.pot │ │ │ │ ├── manim.animation.creation.ShowPartial.pot │ │ │ │ ├── manim.animation.creation.ShowSubmobjectsOneByOne.pot │ │ │ │ ├── manim.animation.creation.SpiralIn.pot │ │ │ │ ├── manim.animation.creation.Uncreate.pot │ │ │ │ ├── manim.animation.creation.Unwrite.pot │ │ │ │ ├── manim.animation.creation.Write.pot │ │ │ │ ├── manim.animation.creation.pot │ │ │ │ ├── manim.animation.fading.FadeIn.pot │ │ │ │ ├── manim.animation.fading.FadeOut.pot │ │ │ │ ├── manim.animation.fading.pot │ │ │ │ ├── manim.animation.growing.GrowArrow.pot │ │ │ │ ├── manim.animation.growing.GrowFromCenter.pot │ │ │ │ ├── manim.animation.growing.GrowFromEdge.pot │ │ │ │ ├── manim.animation.growing.GrowFromPoint.pot │ │ │ │ ├── manim.animation.growing.SpinInFromNothing.pot │ │ │ │ ├── manim.animation.growing.pot │ │ │ │ ├── manim.animation.indication.ApplyWave.pot │ │ │ │ ├── manim.animation.indication.Circumscribe.pot │ │ │ │ ├── manim.animation.indication.Flash.pot │ │ │ │ ├── manim.animation.indication.FocusOn.pot │ │ │ │ ├── manim.animation.indication.Indicate.pot │ │ │ │ ├── manim.animation.indication.ShowCreationThenFadeOut.pot │ │ │ │ ├── manim.animation.indication.ShowPassingFlash.pot │ │ │ │ ├── manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.pot │ │ │ │ ├── manim.animation.indication.Wiggle.pot │ │ │ │ ├── manim.animation.indication.pot │ │ │ │ ├── manim.animation.movement.ComplexHomotopy.pot │ │ │ │ ├── manim.animation.movement.Homotopy.pot │ │ │ │ ├── manim.animation.movement.MoveAlongPath.pot │ │ │ │ ├── manim.animation.movement.PhaseFlow.pot │ │ │ │ ├── manim.animation.movement.SmoothedVectorizedHomotopy.pot │ │ │ │ ├── manim.animation.movement.pot │ │ │ │ ├── manim.animation.numbers.ChangeDecimalToValue.pot │ │ │ │ ├── manim.animation.numbers.ChangingDecimal.pot │ │ │ │ ├── manim.animation.numbers.pot │ │ │ │ ├── manim.animation.rotation.Rotate.pot │ │ │ │ ├── manim.animation.rotation.Rotating.pot │ │ │ │ ├── manim.animation.rotation.pot │ │ │ │ ├── manim.animation.specialized.Broadcast.pot │ │ │ │ ├── manim.animation.specialized.pot │ │ │ │ ├── manim.animation.speedmodifier.ChangeSpeed.pot │ │ │ │ ├── manim.animation.speedmodifier.pot │ │ │ │ ├── manim.animation.transform.ApplyComplexFunction.pot │ │ │ │ ├── manim.animation.transform.ApplyFunction.pot │ │ │ │ ├── manim.animation.transform.ApplyMatrix.pot │ │ │ │ ├── manim.animation.transform.ApplyMethod.pot │ │ │ │ ├── manim.animation.transform.ApplyPointwiseFunction.pot │ │ │ │ ├── manim.animation.transform.ApplyPointwiseFunctionToCenter.pot │ │ │ │ ├── manim.animation.transform.ClockwiseTransform.pot │ │ │ │ ├── manim.animation.transform.CounterclockwiseTransform.pot │ │ │ │ ├── manim.animation.transform.CyclicReplace.pot │ │ │ │ ├── manim.animation.transform.FadeToColor.pot │ │ │ │ ├── manim.animation.transform.FadeTransform.pot │ │ │ │ ├── manim.animation.transform.FadeTransformPieces.pot │ │ │ │ ├── manim.animation.transform.MoveToTarget.pot │ │ │ │ ├── manim.animation.transform.ReplacementTransform.pot │ │ │ │ ├── manim.animation.transform.Restore.pot │ │ │ │ ├── manim.animation.transform.ScaleInPlace.pot │ │ │ │ ├── manim.animation.transform.ShrinkToCenter.pot │ │ │ │ ├── manim.animation.transform.Swap.pot │ │ │ │ ├── manim.animation.transform.Transform.pot │ │ │ │ ├── manim.animation.transform.TransformAnimations.pot │ │ │ │ ├── manim.animation.transform.TransformFromCopy.pot │ │ │ │ ├── manim.animation.transform.pot │ │ │ │ ├── manim.animation.transform_matching_parts.TransformMatchingAbstractBase.pot │ │ │ │ ├── manim.animation.transform_matching_parts.TransformMatchingShapes.pot │ │ │ │ ├── manim.animation.transform_matching_parts.TransformMatchingTex.pot │ │ │ │ ├── manim.animation.transform_matching_parts.pot │ │ │ │ ├── manim.animation.update.MaintainPositionRelativeTo.pot │ │ │ │ ├── manim.animation.update.UpdateFromAlphaFunc.pot │ │ │ │ ├── manim.animation.update.UpdateFromFunc.pot │ │ │ │ ├── manim.animation.update.pot │ │ │ │ ├── manim.animation.updaters.mobject_update_utils.pot │ │ │ │ ├── manim.animation.updaters.pot │ │ │ │ ├── manim.animation.updaters.update.MaintainPositionRelativeTo.pot │ │ │ │ ├── manim.animation.updaters.update.UpdateFromAlphaFunc.pot │ │ │ │ ├── manim.animation.updaters.update.UpdateFromFunc.pot │ │ │ │ ├── manim.animation.updaters.update.pot │ │ │ │ ├── manim.camera.camera.BackgroundColoredVMobjectDisplayer.pot │ │ │ │ ├── manim.camera.camera.Camera.pot │ │ │ │ ├── manim.camera.camera.pot │ │ │ │ ├── manim.camera.mapping_camera.MappingCamera.pot │ │ │ │ ├── manim.camera.mapping_camera.OldMultiCamera.pot │ │ │ │ ├── manim.camera.mapping_camera.SplitScreenCamera.pot │ │ │ │ ├── manim.camera.mapping_camera.pot │ │ │ │ ├── manim.camera.moving_camera.CameraFrame.pot │ │ │ │ ├── manim.camera.moving_camera.MovingCamera.pot │ │ │ │ ├── manim.camera.moving_camera.pot │ │ │ │ ├── manim.camera.multi_camera.MultiCamera.pot │ │ │ │ ├── manim.camera.multi_camera.pot │ │ │ │ ├── manim.camera.three_d_camera.ThreeDCamera.pot │ │ │ │ ├── manim.camera.three_d_camera.pot │ │ │ │ ├── manim.constants.pot │ │ │ │ ├── manim.mobject.boolean_ops.Difference.pot │ │ │ │ ├── manim.mobject.boolean_ops.Exclusion.pot │ │ │ │ ├── manim.mobject.boolean_ops.Intersection.pot │ │ │ │ ├── manim.mobject.boolean_ops.Union.pot │ │ │ │ ├── manim.mobject.boolean_ops.pot │ │ │ │ ├── manim.mobject.changing.AnimatedBoundary.pot │ │ │ │ ├── manim.mobject.changing.TracedPath.pot │ │ │ │ ├── manim.mobject.changing.pot │ │ │ │ ├── manim.mobject.coordinate_systems.Axes.pot │ │ │ │ ├── manim.mobject.coordinate_systems.ComplexPlane.pot │ │ │ │ ├── manim.mobject.coordinate_systems.CoordinateSystem.pot │ │ │ │ ├── manim.mobject.coordinate_systems.NumberPlane.pot │ │ │ │ ├── manim.mobject.coordinate_systems.PolarPlane.pot │ │ │ │ ├── manim.mobject.coordinate_systems.ThreeDAxes.pot │ │ │ │ ├── manim.mobject.coordinate_systems.pot │ │ │ │ ├── manim.mobject.frame.FullScreenFadeRectangle.pot │ │ │ │ ├── manim.mobject.frame.FullScreenRectangle.pot │ │ │ │ ├── manim.mobject.frame.PictureInPictureFrame.pot │ │ │ │ ├── manim.mobject.frame.ScreenRectangle.pot │ │ │ │ ├── manim.mobject.frame.pot │ │ │ │ ├── manim.mobject.functions.FunctionGraph.pot │ │ │ │ ├── manim.mobject.functions.ImplicitFunction.pot │ │ │ │ ├── manim.mobject.functions.ParametricFunction.pot │ │ │ │ ├── manim.mobject.functions.pot │ │ │ │ ├── manim.mobject.geometry.Angle.pot │ │ │ │ ├── manim.mobject.geometry.AnnotationDot.pot │ │ │ │ ├── manim.mobject.geometry.AnnularSector.pot │ │ │ │ ├── manim.mobject.geometry.Annulus.pot │ │ │ │ ├── manim.mobject.geometry.ArcBetweenPoints.pot │ │ │ │ ├── manim.mobject.geometry.ArcPolygon.pot │ │ │ │ ├── manim.mobject.geometry.ArcPolygonFromArcs.pot │ │ │ │ ├── manim.mobject.geometry.Arrow.pot │ │ │ │ ├── manim.mobject.geometry.ArrowCircleFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowCircleTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowSquareFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowSquareTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowTriangleFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.ArrowTriangleTip.pot │ │ │ │ ├── manim.mobject.geometry.Circle.pot │ │ │ │ ├── manim.mobject.geometry.CubicBezier.pot │ │ │ │ ├── manim.mobject.geometry.CurvedArrow.pot │ │ │ │ ├── manim.mobject.geometry.CurvedDoubleArrow.pot │ │ │ │ ├── manim.mobject.geometry.Cutout.pot │ │ │ │ ├── manim.mobject.geometry.DashedLine.pot │ │ │ │ ├── manim.mobject.geometry.Dot.pot │ │ │ │ ├── manim.mobject.geometry.DoubleArrow.pot │ │ │ │ ├── manim.mobject.geometry.Elbow.pot │ │ │ │ ├── manim.mobject.geometry.Ellipse.pot │ │ │ │ ├── manim.mobject.geometry.LabeledDot.pot │ │ │ │ ├── manim.mobject.geometry.Polygon.pot │ │ │ │ ├── manim.mobject.geometry.Rectangle.pot │ │ │ │ ├── manim.mobject.geometry.RegularPolygon.pot │ │ │ │ ├── manim.mobject.geometry.RegularPolygram.pot │ │ │ │ ├── manim.mobject.geometry.RightAngle.pot │ │ │ │ ├── manim.mobject.geometry.RoundedRectangle.pot │ │ │ │ ├── manim.mobject.geometry.Sector.pot │ │ │ │ ├── manim.mobject.geometry.Square.pot │ │ │ │ ├── manim.mobject.geometry.Star.pot │ │ │ │ ├── manim.mobject.geometry.TangentLine.pot │ │ │ │ ├── manim.mobject.geometry.TipableVMobject.pot │ │ │ │ ├── manim.mobject.geometry.Triangle.pot │ │ │ │ ├── manim.mobject.geometry.Vector.pot │ │ │ │ ├── manim.mobject.geometry.arc.AnnotationDot.pot │ │ │ │ ├── manim.mobject.geometry.arc.AnnularSector.pot │ │ │ │ ├── manim.mobject.geometry.arc.Annulus.pot │ │ │ │ ├── manim.mobject.geometry.arc.Arc.pot │ │ │ │ ├── manim.mobject.geometry.arc.ArcBetweenPoints.pot │ │ │ │ ├── manim.mobject.geometry.arc.ArcPolygon.pot │ │ │ │ ├── manim.mobject.geometry.arc.ArcPolygonFromArcs.pot │ │ │ │ ├── manim.mobject.geometry.arc.Circle.pot │ │ │ │ ├── manim.mobject.geometry.arc.CubicBezier.pot │ │ │ │ ├── manim.mobject.geometry.arc.CurvedArrow.pot │ │ │ │ ├── manim.mobject.geometry.arc.CurvedDoubleArrow.pot │ │ │ │ ├── manim.mobject.geometry.arc.Dot.pot │ │ │ │ ├── manim.mobject.geometry.arc.Ellipse.pot │ │ │ │ ├── manim.mobject.geometry.arc.LabeledDot.pot │ │ │ │ ├── manim.mobject.geometry.arc.Sector.pot │ │ │ │ ├── manim.mobject.geometry.arc.TipableVMobject.pot │ │ │ │ ├── manim.mobject.geometry.arc.pot │ │ │ │ ├── manim.mobject.geometry.boolean_ops.Difference.pot │ │ │ │ ├── manim.mobject.geometry.boolean_ops.Exclusion.pot │ │ │ │ ├── manim.mobject.geometry.boolean_ops.Intersection.pot │ │ │ │ ├── manim.mobject.geometry.boolean_ops.Union.pot │ │ │ │ ├── manim.mobject.geometry.boolean_ops.pot │ │ │ │ ├── manim.mobject.geometry.line.Angle.pot │ │ │ │ ├── manim.mobject.geometry.line.Arrow.pot │ │ │ │ ├── manim.mobject.geometry.line.DashedLine.pot │ │ │ │ ├── manim.mobject.geometry.line.DoubleArrow.pot │ │ │ │ ├── manim.mobject.geometry.line.Elbow.pot │ │ │ │ ├── manim.mobject.geometry.line.Line.pot │ │ │ │ ├── manim.mobject.geometry.line.RightAngle.pot │ │ │ │ ├── manim.mobject.geometry.line.TangentLine.pot │ │ │ │ ├── manim.mobject.geometry.line.Vector.pot │ │ │ │ ├── manim.mobject.geometry.line.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Cutout.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Polygon.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Polygram.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Rectangle.pot │ │ │ │ ├── manim.mobject.geometry.polygram.RegularPolygon.pot │ │ │ │ ├── manim.mobject.geometry.polygram.RegularPolygram.pot │ │ │ │ ├── manim.mobject.geometry.polygram.RoundedRectangle.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Square.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Star.pot │ │ │ │ ├── manim.mobject.geometry.polygram.Triangle.pot │ │ │ │ ├── manim.mobject.geometry.polygram.pot │ │ │ │ ├── manim.mobject.geometry.pot │ │ │ │ ├── manim.mobject.geometry.shape_matchers.BackgroundRectangle.pot │ │ │ │ ├── manim.mobject.geometry.shape_matchers.Cross.pot │ │ │ │ ├── manim.mobject.geometry.shape_matchers.SurroundingRectangle.pot │ │ │ │ ├── manim.mobject.geometry.shape_matchers.Underline.pot │ │ │ │ ├── manim.mobject.geometry.shape_matchers.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowCircleFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowCircleTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowSquareFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowSquareTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowTriangleFilledTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.ArrowTriangleTip.pot │ │ │ │ ├── manim.mobject.geometry.tips.pot │ │ │ │ ├── manim.mobject.graph.Graph.pot │ │ │ │ ├── manim.mobject.graph.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.Axes.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.ComplexPlane.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.CoordinateSystem.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.NumberPlane.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.PolarPlane.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.ThreeDAxes.pot │ │ │ │ ├── manim.mobject.graphing.coordinate_systems.pot │ │ │ │ ├── manim.mobject.graphing.functions.FunctionGraph.pot │ │ │ │ ├── manim.mobject.graphing.functions.ImplicitFunction.pot │ │ │ │ ├── manim.mobject.graphing.functions.ParametricFunction.pot │ │ │ │ ├── manim.mobject.graphing.functions.pot │ │ │ │ ├── manim.mobject.graphing.number_line.NumberLine.pot │ │ │ │ ├── manim.mobject.graphing.number_line.UnitInterval.pot │ │ │ │ ├── manim.mobject.graphing.number_line.pot │ │ │ │ ├── manim.mobject.graphing.pot │ │ │ │ ├── manim.mobject.graphing.probability.BarChart.pot │ │ │ │ ├── manim.mobject.graphing.probability.SampleSpace.pot │ │ │ │ ├── manim.mobject.graphing.probability.pot │ │ │ │ ├── manim.mobject.graphing.scale.LinearBase.pot │ │ │ │ ├── manim.mobject.graphing.scale.LogBase.pot │ │ │ │ ├── manim.mobject.graphing.scale.pot │ │ │ │ ├── manim.mobject.logo.ManimBanner.pot │ │ │ │ ├── manim.mobject.logo.pot │ │ │ │ ├── manim.mobject.matrix.DecimalMatrix.pot │ │ │ │ ├── manim.mobject.matrix.IntegerMatrix.pot │ │ │ │ ├── manim.mobject.matrix.Matrix.pot │ │ │ │ ├── manim.mobject.matrix.MobjectMatrix.pot │ │ │ │ ├── manim.mobject.matrix.pot │ │ │ │ ├── manim.mobject.mobject.Group.pot │ │ │ │ ├── manim.mobject.mobject.Mobject.pot │ │ │ │ ├── manim.mobject.mobject.pot │ │ │ │ ├── manim.mobject.mobject_update_utils.pot │ │ │ │ ├── manim.mobject.number_line.NumberLine.pot │ │ │ │ ├── manim.mobject.number_line.UnitInterval.pot │ │ │ │ ├── manim.mobject.number_line.pot │ │ │ │ ├── manim.mobject.numbers.DecimalNumber.pot │ │ │ │ ├── manim.mobject.numbers.Integer.pot │ │ │ │ ├── manim.mobject.numbers.Variable.pot │ │ │ │ ├── manim.mobject.numbers.pot │ │ │ │ ├── manim.mobject.polyhedra.Dodecahedron.pot │ │ │ │ ├── manim.mobject.polyhedra.Icosahedron.pot │ │ │ │ ├── manim.mobject.polyhedra.Octahedron.pot │ │ │ │ ├── manim.mobject.polyhedra.Polyhedron.pot │ │ │ │ ├── manim.mobject.polyhedra.Tetrahedron.pot │ │ │ │ ├── manim.mobject.polyhedra.pot │ │ │ │ ├── manim.mobject.probability.BarChart.pot │ │ │ │ ├── manim.mobject.probability.SampleSpace.pot │ │ │ │ ├── manim.mobject.probability.pot │ │ │ │ ├── manim.mobject.shape_matchers.BackgroundRectangle.pot │ │ │ │ ├── manim.mobject.shape_matchers.Cross.pot │ │ │ │ ├── manim.mobject.shape_matchers.SurroundingRectangle.pot │ │ │ │ ├── manim.mobject.shape_matchers.Underline.pot │ │ │ │ ├── manim.mobject.shape_matchers.pot │ │ │ │ ├── manim.mobject.svg.brace.ArcBrace.pot │ │ │ │ ├── manim.mobject.svg.brace.Brace.pot │ │ │ │ ├── manim.mobject.svg.brace.BraceBetweenPoints.pot │ │ │ │ ├── manim.mobject.svg.brace.BraceLabel.pot │ │ │ │ ├── manim.mobject.svg.brace.BraceText.pot │ │ │ │ ├── manim.mobject.svg.brace.pot │ │ │ │ ├── manim.mobject.svg.code_mobject.Code.pot │ │ │ │ ├── manim.mobject.svg.code_mobject.pot │ │ │ │ ├── manim.mobject.svg.pot │ │ │ │ ├── manim.mobject.svg.style_utils.pot │ │ │ │ ├── manim.mobject.svg.svg_mobject.SVGMobject.pot │ │ │ │ ├── manim.mobject.svg.svg_mobject.pot │ │ │ │ ├── manim.mobject.svg.svg_path.SVGPathMobject.pot │ │ │ │ ├── manim.mobject.svg.svg_path.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.BulletedList.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.MathTex.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.SingleStringMathTex.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.Tex.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.TexSymbol.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.Title.pot │ │ │ │ ├── manim.mobject.svg.tex_mobject.pot │ │ │ │ ├── manim.mobject.svg.text_mobject.MarkupText.pot │ │ │ │ ├── manim.mobject.svg.text_mobject.Paragraph.pot │ │ │ │ ├── manim.mobject.svg.text_mobject.Text.pot │ │ │ │ ├── manim.mobject.svg.text_mobject.pot │ │ │ │ ├── manim.mobject.table.DecimalTable.pot │ │ │ │ ├── manim.mobject.table.IntegerTable.pot │ │ │ │ ├── manim.mobject.table.MathTable.pot │ │ │ │ ├── manim.mobject.table.MobjectTable.pot │ │ │ │ ├── manim.mobject.table.Table.pot │ │ │ │ ├── manim.mobject.table.pot │ │ │ │ ├── manim.mobject.text.code_mobject.Code.pot │ │ │ │ ├── manim.mobject.text.code_mobject.pot │ │ │ │ ├── manim.mobject.text.numbers.DecimalNumber.pot │ │ │ │ ├── manim.mobject.text.numbers.Integer.pot │ │ │ │ ├── manim.mobject.text.numbers.Variable.pot │ │ │ │ ├── manim.mobject.text.numbers.pot │ │ │ │ ├── manim.mobject.text.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.BulletedList.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.MathTex.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.SingleStringMathTex.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.Tex.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.TexSymbol.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.Title.pot │ │ │ │ ├── manim.mobject.text.tex_mobject.pot │ │ │ │ ├── manim.mobject.text.text_mobject.MarkupText.pot │ │ │ │ ├── manim.mobject.text.text_mobject.Paragraph.pot │ │ │ │ ├── manim.mobject.text.text_mobject.Text.pot │ │ │ │ ├── manim.mobject.text.text_mobject.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.Dodecahedron.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.Icosahedron.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.Octahedron.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.Polyhedron.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.Tetrahedron.pot │ │ │ │ ├── manim.mobject.three_d.polyhedra.pot │ │ │ │ ├── manim.mobject.three_d.pot │ │ │ │ ├── manim.mobject.three_d.three_d_utils.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Arrow3D.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Cone.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Cube.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Cylinder.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Dot3D.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Line3D.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Prism.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Sphere.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Surface.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.ThreeDVMobject.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.Torus.pot │ │ │ │ ├── manim.mobject.three_d.three_dimensions.pot │ │ │ │ ├── manim.mobject.three_d_utils.pot │ │ │ │ ├── manim.mobject.three_dimensions.Arrow3D.pot │ │ │ │ ├── manim.mobject.three_dimensions.Cone.pot │ │ │ │ ├── manim.mobject.three_dimensions.Cube.pot │ │ │ │ ├── manim.mobject.three_dimensions.Cylinder.pot │ │ │ │ ├── manim.mobject.three_dimensions.Dot3D.pot │ │ │ │ ├── manim.mobject.three_dimensions.Line3D.pot │ │ │ │ ├── manim.mobject.three_dimensions.ParametricSurface.pot │ │ │ │ ├── manim.mobject.three_dimensions.Prism.pot │ │ │ │ ├── manim.mobject.three_dimensions.Sphere.pot │ │ │ │ ├── manim.mobject.three_dimensions.Surface.pot │ │ │ │ ├── manim.mobject.three_dimensions.ThreeDVMobject.pot │ │ │ │ ├── manim.mobject.three_dimensions.Torus.pot │ │ │ │ ├── manim.mobject.three_dimensions.pot │ │ │ │ ├── manim.mobject.types.image_mobject.AbstractImageMobject.pot │ │ │ │ ├── manim.mobject.types.image_mobject.ImageMobject.pot │ │ │ │ ├── manim.mobject.types.image_mobject.ImageMobjectFromCamera.pot │ │ │ │ ├── manim.mobject.types.image_mobject.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.Mobject1D.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.Mobject2D.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.PGroup.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.PMobject.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.Point.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.PointCloudDot.pot │ │ │ │ ├── manim.mobject.types.point_cloud_mobject.pot │ │ │ │ ├── manim.mobject.types.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.DashedVMobject.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.VDict.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.VGroup.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.VMobject.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.VectorizedPoint.pot │ │ │ │ ├── manim.mobject.types.vectorized_mobject.pot │ │ │ │ ├── manim.mobject.value_tracker.ComplexValueTracker.pot │ │ │ │ ├── manim.mobject.value_tracker.ValueTracker.pot │ │ │ │ ├── manim.mobject.value_tracker.pot │ │ │ │ ├── manim.mobject.vector_field.ArrowVectorField.pot │ │ │ │ ├── manim.mobject.vector_field.StreamLines.pot │ │ │ │ ├── manim.mobject.vector_field.VectorField.pot │ │ │ │ ├── manim.mobject.vector_field.pot │ │ │ │ ├── manim.scene.moving_camera_scene.MovingCameraScene.pot │ │ │ │ ├── manim.scene.moving_camera_scene.pot │ │ │ │ ├── manim.scene.reconfigurable_scene.ReconfigurableScene.pot │ │ │ │ ├── manim.scene.reconfigurable_scene.pot │ │ │ │ ├── manim.scene.sample_space_scene.SampleSpaceScene.pot │ │ │ │ ├── manim.scene.sample_space_scene.pot │ │ │ │ ├── manim.scene.scene.RerunSceneHandler.pot │ │ │ │ ├── manim.scene.scene.Scene.pot │ │ │ │ ├── manim.scene.scene.pot │ │ │ │ ├── manim.scene.scene_file_writer.SceneFileWriter.pot │ │ │ │ ├── manim.scene.scene_file_writer.pot │ │ │ │ ├── manim.scene.section.DefaultSectionType.pot │ │ │ │ ├── manim.scene.section.Section.pot │ │ │ │ ├── manim.scene.section.pot │ │ │ │ ├── manim.scene.three_d_scene.SpecialThreeDScene.pot │ │ │ │ ├── manim.scene.three_d_scene.ThreeDScene.pot │ │ │ │ ├── manim.scene.three_d_scene.pot │ │ │ │ ├── manim.scene.vector_space_scene.LinearTransformationScene.pot │ │ │ │ ├── manim.scene.vector_space_scene.VectorScene.pot │ │ │ │ ├── manim.scene.vector_space_scene.pot │ │ │ │ ├── manim.scene.zoomed_scene.ZoomedScene.pot │ │ │ │ ├── manim.scene.zoomed_scene.pot │ │ │ │ ├── manim.utils.bezier.pot │ │ │ │ ├── manim.utils.color.Colors.pot │ │ │ │ ├── manim.utils.color.pot │ │ │ │ ├── manim.utils.commands.pot │ │ │ │ ├── manim.utils.config_ops.DictAsObject.pot │ │ │ │ ├── manim.utils.config_ops.pot │ │ │ │ ├── manim.utils.debug.pot │ │ │ │ ├── manim.utils.deprecation.pot │ │ │ │ ├── manim.utils.docbuild.manim_directive.ManimDirective.pot │ │ │ │ ├── manim.utils.docbuild.manim_directive.pot │ │ │ │ ├── manim.utils.docbuild.manim_directive.skip_manim_node.pot │ │ │ │ ├── manim.utils.docbuild.pot │ │ │ │ ├── manim.utils.hashing.pot │ │ │ │ ├── manim.utils.images.pot │ │ │ │ ├── manim.utils.ipython_magic.ManimMagic.pot │ │ │ │ ├── manim.utils.ipython_magic.pot │ │ │ │ ├── manim.utils.iterables.pot │ │ │ │ ├── manim.utils.paths.pot │ │ │ │ ├── manim.utils.rate_functions.pot │ │ │ │ ├── manim.utils.scale.LinearBase.pot │ │ │ │ ├── manim.utils.scale.LogBase.pot │ │ │ │ ├── manim.utils.scale.pot │ │ │ │ ├── manim.utils.simple_functions.pot │ │ │ │ ├── manim.utils.sounds.pot │ │ │ │ ├── manim.utils.space_ops.pot │ │ │ │ ├── manim.utils.strings.pot │ │ │ │ ├── manim.utils.tex.TexTemplate.pot │ │ │ │ ├── manim.utils.tex.TexTemplateFromFile.pot │ │ │ │ ├── manim.utils.tex.pot │ │ │ │ ├── manim.utils.tex_file_writing.pot │ │ │ │ ├── manim.utils.tex_templates.TexFontTemplates.pot │ │ │ │ ├── manim.utils.tex_templates.TexTemplateLibrary.pot │ │ │ │ ├── manim.utils.tex_templates.pot │ │ │ │ ├── manim_directive.ManimDirective.pot │ │ │ │ ├── manim_directive.pot │ │ │ │ └── manim_directive.skip_manim_node.pot │ │ │ ├── reference.pot │ │ │ ├── reference_index/ │ │ │ │ ├── animations.pot │ │ │ │ ├── cameras.pot │ │ │ │ ├── configuration.pot │ │ │ │ ├── mobjects.pot │ │ │ │ ├── scenes.pot │ │ │ │ └── utilities_misc.pot │ │ │ ├── reporting_bugs.pot │ │ │ ├── tutorials/ │ │ │ │ ├── a_deeper_look.pot │ │ │ │ ├── building_blocks.pot │ │ │ │ ├── configuration.pot │ │ │ │ ├── index.pot │ │ │ │ ├── output_and_config.pot │ │ │ │ ├── quickstart.pot │ │ │ │ └── using_text.pot │ │ │ ├── tutorials.pot │ │ │ └── tutorials_guides.pot │ │ ├── hi/ │ │ │ └── LC_MESSAGES/ │ │ │ └── index.po │ │ ├── pt/ │ │ │ └── LC_MESSAGES/ │ │ │ └── index.po │ │ ├── readyForTranslation │ │ ├── stripUntranslatable.awk │ │ ├── stripUntranslatable.sh │ │ └── sv/ │ │ └── LC_MESSAGES/ │ │ ├── contributing.po │ │ ├── examples.po │ │ ├── index.po │ │ ├── installation.po │ │ ├── plugins.po │ │ ├── reference.po │ │ ├── reporting_bugs.po │ │ ├── tutorials/ │ │ │ ├── building_blocks.po │ │ │ └── quickstart.po │ │ └── tutorials.po │ ├── make.bat │ ├── requirements.txt │ ├── rtd-requirements.txt │ ├── skip-manim │ └── source/ │ ├── _static/ │ │ ├── custom.css │ │ ├── manim-binder.min.js.LICENSE.txt │ │ └── responsiveSvg.js │ ├── _templates/ │ │ ├── autosummary/ │ │ │ ├── class.rst │ │ │ └── module.rst │ │ └── logo-text.html │ ├── changelog/ │ │ ├── 0.1.0-changelog.rst │ │ ├── 0.1.1-changelog.rst │ │ ├── 0.10.0-changelog.rst │ │ ├── 0.11.0-changelog.rst │ │ ├── 0.12.0-changelog.rst │ │ ├── 0.13.0-changelog.rst │ │ ├── 0.13.1-changelog.rst │ │ ├── 0.14.0-changelog.rst │ │ ├── 0.15.0-changelog.rst │ │ ├── 0.15.1-changelog.rst │ │ ├── 0.15.2-changelog.rst │ │ ├── 0.16.0-changelog.rst │ │ ├── 0.17.0-changelog.rst │ │ ├── 0.17.1-changelog.rst │ │ ├── 0.17.2-changelog.rst │ │ ├── 0.17.3-changelog.rst │ │ ├── 0.18.0-changelog.rst │ │ ├── 0.18.0.post0-changelog.rst │ │ ├── 0.18.1-changelog.md │ │ ├── 0.19.0-changelog.rst │ │ ├── 0.19.1-changelog.md │ │ ├── 0.19.2-changelog.md │ │ ├── 0.2.0-changelog.rst │ │ ├── 0.20.0-changelog.md │ │ ├── 0.20.1-changelog.md │ │ ├── 0.3.0-changelog.rst │ │ ├── 0.4.0-changelog.rst │ │ ├── 0.5.0-changelog.rst │ │ ├── 0.6.0-changelog.rst │ │ ├── 0.7.0-changelog.rst │ │ ├── 0.8.0-changelog.rst │ │ └── 0.9.0-changelog.rst │ ├── changelog.rst │ ├── conf.py │ ├── contributing/ │ │ ├── development.md │ │ ├── docs/ │ │ │ ├── admonitions.rst │ │ │ ├── docstrings.rst │ │ │ ├── examples.rst │ │ │ ├── references.rst │ │ │ ├── types.rst │ │ │ └── typings.rst │ │ ├── docs.rst │ │ ├── internationalization.rst │ │ ├── performance.rst │ │ └── testing.rst │ ├── contributing.rst │ ├── examples.rst │ ├── faq/ │ │ ├── general.md │ │ ├── help.md │ │ ├── index.rst │ │ ├── installation.md │ │ ├── internals.md │ │ └── opengl.md │ ├── guides/ │ │ ├── add_voiceovers.rst │ │ ├── configuration.rst │ │ ├── deep_dive.rst │ │ ├── index.rst │ │ └── using_text.rst │ ├── index.rst │ ├── installation/ │ │ ├── conda.rst │ │ ├── docker.rst │ │ ├── jupyter.rst │ │ └── uv.md │ ├── installation.rst │ ├── plugins.rst │ ├── reference.rst │ ├── reference_index/ │ │ ├── animations.rst │ │ ├── cameras.rst │ │ ├── configuration.rst │ │ ├── mobjects.rst │ │ ├── scenes.rst │ │ └── utilities_misc.rst │ ├── robots.txt │ ├── tutorials/ │ │ ├── building_blocks.rst │ │ ├── index.rst │ │ ├── output_and_config.rst │ │ └── quickstart.rst │ └── tutorials_guides.rst ├── example_scenes/ │ ├── advanced_tex_fonts.py │ ├── basic.py │ ├── custom_template.tex │ ├── customtex.py │ ├── manim.cfg │ ├── manim_jupyter_example.ipynb │ └── opengl.py ├── lgtm.yml ├── manim/ │ ├── __init__.py │ ├── __main__.py │ ├── _config/ │ │ ├── __init__.py │ │ ├── cli_colors.py │ │ ├── default.cfg │ │ ├── logger_utils.py │ │ └── utils.py │ ├── animation/ │ │ ├── __init__.py │ │ ├── animation.py │ │ ├── changing.py │ │ ├── composition.py │ │ ├── creation.py │ │ ├── fading.py │ │ ├── growing.py │ │ ├── indication.py │ │ ├── movement.py │ │ ├── numbers.py │ │ ├── rotation.py │ │ ├── specialized.py │ │ ├── speedmodifier.py │ │ ├── transform.py │ │ ├── transform_matching_parts.py │ │ └── updaters/ │ │ ├── __init__.py │ │ ├── mobject_update_utils.py │ │ └── update.py │ ├── camera/ │ │ ├── __init__.py │ │ ├── camera.py │ │ ├── mapping_camera.py │ │ ├── moving_camera.py │ │ ├── multi_camera.py │ │ └── three_d_camera.py │ ├── cli/ │ │ ├── __init__.py │ │ ├── cfg/ │ │ │ ├── __init__.py │ │ │ └── group.py │ │ ├── checkhealth/ │ │ │ ├── __init__.py │ │ │ ├── checks.py │ │ │ └── commands.py │ │ ├── default_group.py │ │ ├── init/ │ │ │ ├── __init__.py │ │ │ └── commands.py │ │ ├── plugins/ │ │ │ ├── __init__.py │ │ │ └── commands.py │ │ └── render/ │ │ ├── __init__.py │ │ ├── commands.py │ │ ├── ease_of_access_options.py │ │ ├── global_options.py │ │ ├── output_options.py │ │ └── render_options.py │ ├── constants.py │ ├── data_structures.py │ ├── mobject/ │ │ ├── __init__.py │ │ ├── frame.py │ │ ├── geometry/ │ │ │ ├── __init__.py │ │ │ ├── arc.py │ │ │ ├── boolean_ops.py │ │ │ ├── labeled.py │ │ │ ├── line.py │ │ │ ├── polygram.py │ │ │ ├── shape_matchers.py │ │ │ └── tips.py │ │ ├── graph.py │ │ ├── graphing/ │ │ │ ├── __init__.py │ │ │ ├── coordinate_systems.py │ │ │ ├── functions.py │ │ │ ├── number_line.py │ │ │ ├── probability.py │ │ │ └── scale.py │ │ ├── logo.py │ │ ├── matrix.py │ │ ├── mobject.py │ │ ├── opengl/ │ │ │ ├── __init__.py │ │ │ ├── dot_cloud.py │ │ │ ├── opengl_compatibility.py │ │ │ ├── opengl_geometry.py │ │ │ ├── opengl_image_mobject.py │ │ │ ├── opengl_mobject.py │ │ │ ├── opengl_point_cloud_mobject.py │ │ │ ├── opengl_surface.py │ │ │ ├── opengl_three_dimensions.py │ │ │ └── opengl_vectorized_mobject.py │ │ ├── svg/ │ │ │ ├── __init__.py │ │ │ ├── brace.py │ │ │ └── svg_mobject.py │ │ ├── table.py │ │ ├── text/ │ │ │ ├── __init__.py │ │ │ ├── code_mobject.py │ │ │ ├── numbers.py │ │ │ ├── tex_mobject.py │ │ │ └── text_mobject.py │ │ ├── three_d/ │ │ │ ├── __init__.py │ │ │ ├── polyhedra.py │ │ │ ├── three_d_utils.py │ │ │ └── three_dimensions.py │ │ ├── types/ │ │ │ ├── __init__.py │ │ │ ├── image_mobject.py │ │ │ ├── point_cloud_mobject.py │ │ │ └── vectorized_mobject.py │ │ ├── utils.py │ │ ├── value_tracker.py │ │ └── vector_field.py │ ├── opengl/ │ │ └── __init__.py │ ├── plugins/ │ │ ├── __init__.py │ │ └── plugins_flags.py │ ├── py.typed │ ├── renderer/ │ │ ├── __init__.py │ │ ├── cairo_renderer.py │ │ ├── opengl_renderer.py │ │ ├── opengl_renderer_window.py │ │ ├── shader.py │ │ ├── shader_wrapper.py │ │ ├── shaders/ │ │ │ ├── default/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── design.frag │ │ │ ├── design_2.frag │ │ │ ├── design_3.frag │ │ │ ├── image/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── include/ │ │ │ │ ├── NOTE.md │ │ │ │ ├── add_light.glsl │ │ │ │ ├── camera_uniform_declarations.glsl │ │ │ │ ├── finalize_color.glsl │ │ │ │ ├── get_gl_Position.glsl │ │ │ │ ├── get_rotated_surface_unit_normal_vector.glsl │ │ │ │ ├── get_unit_normal.glsl │ │ │ │ ├── position_point_into_frame.glsl │ │ │ │ ├── quadratic_bezier_distance.glsl │ │ │ │ └── quadratic_bezier_geometry_functions.glsl │ │ │ ├── manim_coords/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── quadratic_bezier_fill/ │ │ │ │ ├── frag.glsl │ │ │ │ ├── geom.glsl │ │ │ │ └── vert.glsl │ │ │ ├── quadratic_bezier_stroke/ │ │ │ │ ├── frag.glsl │ │ │ │ ├── geom.glsl │ │ │ │ └── vert.glsl │ │ │ ├── simple_vert.glsl │ │ │ ├── surface/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── test/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── textured_surface/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── true_dot/ │ │ │ │ ├── frag.glsl │ │ │ │ ├── geom.glsl │ │ │ │ └── vert.glsl │ │ │ ├── vectorized_mobject_fill/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ ├── vectorized_mobject_stroke/ │ │ │ │ ├── frag.glsl │ │ │ │ └── vert.glsl │ │ │ └── vertex_colors/ │ │ │ ├── frag.glsl │ │ │ └── vert.glsl │ │ └── vectorized_mobject_rendering.py │ ├── scene/ │ │ ├── __init__.py │ │ ├── moving_camera_scene.py │ │ ├── scene.py │ │ ├── scene_file_writer.py │ │ ├── section.py │ │ ├── three_d_scene.py │ │ ├── vector_space_scene.py │ │ └── zoomed_scene.py │ ├── templates/ │ │ ├── Axes.mtp │ │ ├── Default.mtp │ │ ├── MovingCamera.mtp │ │ └── template.cfg │ ├── typing.py │ └── utils/ │ ├── __init__.py │ ├── bezier.py │ ├── caching.py │ ├── color/ │ │ ├── AS2700.py │ │ ├── BS381.py │ │ ├── DVIPSNAMES.py │ │ ├── SVGNAMES.py │ │ ├── X11.py │ │ ├── XKCD.py │ │ ├── __init__.py │ │ ├── core.py │ │ └── manim_colors.py │ ├── commands.py │ ├── config_ops.py │ ├── debug.py │ ├── deprecation.py │ ├── docbuild/ │ │ ├── __init__.py │ │ ├── autoaliasattr_directive.py │ │ ├── autocolor_directive.py │ │ ├── manim_directive.py │ │ └── module_parsing.py │ ├── exceptions.py │ ├── family.py │ ├── family_ops.py │ ├── file_ops.py │ ├── hashing.py │ ├── images.py │ ├── ipython_magic.py │ ├── iterables.py │ ├── module_ops.py │ ├── opengl.py │ ├── parameter_parsing.py │ ├── paths.py │ ├── polylabel.py │ ├── qhull.py │ ├── rate_functions.py │ ├── simple_functions.py │ ├── sounds.py │ ├── space_ops.py │ ├── testing/ │ │ ├── __init__.py │ │ ├── _frames_testers.py │ │ ├── _show_diff.py │ │ ├── _test_class_makers.py │ │ ├── config_graphical_tests_monoframe.cfg │ │ ├── config_graphical_tests_multiframes.cfg │ │ └── frames_comparison.py │ ├── tex.py │ ├── tex_file_writing.py │ ├── tex_templates.py │ └── unit.py ├── mypy.ini ├── pyproject.toml ├── scripts/ │ ├── TEMPLATE.cff │ ├── extract_frames.py │ ├── make_and_open_docs.py │ ├── release.py │ └── template_docsting_with_example.py └── tests/ ├── __init__.py ├── assert_utils.py ├── conftest.py ├── control_data/ │ ├── logs_data/ │ │ ├── BasicSceneLoggingTest.txt │ │ └── bad_tex_scene_BadTex.txt │ └── videos_data/ │ ├── InputFileViaCfg.json │ ├── SceneWithDisabledSections.json │ ├── SceneWithEnabledSections.json │ ├── SceneWithMultipleCallsWithNFlag.json │ ├── SceneWithMultiplePlayCallsWithNFlag.json │ ├── SceneWithMultipleWaitCallsWithNFlag.json │ ├── SceneWithSections.json │ ├── SceneWithSkipAnimations.json │ ├── SquareToCircleWithDefaultValues.json │ └── SquareToCircleWithlFlag.json ├── helpers/ │ ├── __init__.py │ ├── graphical_units.py │ ├── path_utils.py │ └── video_utils.py ├── interface/ │ └── test_commands.py ├── miscellaneous/ │ └── test_version.py ├── module/ │ ├── animation/ │ │ ├── test_animate.py │ │ ├── test_animation.py │ │ ├── test_composition.py │ │ ├── test_creation.py │ │ ├── test_override_animation.py │ │ ├── test_transform.py │ │ └── test_updaters.py │ ├── mobject/ │ │ ├── geometry/ │ │ │ └── test_unit_geometry.py │ │ ├── graphing/ │ │ │ ├── test_axes_shift.py │ │ │ ├── test_coordinate_system.py │ │ │ ├── test_number_line.py │ │ │ └── test_ticks.py │ │ ├── mobject/ │ │ │ ├── test_copy.py │ │ │ ├── test_family.py │ │ │ ├── test_get_set.py │ │ │ ├── test_mobject.py │ │ │ ├── test_opengl_metaclass.py │ │ │ └── test_set_attr.py │ │ ├── svg/ │ │ │ └── test_svg_mobject.py │ │ ├── test_boolean_ops.py │ │ ├── test_graph.py │ │ ├── test_image.py │ │ ├── test_matrix.py │ │ ├── test_table.py │ │ ├── test_value_tracker.py │ │ ├── text/ │ │ │ ├── test_markup.py │ │ │ ├── test_numbers.py │ │ │ ├── test_texmobject.py │ │ │ └── test_text_mobject.py │ │ └── types/ │ │ └── vectorized_mobject/ │ │ ├── test_dashed_vmobject.py │ │ ├── test_stroke.py │ │ └── test_vectorized_mobject.py │ ├── scene/ │ │ ├── test_auto_zoom.py │ │ ├── test_scene.py │ │ ├── test_sound.py │ │ └── test_threed_scene.py │ └── utils/ │ ├── _split_matrices.py │ ├── _subdivision_matrices.py │ ├── test_bezier.py │ ├── test_color.py │ ├── test_deprecation.py │ ├── test_file_ops.py │ ├── test_hashing.py │ ├── test_manim_color.py │ ├── test_space_ops.py │ ├── test_tex.py │ └── test_units.py ├── opengl/ │ ├── __init__.py │ ├── control_data/ │ │ └── coordinate_system_opengl/ │ │ ├── gradient_line_graph_x_axis_using_opengl_renderer[None].npz │ │ └── gradient_line_graph_y_axis_using_opengl_renderer[None].npz │ ├── test_animate_opengl.py │ ├── test_axes_shift_opengl.py │ ├── test_color_opengl.py │ ├── test_composition_opengl.py │ ├── test_config_opengl.py │ ├── test_coordinate_system_opengl.py │ ├── test_copy_opengl.py │ ├── test_family_opengl.py │ ├── test_graph_opengl.py │ ├── test_ipython_magic_opengl.py │ ├── test_markup_opengl.py │ ├── test_number_line_opengl.py │ ├── test_numbers_opengl.py │ ├── test_opengl_mobject.py │ ├── test_opengl_surface.py │ ├── test_opengl_vectorized_mobject.py │ ├── test_override_animation_opengl.py │ ├── test_scene_opengl.py │ ├── test_sound_opengl.py │ ├── test_stroke_opengl.py │ ├── test_svg_mobject_opengl.py │ ├── test_texmobject_opengl.py │ ├── test_text_mobject_opengl.py │ ├── test_ticks_opengl.py │ ├── test_unit_geometry_opengl.py │ └── test_value_tracker_opengl.py ├── standard_config.cfg ├── template_generate_graphical_units_data.py ├── test_camera.py ├── test_code_mobject.py ├── test_config.py ├── test_graphical_units/ │ ├── __init__.py │ ├── conftest.py │ ├── control_data/ │ │ ├── boolean_ops/ │ │ │ ├── difference.npz │ │ │ ├── exclusion.npz │ │ │ ├── intersection.npz │ │ │ ├── intersection_3_mobjects.npz │ │ │ └── union.npz │ │ ├── brace/ │ │ │ ├── arcBrace.npz │ │ │ ├── braceTip.npz │ │ │ └── brace_sharpness.npz │ │ ├── composition/ │ │ │ ├── animationgroup_is_passing_remover_to_animations.npz │ │ │ └── animationgroup_is_passing_remover_to_nested_animationgroups.npz │ │ ├── coordinate_system/ │ │ │ ├── gradient_line_graph_x_axis.npz │ │ │ ├── gradient_line_graph_y_axis.npz │ │ │ ├── implicit_graph.npz │ │ │ ├── line_graph.npz │ │ │ ├── number_plane.npz │ │ │ ├── number_plane_log.npz │ │ │ ├── plot_log_x_axis.npz │ │ │ ├── plot_log_x_axis_vectorized.npz │ │ │ ├── plot_surface.npz │ │ │ └── plot_surface_colorscale.npz │ │ ├── coordinate_systems/ │ │ │ └── NumberPlaneTest.npz │ │ ├── creation/ │ │ │ ├── DrawBorderThenFill.npz │ │ │ ├── FadeIn.npz │ │ │ ├── FadeOut.npz │ │ │ ├── GrowFromCenter.npz │ │ │ ├── GrowFromEdge.npz │ │ │ ├── GrowFromPoint.npz │ │ │ ├── ShrinkToCenter.npz │ │ │ ├── SpinInFromNothing.npz │ │ │ ├── SpiralIn.npz │ │ │ ├── bring_to_back_introducer.npz │ │ │ ├── create.npz │ │ │ ├── uncreate.npz │ │ │ ├── uncreate_rate_func.npz │ │ │ └── z_index_introducer.npz │ │ ├── functions/ │ │ │ ├── FunctionGraph.npz │ │ │ └── ImplicitFunction.npz │ │ ├── geometry/ │ │ │ ├── Angle.npz │ │ │ ├── AngledArrowTip.npz │ │ │ ├── AnnotationDot.npz │ │ │ ├── AnnularSector.npz │ │ │ ├── Annulus.npz │ │ │ ├── Arc.npz │ │ │ ├── ArcBetweenPoints.npz │ │ │ ├── Arrange.npz │ │ │ ├── Circle.npz │ │ │ ├── CirclePoints.npz │ │ │ ├── ConvexHull.npz │ │ │ ├── Coordinates.npz │ │ │ ├── CurvedArrow.npz │ │ │ ├── CurvedArrowCustomTip.npz │ │ │ ├── CustomDoubleArrow.npz │ │ │ ├── DashedVMobject.npz │ │ │ ├── DashedVMobjectTest.npz │ │ │ ├── Dot.npz │ │ │ ├── DoubleArrow.npz │ │ │ ├── Elbow.npz │ │ │ ├── Ellipse.npz │ │ │ ├── LabeledArrow.npz │ │ │ ├── LabeledLine.npz │ │ │ ├── LabeledPolygram.npz │ │ │ ├── Line.npz │ │ │ ├── Polygon.npz │ │ │ ├── Polygram.npz │ │ │ ├── Rectangle.npz │ │ │ ├── RegularPolygram.npz │ │ │ ├── RightAngle.npz │ │ │ ├── RoundedRectangle.npz │ │ │ ├── Sector.npz │ │ │ ├── Star.npz │ │ │ ├── Vector.npz │ │ │ ├── ZIndex.npz │ │ │ ├── negative_z_index_AnimationGroup.npz │ │ │ ├── negative_z_index_LaggedStart.npz │ │ │ ├── nested_animation_groups_with_negative_z_index.npz │ │ │ └── three_points_Angle.npz │ │ ├── img_and_svg/ │ │ │ ├── Arcs01.npz │ │ │ ├── Arcs02.npz │ │ │ ├── BrachistochroneCurve.npz │ │ │ ├── ContiguousUSMap.npz │ │ │ ├── CubicAndLineto.npz │ │ │ ├── CubicPath.npz │ │ │ ├── DesmosGraph1.npz │ │ │ ├── HalfEllipse.npz │ │ │ ├── Heart.npz │ │ │ ├── ImageInterpolation.npz │ │ │ ├── ImageMobject.npz │ │ │ ├── Inheritance.npz │ │ │ ├── Line.npz │ │ │ ├── ManimLogo.npz │ │ │ ├── MatrixTransform.npz │ │ │ ├── MultiPartPath.npz │ │ │ ├── MultipleTransform.npz │ │ │ ├── Penrose.npz │ │ │ ├── PixelizedText.npz │ │ │ ├── QuadraticPath.npz │ │ │ ├── Rhomboid.npz │ │ │ ├── RotateTransform.npz │ │ │ ├── ScaleTransform.npz │ │ │ ├── SingleUSState.npz │ │ │ ├── SkewXTransform.npz │ │ │ ├── SkewYTransform.npz │ │ │ ├── SmoothCurves.npz │ │ │ ├── TranslateTransform.npz │ │ │ ├── UKFlag.npz │ │ │ ├── UseTagInheritance.npz │ │ │ ├── VideoIcon.npz │ │ │ ├── WatchTheDecimals.npz │ │ │ ├── WeightSVG.npz │ │ │ └── path_multiple_moves.npz │ │ ├── indication/ │ │ │ ├── ApplyWave.npz │ │ │ ├── Circumscribe.npz │ │ │ ├── Flash.npz │ │ │ ├── FocusOn.npz │ │ │ ├── Indicate.npz │ │ │ ├── ShowPassingFlash.npz │ │ │ └── Wiggle.npz │ │ ├── logo/ │ │ │ └── banner.npz │ │ ├── mobjects/ │ │ │ ├── PointCloudDot.npz │ │ │ ├── become.npz │ │ │ ├── become_no_color_linking.npz │ │ │ ├── match_style.npz │ │ │ ├── vmobject_cap_styles.npz │ │ │ └── vmobject_joint_types.npz │ │ ├── modifier_methods/ │ │ │ ├── Gradient.npz │ │ │ └── GradientRotation.npz │ │ ├── movements/ │ │ │ ├── Homotopy.npz │ │ │ ├── MoveAlongPath.npz │ │ │ ├── MoveTo.npz │ │ │ ├── PhaseFlow.npz │ │ │ ├── Rotate.npz │ │ │ └── Shift.npz │ │ ├── numbers/ │ │ │ └── set_value_with_updaters.npz │ │ ├── opengl/ │ │ │ ├── Circle.npz │ │ │ └── FixedMobjects3D.npz │ │ ├── plot/ │ │ │ ├── PlotFunctions.npz │ │ │ ├── axes.npz │ │ │ ├── axis_tip_custom_width_height.npz │ │ │ ├── axis_tip_default_width_height.npz │ │ │ ├── custom_coordinates.npz │ │ │ ├── get_area.npz │ │ │ ├── get_area_with_boundary_and_few_plot_points.npz │ │ │ ├── get_area_with_riemann_rectangles.npz │ │ │ ├── get_axis_labels.npz │ │ │ ├── get_graph_label.npz │ │ │ ├── get_lines_to_point.npz │ │ │ ├── get_riemann_rectangles_use_vectorized[False].npz │ │ │ ├── get_riemann_rectangles_use_vectorized[True].npz │ │ │ ├── get_x_axis_label.npz │ │ │ ├── get_y_axis_label.npz │ │ │ ├── get_z_axis_label.npz │ │ │ ├── log_scaling_graph.npz │ │ │ ├── plot_derivative_graph_use_vectorized[False].npz │ │ │ ├── plot_derivative_graph_use_vectorized[True].npz │ │ │ ├── plot_functions_use_vectorized[False].npz │ │ │ ├── plot_functions_use_vectorized[True].npz │ │ │ ├── plot_line_graph.npz │ │ │ ├── plot_use_vectorized[False].npz │ │ │ ├── plot_use_vectorized[True].npz │ │ │ ├── polar_graph.npz │ │ │ └── t_label.npz │ │ ├── polyhedra/ │ │ │ ├── ConvexHull3D.npz │ │ │ ├── Dodecahedron.npz │ │ │ ├── Icosahedron.npz │ │ │ ├── Octahedron.npz │ │ │ └── Tetrahedron.npz │ │ ├── probability/ │ │ │ ├── advanced_customization.npz │ │ │ ├── change_bar_values_negative.npz │ │ │ ├── change_bar_values_some_vals.npz │ │ │ ├── default_chart.npz │ │ │ ├── get_bar_labels.npz │ │ │ ├── label_constructor.npz │ │ │ └── negative_values.npz │ │ ├── specialized/ │ │ │ └── Broadcast.npz │ │ ├── speed/ │ │ │ └── SpeedModifier.npz │ │ ├── tables/ │ │ │ ├── DecimalTable.npz │ │ │ ├── IntegerTable.npz │ │ │ ├── MathTable.npz │ │ │ ├── MobjectTable.npz │ │ │ └── Table.npz │ │ ├── tex_mobject/ │ │ │ ├── color_inheritance.npz │ │ │ └── set_opacity_by_tex.npz │ │ ├── threed/ │ │ │ ├── AddFixedInFrameMobjects.npz │ │ │ ├── AmbientCameraMove.npz │ │ │ ├── Arrow3D.npz │ │ │ ├── Axes.npz │ │ │ ├── CameraMove.npz │ │ │ ├── CameraMoveAxes.npz │ │ │ ├── Cone.npz │ │ │ ├── Cube.npz │ │ │ ├── Cylinder.npz │ │ │ ├── Dot3D.npz │ │ │ ├── Line3D.npz │ │ │ ├── MovingVertices.npz │ │ │ ├── Sphere.npz │ │ │ ├── SurfaceColorscale.npz │ │ │ ├── Torus.npz │ │ │ └── Y_Direction.npz │ │ ├── transform/ │ │ │ ├── AnimationBuilder.npz │ │ │ ├── ApplyComplexFunction.npz │ │ │ ├── ApplyFunction.npz │ │ │ ├── ApplyMatrix.npz │ │ │ ├── ApplyPointwiseFunction.npz │ │ │ ├── ClockwiseTransform.npz │ │ │ ├── CounterclockwiseTransform.npz │ │ │ ├── CyclicReplace.npz │ │ │ ├── FadeInAndOut.npz │ │ │ ├── FadeToColort.npz │ │ │ ├── FadeTransform.npz │ │ │ ├── FadeTransformPieces.npz │ │ │ ├── FadeTransform_TargetIsEmpty_FadesOutInPlace.npz │ │ │ ├── FullRotation.npz │ │ │ ├── MatchPointsScene.npz │ │ │ ├── MoveToTarget.npz │ │ │ ├── ReplacementTransform.npz │ │ │ ├── Restore.npz │ │ │ ├── ScaleInPlace.npz │ │ │ ├── ShrinkToCenter.npz │ │ │ ├── Transform.npz │ │ │ ├── TransformFromCopy.npz │ │ │ ├── TransformWithConflictingPaths.npz │ │ │ ├── TransformWithPathArcCenters.npz │ │ │ └── TransformWithPathFunc.npz │ │ ├── transform_matching_parts/ │ │ │ ├── TransformMatchingDisplaysCorrect.npz │ │ │ ├── TransformMatchingLeavesOneObject.npz │ │ │ ├── TransformMatchingTex.npz │ │ │ ├── TransformMatchingTex_FadeTransformMismatches.npz │ │ │ ├── TransformMatchingTex_FadeTransformMismatches_NothingToFade.npz │ │ │ └── TransformMatchingTex_TransformMismatches.npz │ │ ├── updaters/ │ │ │ ├── LastFrameWhenCleared.npz │ │ │ ├── UpdateSceneDuringAnimation.npz │ │ │ ├── Updater.npz │ │ │ └── ValueTracker.npz │ │ ├── utils/ │ │ │ └── pixel_error_threshold.npz │ │ └── vector_scene/ │ │ └── vector_to_coords.npz │ ├── test_animation.py │ ├── test_axes.py │ ├── test_banner.py │ ├── test_boolops.py │ ├── test_brace.py │ ├── test_composition.py │ ├── test_coordinate_systems.py │ ├── test_creation.py │ ├── test_functions.py │ ├── test_geometry.py │ ├── test_img_and_svg.py │ ├── test_indication.py │ ├── test_mobjects.py │ ├── test_modifier_methods.py │ ├── test_movements.py │ ├── test_numbers.py │ ├── test_opengl.py │ ├── test_polyhedra.py │ ├── test_probability.py │ ├── test_specialized.py │ ├── test_speed.py │ ├── test_tables.py │ ├── test_tex_mobject.py │ ├── test_text.py │ ├── test_threed.py │ ├── test_transform.py │ ├── test_transform_matching_parts.py │ ├── test_updaters.py │ ├── test_utils.py │ └── test_vector_scene.py ├── test_ipython_magic.py ├── test_linear_transformation_scene.py ├── test_logging/ │ ├── __init__.py │ ├── bad_tex_scene.py │ ├── basic_scenes_error.py │ ├── basic_scenes_square_to_circle.py │ ├── basic_scenes_write_stuff.py │ └── test_logging.py ├── test_plugins/ │ ├── __init__.py │ ├── simple_scenes.py │ └── test_plugins.py ├── test_scene_rendering/ │ ├── __init__.py │ ├── conftest.py │ ├── infallible_scenes.py │ ├── opengl/ │ │ ├── __init__.py │ │ ├── test_caching_related_opengl.py │ │ ├── test_cli_flags_opengl.py │ │ ├── test_opengl_renderer.py │ │ └── test_play_logic_opengl.py │ ├── simple_scenes.py │ ├── test_caching_related.py │ ├── test_cairo_renderer.py │ ├── test_cli_flags.py │ ├── test_file_writer.py │ ├── test_play_logic.py │ └── test_sections.py └── utils/ ├── __init__.py ├── logging_tester.py ├── test_polylabels.py ├── testing_utils.py └── video_tester.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .codecov.yml ================================================ codecov: notify: require_ci_to_pass: no after_n_builds: 1 coverage: status: project: default: # Require 1% coverage, i.e., always succeed target: 1 patch: true changes: false comment: off ================================================ FILE: .codespell_ignorewords ================================================ nam sherif falsy medias strager ================================================ FILE: .codespellrc ================================================ [codespell] check-hidden = True skip = .git,*.js,*.js.map,*.css,*.css.map,*.html,*.po,*.pot,uv.lock,*.log,*.svg ignore-words = .codespell_ignorewords ================================================ FILE: .dockerignore ================================================ .git # Development / test artifacts __pycache__ **/__pycache__ *.pyc *.pyo *.pyd *.egg-info dist/ build/ coverage.xml # Not needed to install the package docs/ tests/ example_scenes/ media/ logo/ scripts/ ================================================ FILE: .flake8 ================================================ [flake8] # Exclude the grpc generated code exclude = ./manim/grpc/gen/*, __pycache__,.git, per-file-ignores = __init__.py:F401 max-complexity = 29 max-line-length = 88 statistics = True # Prevents some flake8-rst-docstrings errors rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc rst-directives = manim, SEEALSO, seealso docstring-convention=numpy select = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W,F401 # General Compatibility extend-ignore = E203, W503, D202, D212, D213, D404 # Misc F401, F403, F405, F841, E501, E731, E402, F811, F821, # multiple statements on one line (overload) E704, # Plug-in: flake8-builtins A001, A002, A003, # Plug-in: flake8-bugbear B006, B007, B008, B009, B010, B903, B950, # Plug-in: flake8-simplify SIM105, SIM106, SIM119, # Plug-in: flake8-pytest-style PT001, PT004, PT006, PT011, PT018, PT022, PT023, # Plug-in: flake8-docstrings D100, D101, D102, D103, D104, D105, D106, D107, D200, D202, D204, D205, D209, D301, D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414, # Plug-in: flake8-rst-docstrings RST201, RST203, RST210, RST212, RST213, RST215, RST301, RST303, RST499 ================================================ FILE: .git-blame-ignore-revs ================================================ # Switched to ruff format: 24025b60d57301b0a59754c38d77bccd8ed69feb ================================================ FILE: .gitattributes ================================================ # Declare files that always have LF line endings on checkout * text eol=lf *.bat text eol=crlf # Denote all files that are truly binary and should not be modified *.npz binary *.png binary *.wav binary manim/grpc/gen/** linguist-generated=true ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Manim bug about: Report a bug or unexpected behavior when running Manim title: "" labels: bug assignees: '' --- ## Description of bug / unexpected behavior ## Expected behavior ## How to reproduce the issue
Code for reproducing the problem ```py Paste your code here. ```
## Additional media files
Images/GIFs
## Logs
Terminal output ``` PASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR ```
## System specifications
System Details - OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)): - RAM: - Python version (`python/py/python3 --version`): - Installed modules (provide output from `pip list`): ``` PASTE HERE ```
LaTeX details + LaTeX distribution (e.g. TeX Live 2020): + Installed LaTeX packages:
## Additional comments ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Request a new feature for Manim title: "" labels: new feature assignees: '' --- ## Description of proposed feature ## How can the new feature be used? ## Additional comments ================================================ FILE: .github/ISSUE_TEMPLATE/installation_issue.md ================================================ --- name: Installation issue about: Report issues with the installation process of Manim title: "" labels: bug, installation assignees: '' --- #### Preliminaries - [ ] I have followed the latest version of the [installation instructions](https://docs.manim.community/en/stable/installation.html). - [ ] I have checked the [installation FAQ](https://docs.manim.community/en/stable/faq/installation.html) and my problem is either not mentioned there, or the solution given there does not help. ## Description of error ## Installation logs
Terminal output ``` PASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR ```
## System specifications
System Details - OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)): - RAM: - Python version (`python/py/python3 --version`): - Installed modules (provide output from `pip list`): ``` PASTE HERE ```
LaTeX details + LaTeX distribution (e.g. TeX Live 2020): + Installed LaTeX packages:
## Additional comments ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/bugfix.md ================================================ ## Changelog ## Summary of Changes ## Checklist - [ ] I have read the [Contributing Guidelines](https://docs.manim.community/en/latest/contributing.html) - [ ] I have written a descriptive PR title (see top of PR template for examples) - [ ] I have added a test case to prevent software regression ## Reviewer Checklist - [ ] The PR title is descriptive enough - [ ] The PR is labeled appropriately - [ ] Regression test(s) are implemented ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/documentation.md ================================================ ## Summary of Changes ## Changelog ## Checklist - [ ] I have read the [Contributing Guidelines](https://docs.manim.community/en/latest/contributing.html) - [ ] I have written a descriptive PR title (see top of PR template for examples) - [ ] My new documentation builds, looks correctly formatted, and adds no additional build warnings ## Reviewer Checklist - [ ] The PR title is descriptive enough - [ ] The PR is labeled appropriately - [ ] Newly added documentation builds, looks correctly formatted, and adds no additional build warnings ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/hackathon.md ================================================ Thanks for your contribution for the manim community hackathon! Please make sure your pull request has a meaningful title. E.g. "Example for the class Angle". Details for the submissions can be found in the [discord announcement channel](https://discord.com/channels/581738731934056449/581739610154074112/846460718479966228 ). Docstrings can be created in the discord channel with the manimator like this: ``` !mdocstring ``` ```python class HelloWorld(Scene): def construct(self): self.add(Circle()) ``` Copy+paste the output docstring to the right place in the source code. If you need any help, do not hesitate to ask the hackathon-mentors in the discord channel. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Overview: What does this pull request change? ## Motivation and Explanation: Why and how do your changes improve the library? ## Links to added or changed documentation pages ## Further Information and Comments ## Reviewer Checklist - [ ] The PR title is descriptive enough for the changelog, and the PR is labeled correctly - [ ] If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section - [ ] If applicable: newly added functions and classes are tested ================================================ FILE: .github/codeql.yml ================================================ query-filters: - exclude: id: py/init-calls-subclass - exclude: id: py/unexpected-raise-in-special-method - exclude: id: py/modification-of-locals - exclude: id: py/multiple-calls-to-init - exclude: id: py/missing-call-to-init - exclude: id: py/method-first-arg-is-not-self - exclude: id: py/cyclic-import - exclude: id: py/unsafe-cyclic-import paths: - manim paths-ignore: - tests/ - example_scenes/ ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" ignore: - dependency-name: "*" update-types: - "version-update:semver-minor" - "version-update:semver-patch" ================================================ FILE: .github/manimdependency.json ================================================ { "windows": { "tinytex": [ "standalone", "preview", "doublestroke", "count1to", "multitoc", "prelim2e", "ragged2e", "everysel", "setspace", "rsfs", "relsize", "ragged2e", "fundus-calligra", "microtype", "wasysym", "physics", "dvisvgm", "jknapltx", "wasy", "cm-super", "babel-english", "gnu-freefont", "mathastext", "cbfonts-fd" ] }, "macos": { "tinytex": [ "standalone", "preview", "doublestroke", "count1to", "multitoc", "prelim2e", "ragged2e", "everysel", "setspace", "rsfs", "relsize", "ragged2e", "fundus-calligra", "microtype", "wasysym", "physics", "dvisvgm", "jknapltx", "wasy", "cm-super", "babel-english", "gnu-freefont", "mathastext", "cbfonts-fd" ] } } ================================================ FILE: .github/release.yml ================================================ # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes changelog: exclude: labels: - duplicate/wontfix - invalid - question - release authors: - dependabot[bot] - pre-commit-ci[bot] categories: # High Impact - title: "Breaking Changes 🚨" labels: - breaking changes # Highlights - title: "Highlights 🌟" labels: - highlight # User-facing - title: "New Features ✨" labels: - new feature - title: "Enhancements 🚀" labels: - enhancement - title: "Bug Fixes 🐛" labels: - pr:bugfix - title: "Deprecations & Removals ⚠️" labels: - pr:deprecation # Developer-facing - title: "Documentation 📚" labels: - documentation - title: "Testing 🧪" labels: - testing - title: "Infrastructure & Build 🔨" labels: - infrastructure - title: "Code Quality & Refactoring 🧹" labels: - maintenance - refactor - title: "Type Hints 📝" labels: - typehints # Catch-all (must be last) - title: "Other Changes" labels: - "*" ================================================ FILE: .github/scripts/ci_build_cairo.py ================================================ # Logic is as follows: # 1. Download cairo source code: https://cairographics.org/releases/cairo-.tar.xz # 2. Verify the downloaded file using the sha256sums file: https://cairographics.org/releases/cairo-.tar.xz.sha256sum # 3. Extract the downloaded file. # 4. Create a virtual environment and install meson and ninja. # 5. Run meson build in the extracted directory. Also, set required prefix. # 6. Run meson compile -C build. # 7. Run meson install -C build. import hashlib import logging import os import subprocess import sys import tarfile import tempfile import urllib.request from collections.abc import Generator from contextlib import contextmanager from pathlib import Path from sys import stdout CAIRO_VERSION = "1.18.0" CAIRO_URL = f"https://cairographics.org/releases/cairo-{CAIRO_VERSION}.tar.xz" CAIRO_SHA256_URL = f"{CAIRO_URL}.sha256sum" VENV_NAME = "meson-venv" BUILD_DIR = "build" INSTALL_PREFIX = Path(__file__).parent.parent.parent / "third_party" / "cairo" logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) def is_ci(): return os.getenv("CI", None) is not None def download_file(url, path): logger.info(f"Downloading {url} to {path}") block_size = 1024 * 1024 with urllib.request.urlopen(url) as response, open(path, "wb") as file: while True: data = response.read(block_size) if not data: break file.write(data) def verify_sha256sum(path, sha256sum): with open(path, "rb") as file: file_hash = hashlib.sha256(file.read()).hexdigest() if file_hash != sha256sum: raise Exception("SHA256SUM does not match") def extract_tar_xz(path, directory): with tarfile.open(path) as file: file.extractall(directory) def run_command(command, cwd=None, env=None): process = subprocess.Popen(command, cwd=cwd, env=env) process.communicate() if process.returncode != 0: raise Exception("Command failed") @contextmanager def gha_group(title: str) -> Generator: if not is_ci(): yield return print(f"\n::group::{title}") stdout.flush() try: yield finally: print("::endgroup::") stdout.flush() def set_env_var_gha(name: str, value: str) -> None: if not is_ci(): return env_file = os.getenv("GITHUB_ENV", None) if env_file is None: return with open(env_file, "a") as file: file.write(f"{name}={value}\n") stdout.flush() def get_ld_library_path(prefix: Path) -> str: # given a prefix, the ld library path can be found at # /lib/* or sometimes just /lib # this function returns the path to the ld library path # first, check if the ld library path exists at /lib/* ld_library_paths = list(prefix.glob("lib/*")) if len(ld_library_paths) == 1: return ld_library_paths[0].absolute().as_posix() # if the ld library path does not exist at /lib/*, # return /lib ld_library_path = prefix / "lib" if ld_library_path.exists(): return ld_library_path.absolute().as_posix() return "" def main(): if sys.platform == "win32": logger.info("Skipping build on windows") return with tempfile.TemporaryDirectory() as tmpdir: with gha_group("Downloading and Extracting Cairo"): logger.info(f"Downloading cairo version {CAIRO_VERSION}") download_file(CAIRO_URL, os.path.join(tmpdir, "cairo.tar.xz")) logger.info("Downloading cairo sha256sum") download_file(CAIRO_SHA256_URL, os.path.join(tmpdir, "cairo.sha256sum")) logger.info("Verifying cairo sha256sum") with open(os.path.join(tmpdir, "cairo.sha256sum")) as file: sha256sum = file.read().split()[0] verify_sha256sum(os.path.join(tmpdir, "cairo.tar.xz"), sha256sum) logger.info("Extracting cairo") extract_tar_xz(os.path.join(tmpdir, "cairo.tar.xz"), tmpdir) with gha_group("Installing meson and ninja"): logger.info("Creating virtual environment") run_command([sys.executable, "-m", "venv", os.path.join(tmpdir, VENV_NAME)]) logger.info("Installing meson and ninja") run_command( [ os.path.join(tmpdir, VENV_NAME, "bin", "pip"), "install", "meson", "ninja", ] ) # Inherit the current environment so PKG_CONFIG_PATH, CFLAGS, LDFLAGS, etc. are preserved. env_vars = os.environ.copy() # Prepend the venv bin directory so meson/ninja from the venv are used. env_vars["PATH"] = f"{os.path.join(tmpdir, VENV_NAME, 'bin')}{os.pathsep}{env_vars.get('PATH','')}" # Ensure Homebrew-provided pkgconfig and include/lib paths are present on macOS ARM. if sys.platform == "darwin": try: # Try to get specific prefix for lzo (safer for opt path), fall back to generic brew prefix. brew_prefix = subprocess.check_output(["brew", "--prefix", "lzo"], text=True).strip() except subprocess.CalledProcessError: try: brew_prefix = subprocess.check_output(["brew", "--prefix"], text=True).strip() except Exception: brew_prefix = None if brew_prefix: # pkg-config files can live in lib/pkgconfig or opt//lib/pkgconfig pkgconfig_paths = [f"{brew_prefix}/lib/pkgconfig", f"{brew_prefix}/opt/lzo/lib/pkgconfig"] # merge with any existing PKG_CONFIG_PATH existing_pc = env_vars.get("PKG_CONFIG_PATH", "") merged_pc = ":".join([p for p in pkgconfig_paths if p]) + (f":{existing_pc}" if existing_pc else "") env_vars["PKG_CONFIG_PATH"] = merged_pc # Ensure compiler & linker flags include brew include/lib existing_cflags = env_vars.get("CFLAGS", "") existing_ldflags = env_vars.get("LDFLAGS", "") env_vars["CFLAGS"] = f"-I{brew_prefix}/include {existing_cflags}".strip() env_vars["LDFLAGS"] = f"-L{brew_prefix}/lib {existing_ldflags}".strip() # Debugging: log environment keys relevant to detection # logger.info(f"env vars for meson: {env_vars}") with gha_group("Building and Installing Cairo"): logger.info("Running meson setup") run_command( [ os.path.join(tmpdir, VENV_NAME, "bin", "meson"), "setup", BUILD_DIR, f"--prefix={INSTALL_PREFIX.absolute().as_posix()}", "--buildtype=release", "-Dtests=disabled", ], cwd=os.path.join(tmpdir, f"cairo-{CAIRO_VERSION}"), env=env_vars, ) logger.info("Running meson compile") run_command( [ os.path.join(tmpdir, VENV_NAME, "bin", "meson"), "compile", "-C", BUILD_DIR, ], cwd=os.path.join(tmpdir, f"cairo-{CAIRO_VERSION}"), env=env_vars, ) logger.info("Running meson install") run_command( [ os.path.join(tmpdir, VENV_NAME, "bin", "meson"), "install", "-C", BUILD_DIR, ], cwd=os.path.join(tmpdir, f"cairo-{CAIRO_VERSION}"), env=env_vars, ) logger.info(f"Successfully built cairo and installed it to {INSTALL_PREFIX}") if __name__ == "__main__": if "--set-env-vars" in sys.argv: with gha_group("Setting environment variables"): # append the pkgconfig directory to PKG_CONFIG_PATH set_env_var_gha( "PKG_CONFIG_PATH", f"{Path(get_ld_library_path(INSTALL_PREFIX), 'pkgconfig').as_posix()}{os.pathsep}" f'{os.getenv("PKG_CONFIG_PATH", "")}', ) set_env_var_gha( "LD_LIBRARY_PATH", f"{get_ld_library_path(INSTALL_PREFIX)}{os.pathsep}" f'{os.getenv("LD_LIBRARY_PATH", "")}', ) sys.exit(0) main() ================================================ FILE: .github/workflows/cffconvert.yml ================================================ name: cffconvert on: push: paths: - CITATION.cff jobs: validate: name: "validate" runs-on: ubuntu-latest steps: - name: Check out a copy of the repository uses: actions/checkout@v6 - name: Check whether the citation metadata from CITATION.cff is valid uses: citation-file-format/cffconvert-github-action@2.0.0 with: args: "--validate" ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI concurrency: group: ${{ github.ref }} cancel-in-progress: true on: push: branches: - main pull_request: branches: - main jobs: test: runs-on: ${{ matrix.os }} env: DISPLAY: :0 PYTEST_ADDOPTS: "--color=yes" # colors in pytest PYTHONIOENCODING: "utf8" strategy: fail-fast: false matrix: os: [ubuntu-22.04, macos-latest, windows-latest] python: ["3.11", "3.12", "3.13", "3.14"] include: - os: macos-15-intel python: "3.13" steps: - name: Checkout the repository uses: actions/checkout@v6 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} - name: Install uv uses: astral-sh/setup-uv@v7 with: enable-cache: true - name: Setup cache variables shell: bash id: cache-vars run: | echo "date=$(/bin/date -u "+%m%w%Y")" >> $GITHUB_OUTPUT - name: Install system dependencies (Linux) if: runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@latest with: packages: python3-opengl libpango1.0-dev xvfb freeglut3-dev version: 1.0 - name: Install Texlive (Linux) if: runner.os == 'Linux' uses: zauguin/install-texlive@v4 with: packages: > scheme-basic latex fontspec tipa calligra xcolor standalone preview doublestroke setspace rsfs relsize ragged2e fundus-calligra microtype wasysym physics dvisvgm jknapltx wasy cm-super babel-english gnu-freefont mathastext cbfonts-fd xetex - name: Start virtual display (Linux) if: runner.os == 'Linux' run: | # start xvfb in background sudo /usr/bin/Xvfb $DISPLAY -screen 0 1280x1024x24 & - name: Setup Cairo Cache uses: actions/cache@v5 id: cache-cairo if: runner.os == 'Linux' || runner.os == 'macOS' with: path: ${{ github.workspace }}/third_party key: ${{ runner.os }}-${{ runner.arch }}-dependencies-cairo-${{ hashFiles('.github/scripts/ci_build_cairo.py') }} - name: Build and install Cairo (Linux and macOS) if: (runner.os == 'Linux' || runner.os == 'macOS') && steps.cache-cairo.outputs.cache-hit != 'true' run: python .github/scripts/ci_build_cairo.py - name: Set env vars for Cairo (Linux and macOS) if: runner.os == 'Linux' || runner.os == 'macOS' run: python .github/scripts/ci_build_cairo.py --set-env-vars - name: Setup macOS cache uses: actions/cache@v5 id: cache-macos if: runner.os == 'macOS' with: path: ${{ github.workspace }}/macos-cache key: ${{ runner.os }}-dependencies-tinytex-${{ hashFiles('.github/manimdependency.json') }}-${{ steps.cache-vars.outputs.date }}-1 - name: Install system dependencies (MacOS) if: runner.os == 'macOS' && steps.cache-macos.outputs.cache-hit != 'true' run: | tinyTexPackages=$(python -c "import json;print(' '.join(json.load(open('.github/manimdependency.json'))['macos']['tinytex']))") IFS=' ' read -a ttp <<< "$tinyTexPackages" oriPath=$PATH sudo mkdir -p $PWD/macos-cache echo "Install TinyTeX" sudo curl -L -o "/tmp/TinyTeX.tgz" "https://github.com/yihui/tinytex-releases/releases/download/daily/TinyTeX-1.tgz" sudo tar zxf "/tmp/TinyTeX.tgz" -C "$PWD/macos-cache" export PATH="$PWD/macos-cache/TinyTeX/bin/universal-darwin:$PATH" sudo tlmgr update --self for i in "${ttp[@]}"; do sudo tlmgr install "$i" done export PATH="$oriPath" echo "Completed TinyTeX" - name: Add macOS dependencies to PATH if: runner.os == 'macOS' shell: bash run: | echo "/Library/TeX/texbin" >> $GITHUB_PATH echo "$PWD/macos-cache/TinyTeX/bin/universal-darwin" >> $GITHUB_PATH - name: Setup Windows cache id: cache-windows if: runner.os == 'Windows' uses: actions/cache@v5 with: path: ${{ github.workspace }}\ManimCache key: ${{ runner.os }}-dependencies-tinytex-${{ hashFiles('.github/manimdependency.json') }}-${{ steps.cache-vars.outputs.date }}-1 - uses: ssciwr/setup-mesa-dist-win@v2 - name: Install system dependencies (Windows) if: runner.os == 'Windows' && steps.cache-windows.outputs.cache-hit != 'true' run: | $tinyTexPackages = $(python -c "import json;print(' '.join(json.load(open('.github/manimdependency.json'))['windows']['tinytex']))") -Split ' ' $OriPath = $env:PATH echo "Install Tinytex" Invoke-WebRequest "https://github.com/yihui/tinytex-releases/releases/download/daily/TinyTeX-1.zip" -OutFile "$($env:TMP)\TinyTex.zip" Expand-Archive -LiteralPath "$($env:TMP)\TinyTex.zip" -DestinationPath "$($PWD)\ManimCache\LatexWindows" $env:Path = "$($PWD)\ManimCache\LatexWindows\TinyTeX\bin\windows;$($env:PATH)" tlmgr update --self tlmgr install $tinyTexPackages $env:PATH=$OriPath echo "Completed Latex" - name: Add Windows dependencies to PATH if: runner.os == 'Windows' run: | $env:Path += ";" + "$($PWD)\ManimCache\LatexWindows\TinyTeX\bin\windows" echo "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Install dependencies and manim run: | uv sync --all-extras --locked - name: Run tests run: | uv run python -m pytest - name: Run module doctests run: | uv run python -m pytest -v --cov-append --ignore-glob="*opengl*" --doctest-modules manim - name: Run doctests in rst files run: | cd docs && uv run make doctest O=-tskip-manim ================================================ FILE: .github/workflows/codeql.yml ================================================ name: "CodeQL" on: push: branches: [ "main" ] pull_request: branches: [ "main" ] schedule: - cron: "21 16 * * 3" jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ python ] steps: - name: Checkout uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql.yml queries: +security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: category: "/language:${{ matrix.language }}" ================================================ FILE: .github/workflows/dependent-issues.yml ================================================ name: Dependent Issues on: issues: types: - opened - edited - reopened pull_request_target: types: - opened - edited - reopened - synchronize schedule: - cron: '0 0 * * *' # schedule daily check jobs: check: runs-on: ubuntu-latest steps: - uses: z0al/dependent-issues@v1 env: # (Required) The token to use to make API calls to GitHub. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: # (Optional) The label to use to mark dependent issues label: dependent # (Optional) Enable checking for dependencies in issues. Enable by # setting the value to "on". Default "off" check_issues: on # (Optional) A comma-separated list of keywords. Default # "depends on, blocked by" keywords: depends on, blocked by ================================================ FILE: .github/workflows/publish-docker.yml ================================================ name: Publish Docker Image on: push: branches: - main release: types: [released] jobs: docker-latest: runs-on: ubuntu-latest if: github.event_name != 'release' steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: platforms: linux/arm64,linux/amd64 push: true file: docker/Dockerfile tags: | manimcommunity/manim:latest docker-release: runs-on: ubuntu-latest if: github.event_name == 'release' steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Get Version id: create_release shell: python env: tag_act: ${{ github.ref }} run: | import os ref_tag = os.getenv('tag_act').split('/')[-1] with open(os.getenv('GITHUB_OUTPUT'), 'w') as f: print(f"tag_name={ref_tag}", file=f) - name: Build and push uses: docker/build-push-action@v6 with: platforms: linux/arm64,linux/amd64 push: true file: docker/Dockerfile tags: | manimcommunity/manim:stable manimcommunity/manim:latest manimcommunity/manim:${{ steps.create_release.outputs.tag_name }} ================================================ FILE: .github/workflows/python-publish.yml ================================================ name: Publish Release on: release: types: [released] jobs: release: name: "Publish release" runs-on: ubuntu-latest environment: release permissions: id-token: write contents: write steps: - uses: actions/checkout@v6 - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y build-essential python3-dev libcairo2-dev libpango1.0-dev - name: Set up Python 3.13 uses: actions/setup-python@v6 with: python-version: 3.13 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Build and push release to PyPI run: | uv build uv publish - name: Store artifacts uses: actions/upload-artifact@v6 with: path: dist/*.tar.gz name: manim.tar.gz - name: Upload Release Asset shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | TAG=${{ github.event.release.tag_name }} gh release upload "$TAG" "dist/manim-${TAG#v}.tar.gz" ================================================ FILE: .github/workflows/release-publish-documentation.yml ================================================ name: Publish downloadable documentation on: release: types: [released] workflow_dispatch: jobs: build-and-publish-htmldocs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: python-version: 3.13 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install system dependencies run: | sudo apt update && sudo apt install -y \ pkg-config libcairo-dev libpango1.0-dev wget fonts-roboto wget -qO- "https://yihui.org/tinytex/install-bin-unix.sh" | sh echo ${HOME}/.TinyTeX/bin/x86_64-linux >> $GITHUB_PATH - name: Install LaTeX and Python dependencies run: | tlmgr update --self tlmgr install \ babel-english ctex doublestroke dvisvgm frcursive fundus-calligra jknapltx \ mathastext microtype physics preview ragged2e relsize rsfs setspace standalone \ wasy wasysym uv sync - name: Build and package documentation run: | cd docs/ uv run make html cd build/html/ tar -czvf ../html-docs.tar.gz * - name: Store artifacts uses: actions/upload-artifact@v6 with: path: ${{ github.workspace }}/docs/build/html-docs.tar.gz name: html-docs.tar.gz - name: Install Dependency run: pip install requests - name: Get Upload URL if: github.event == 'release' id: create_release shell: python env: access_token: ${{ secrets.GITHUB_TOKEN }} tag_act: ${{ github.ref }} run: | import requests import os ref_tag = os.getenv('tag_act').split('/')[-1] access_token = os.getenv('access_token') headers = { "Accept":"application/vnd.github.v3+json", "Authorization": f"token {access_token}" } url = f"https://api.github.com/repos/ManimCommunity/manim/releases/tags/{ref_tag}" c = requests.get(url,headers=headers) upload_url=c.json()['upload_url'] with open(os.getenv('GITHUB_OUTPUT'), 'w') as f: print(f"upload_url={upload_url}", file=f) print(f"tag_name={ref_tag[1:]}", file=f) - name: Upload Release Asset if: github.event == 'release' id: upload-release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: ${{ github.workspace }}/docs/build/html-docs.tar.gz asset_name: manim-htmldocs-${{ steps.create_release.outputs.tag_name }}.tar.gz asset_content_type: application/gzip ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ *.log # Sphinx documentation docs/_build/ docs/build/ docs/source/_autosummary/ docs/source/reference/ docs/source/_build/ docs/rendering_times.csv #i18n docs/i18n/gettext/.doctrees docs/i18n/**/*.mo docs/i18n/translatable.po docs/i18n/untranslatable.po # PyBuilder target/ # Jupyter Notebook jupyter/ .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # PyCharm /.idea/ # Celery stuff celerybeat-schedule celerybeat.pid # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json *.pyc *.bak .DS_Store .floo .flooignore .vscode .vs *.xml *.iml media .eggs/ build/ dist/ /media_dir.txt # ^TODO: Remove the need for this with a proper config file # Ignore the built dependencies third_party/* ================================================ FILE: .pre-commit-config.yaml ================================================ default_stages: [pre-commit, pre-push] fail_fast: false exclude: ^(manim/grpc/gen/|docs/i18n/) repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: check-ast name: Validate Python - id: trailing-whitespace - id: mixed-line-ending - id: end-of-file-fixer - id: check-toml name: Validate pyproject.toml - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell files: ^.*\.(py|md|rst)$ args: ["-L", "medias,nam"] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.10 hooks: - id: ruff name: ruff lint types: [python] args: [--exit-non-zero-on-fix] - id: ruff-format types: [python] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.19.1 hooks: - id: mypy additional_dependencies: [ types-backports, types-decorator, types-docutils, types-requests, types-setuptools, ] files: ^manim/ ================================================ FILE: .pylintrc ================================================ [MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-whitelist= # Specify a score threshold to be exceeded before program exits with error. fail-under=10.0 # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python module names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then re-enable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=print-statement, parameter-unpacking, unpacking-in-except, old-raise-syntax, backtick, long-suffix, old-ne-operator, old-octal-literal, import-star-module-level, non-ascii-bytes-literal, raw-checker-failed, bad-inline-option, locally-disabled, file-ignored, suppressed-message, useless-suppression, deprecated-pragma, use-symbolic-message-instead, apply-builtin, basestring-builtin, buffer-builtin, cmp-builtin, coerce-builtin, execfile-builtin, file-builtin, long-builtin, raw_input-builtin, reduce-builtin, standarderror-builtin, unicode-builtin, xrange-builtin, coerce-method, delslice-method, getslice-method, setslice-method, no-absolute-import, old-division, dict-iter-method, dict-view-method, next-method-called, metaclass-assignment, indexing-exception, raising-string, reload-builtin, oct-method, hex-method, nonzero-method, cmp-method, input-builtin, round-builtin, intern-builtin, unichr-builtin, map-builtin-not-iterating, zip-builtin-not-iterating, range-builtin-not-iterating, filter-builtin-not-iterating, using-cmp-argument, eq-without-hash, div-method, idiv-method, rdiv-method, exception-message-attribute, invalid-str-codec, sys-max-int, bad-python3-import, deprecated-string-function, deprecated-str-translate-call, deprecated-itertools-function, deprecated-types-field, next-method-defined, dict-items-not-iterating, dict-keys-not-iterating, dict-values-not-iterating, deprecated-operator-function, deprecated-urllib-function, xreadlines-attribute, deprecated-sys-function, exception-escape, comprehension-escape, fixme, missing-function-docstring # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a score less than or equal to 10. You # have access to the variables 'error', 'warning', 'refactor', and 'convention' # which contain the number of messages in each category, as well as 'statement' # which is the total number of statements analyzed. This score is used by the # global evaluation report (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=yes [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Bad variable names regexes, separated by a comma. If names match any regex, # they will always be refused bad-names-rgxs= # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. #class-attribute-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, e, Run, _ # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted good-names-rgxs= # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. #variable-rgx= [STRING] # This flag controls whether inconsistent-quotes generates a warning when the # character used as a quote delimiter is used inconsistently within a module. check-quote-consistency=no # This flag controls whether the implicit-str-concat should generate a warning # on implicit string concatenation in sequences defined over several lines. check-str-concat-over-line-jumps=no [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=88 # Maximum number of lines in a module. max-module-lines=1000 # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it work, # install the python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains the private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to the private dictionary (see the # --spelling-private-dict-file option) instead of raising a message. spelling-store-unknown-words=no [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis). It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 # List of decorators that change the signature of a decorated function. signature-mutators= [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid defining new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO # Regular expression of note tags to take in consideration. #notes-rgx= [LOGGING] # The type of string formatting that logging methods do. `old` means using % # formatting, `new` is for `{}` formatting. logging-format-style=old # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [DESIGN] # Maximum number of arguments for function / method. max-args=5 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=12 # Maximum number of locals for function / method body. max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of return / yield for function / method body. max-returns=6 # Maximum number of statements in function / method body. max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 [IMPORTS] # List of modules that can be imported at any level, not just the top level # one. allow-any-import-level= # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled). ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled). import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant # Couples of modules and preferred modules, separated by a comma. preferred-modules= [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp, __post_init__ # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "BaseException, Exception". overgeneral-exceptions=BaseException, Exception ================================================ FILE: .readthedocs.yml ================================================ version: 2 sphinx: configuration: docs/source/conf.py build: os: ubuntu-22.04 tools: python: "3.13" apt_packages: - libpango1.0-dev - graphviz python: install: - requirements: docs/rtd-requirements.txt - requirements: docs/requirements.txt - method: pip path: . ================================================ FILE: CITATION.cff ================================================ # YAML 1.2 --- authors: - name: "The Manim Community Developers" cff-version: "1.2.0" date-released: 2026-02-27 license: MIT message: "We acknowledge the importance of good software to support research, and we note that research becomes more valuable when it is communicated effectively. To demonstrate the value of Manim, we ask that you cite Manim in your work." title: Manim – Mathematical Animation Framework url: "https://www.manim.community/" version: "v0.20.1" ... ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct > TL;DR Be excellent to each other; we're a community after all. If you run into issues with others in our community, please [contact](https://www.manim.community/discord/) a Manim Community Dev, or Moderator. ## Purpose The Manim Community includes members of varying skills, languages, personalities, cultural backgrounds, and experiences from around the globe. Through these differences, we continue to grow and collectively improve upon an open-source animation engine. When working in a community, it is important to remember that you are interacting with humans on the other end of your screen. This code of conduct will guide your interactions and keep Manim a positive environment for our developers, users, and fundamentally our growing community. ## Our Community Members of Manim Community are respectful, open, and considerate. Behaviors that reinforce these values contribute to our positive environment, and include: - **Being respectful.** Respectful of others, their positions, experiences, viewpoints, skills, commitments, time, and efforts. - **Being open.** Open to collaboration, whether it's on problems, Pull Requests, issues, or otherwise. - **Being considerate.** Considerate of their peers -- other Manim users and developers. - **Focusing on what is best for the community.** We're respectful of the processes set forth in the community, and we work within them. - **Showing empathy towards other community members.** We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views. - **Gracefully accepting constructive criticism.** When we disagree, we are courteous in raising our issues. - **Using welcoming and inclusive language.** We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference. ## Our Standards Every member of our community has the right to have their identity respected. Manim Community is dedicated to providing a positive environment for everyone, regardless of age, gender identity and expression, sexual orientation, disability, physical appearance, body size, ethnicity, nationality, race, religion (or lack thereof), education, or socioeconomic status. ## Inappropriate Behavior Examples of unacceptable behavior by participants include: * Harassment of any participants in any form * Deliberate intimidation, stalking, or following * Logging or taking screenshots of online activity for harassment purposes * Publishing others' private information, such as a physical or electronic address, without explicit permission * Violent threats or language directed against another person * Incitement of violence or harassment towards any individual, including encouraging a person to commit suicide or to engage in self-harm * Creating additional online accounts in order to harass another person or circumvent a ban * Sexual language and imagery in online communities or any conference venue, including talks * Insults, put-downs, or jokes that are based upon stereotypes, that are exclusionary, or that hold others up for ridicule * Excessive swearing * Unwelcome sexual attention or advances * Unwelcome physical contact, including simulated physical contact (eg, textual descriptions like "hug" or "backrub") without consent or after a request to stop * Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others * Sustained disruption of online community discussions, in-person presentations, or other in-person events * Continued one-on-one communication after requests to cease * Other conduct that is inappropriate for a professional audience including people of many different backgrounds Community members asked to stop any inappropriate behavior are expected to comply immediately. ## Manim Community Online Spaces This Code of Conduct applies to the following online spaces: - The [ManimCommunity GitHub Organization](https://github.com/ManimCommunity) and all of its repositories - The Manim [Discord](https://www.manim.community/discord/) - The Manim [Reddit](https://www.reddit.com/r/manim/) - The Manim [Twitter](https://twitter.com/manim\_community/) This Code of Conduct applies to every member in official Manim Community online spaces, including: - Moderators - Maintainers - Developers - Reviewers - Contributors - Users - All community members ## Consequences If a member's behavior violates this code of conduct, the Manim Community Code of Conduct team may take any action they deem appropriate, including, but not limited to: warning the offender, temporary bans, deletion of offending messages, and expulsion from the community and its online spaces. The full list of consequences for inappropriate behavior is listed below in the Enforcement Procedures. Thank you for helping make this a welcoming, friendly community for everyone. ## Contact Information If you believe someone is violating the code of conduct, or have any other concerns, please contact a Manim Community Dev, or Moderator immediately. They can be reached on Manim's Community [Discord](https://www.manim.community/discord/).

## Enforcement Procedures This document summarizes the procedures the Manim Community Code of Conduct team uses to enforce the Code of Conduct. ### Summary of processes When the team receives a report of a possible Code of Conduct violation, it will: 1. Acknowledge the receipt of the report. 1. Evaluate conflicts of interest. 1. Call a meeting of code of conduct team members without a conflict of interest. 1. Evaluate the reported incident. 1. Propose a behavioral modification plan. 1. Propose consequences for the reported behavior. 1. Vote on behavioral modification plan and consequences for the reported person. 1. Contact Manim Community moderators to approve the behavioral modification plan and consequences. 1. Follow up with the reported person. 1. Decide further responses. 1. Follow up with the reporter. ### Acknowledge the report Reporters should receive an acknowledgment of the receipt of their report within 48 hours. ### Conflict of interest policy Examples of conflicts of interest include: * You have a romantic or platonic relationship with either the reporter or the reported person. It's fine to participate if they are an acquaintance. * The reporter or reported person is someone you work closely with. This could be someone on your team or someone who works on the same project as you. * The reporter or reported person is a maintainer who regularly reviews your contributions * The reporter or reported person is your metamour. * The reporter or reported person is your family member Committee members do not need to state why they have a conflict of interest, only that one exists. Other team members should not ask why the person has a conflict of interest. Anyone who has a conflict of interest will remove themselves from the discussion of the incident, and recluse themselves from voting on a response to the report. ### Evaluating a report #### Jurisdiction * *Is this a Code of Conduct violation?* Is this behavior on our list of inappropriate behavior? Is it borderline inappropriate behavior? Does it violate our community norms? * *Did this occur in a space that is within our Code of Conduct's scope?* If the incident occurred outside the community, but a community member's mental health or physical safety may be negatively impacted if no action is taken, the incident may be in scope. Private conversations in community spaces are also in scope. #### Impact * *Did this incident occur in a private conversation or a public space?* Incidents that all community members can see will have a more negative impact. * *Does this behavior negatively impact a marginalized group in our community?* Is the reporter a person from a marginalized group in our community? How is the reporter being negatively impacted by the reported person's behavior? Are members of the marginalized group likely to disengage with the community if no action was taken on this report? * *Does this incident involve a community leader?* Community members often look up to community leaders to set the standard of acceptable behavior #### Risk * *Does this incident include sexual harassment?* * *Does this pose a safety risk?* Does the behavior put a person's physical safety at risk? Will this incident severely negatively impact someone's mental health? * *Is there a risk of this behavior being repeated?* Does the reported person understand why their behavior was inappropriate? Is there an established pattern of behavior from past reports? Reports which involve higher risk or higher impact may face more severe consequences than reports which involve lower risk or lower impact. ### Propose consequences What follows are examples of possible consequences of an incident report. This list of consequences is not exhaustive, and the Manim Community Code of Conduct team reserves the right to take any action it deems necessary. Possible private responses to an incident include: * Nothing, if the behavior was determined to not be a Code of Conduct violation * A warning * A final warning * Temporarily removing the reported person from the community's online space(s) * Permanently removing the reported person from the community's online space(s) * Publishing an account of the incident ### Team vote Some team members may have a conflict of interest and may be excluded from discussions of a particular incident report. Excluding those members, decisions on the behavioral modification plans and consequences will be determined by a two-thirds majority vote of the Manim Community Code of Conduct team. ### Moderators approval Once the team has approved the behavioral modification plans and consequences, they will communicate the recommended response to the Manim Community moderators. The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report. Moderators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week. In cases where the moderators disagree on the suggested resolution for a report, the Manim Community Code of Conduct team may choose to notify the Manim Community Moderators. ### Follow up with the reported person The Manim Community Code of Conduct team will work with Manim Community moderators to draft a response to the reported person. The response should contain: * A description of the person's behavior in neutral language * The negative impact of that behavior * A concrete behavioral modification plan * Any consequences of their behavior The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report. The reported person should be discouraged from contacting the reporter to discuss the report. If they wish to apologize to the reporter, the team can accept the apology on behalf of the reporter. ### Decide further responses If the reported person provides additional context, the Manim Community Code of Conduct team may need to re-evaluate the behavioral modification plan and consequences. ### Follow up with the reporter A person who makes a report should receive a follow-up response stating what action was taken in response to the report. If the team decided no response was needed, they should provide an explanation why it was not a Code of Conduct violation. Reports that are not made in good faith (such as "reverse sexism" or "reverse racism") may receive no response. The follow-up should be sent no later than one week after the receipt of the report. If deliberation or follow-up with the reported person takes longer than one week, the team should send a status update to the reporter. ### Changes to Code of Conduct When discussing a change to the Manim Community code of conduct or enforcement procedures, the Manim Community Code of Conduct team will follow this decision-making process: * **Brainstorm options.** Team members should discuss any relevant context and brainstorm a set of possible options. It is important to provide constructive feedback without getting side-tracked from the main question. * **Vote.** Proposed changes to the code of conduct will be decided by a two-thirds majority of all voting members of the Code of Conduct team. Team members are listed in the charter. Currently active voting members are listed in the following section. * **Board Vote.** Once a working draft is in place for the Code of Conduct and procedures, the Code of Conduct team shall provide the Manim Community Moderators with a draft of the changes. The Manim Community Moderators will vote on the changes at a board meeting. ### Current list of voting members - All available Community Developers (i.e. those with "write" permissions, or above, on the Manim Community GitHub organization). ## License This Code of Conduct is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](https://creativecommons.org/licenses/by-sa/3.0/). ## Attributions This Code of Conduct was forked from the code of conduct from the [Python Software Foundation](https://www.python.org/psf/conduct/) and adapted by Manim Community. ================================================ FILE: CONTRIBUTING.md ================================================ # Thanks for your interest in contributing! Please read our contributing guidelines which are hosted at https://docs.manim.community/en/latest/contributing.html ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 3Blue1Brown LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: LICENSE.community ================================================ MIT License Copyright (c) 2024, the Manim Community Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

Manim Community logo

PyPI Latest Release Docker image Launch Binder MIT License Reddit Twitter Discord Documentation Status CI

An animation engine for explanatory math videos


Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as demonstrated in the videos of [3Blue1Brown](https://www.3blue1brown.com/). > [!NOTE] > The community edition of Manim (ManimCE) is a version maintained and developed by the community. It was forked from 3b1b/manim, a tool originally created and open-sourced by Grant Sanderson, also creator of the 3Blue1Brown educational math videos. While Grant Sanderson continues to maintain his own repository, we recommend this version for its continued development, improved features, enhanced documentation, and more active community-driven maintenance. If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)). ## Table of Contents: - [Installation](#installation) - [Usage](#usage) - [Documentation](#documentation) - [Docker](#docker) - [Help with Manim](#help-with-manim) - [Contributing](#contributing) - [License](#license) ## Installation > [!CAUTION] > These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version. Manim requires a few dependencies that must be installed prior to using it. If you want to try it out first before installing it locally, you can do so [in our online Jupyter environment](https://try.manim.community/). For local installation, please visit the [Documentation](https://docs.manim.community/en/stable/installation.html) and follow the appropriate instructions for your operating system. ## Usage Manim is an extremely versatile package. The following is an example `Scene` you can construct: ```python from manim import * class SquareToCircle(Scene): def construct(self): circle = Circle() square = Square() square.flip(RIGHT) square.rotate(-3 * TAU / 8) circle.set_fill(PINK, opacity=0.5) self.play(Create(square)) self.play(Transform(square, circle)) self.play(FadeOut(square)) ``` In order to view the output of this scene, save the code in a file called `example.py`. Then, run the following in a terminal window: ```sh manim -p -ql example.py SquareToCircle ``` You should see your native video player program pop up and play a simple scene in which a square is transformed into a circle. You may find some more simple examples within this [GitHub repository](example_scenes). You can also visit the [official gallery](https://docs.manim.community/en/stable/examples.html) for more advanced examples. Manim also ships with a `%%manim` IPython magic which allows to use it conveniently in JupyterLab (as well as classic Jupyter) notebooks. See the [corresponding documentation](https://docs.manim.community/en/stable/reference/manim.utils.ipython_magic.ManimMagic.html) for some guidance and [try it out online](https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb). ## Command line arguments The general usage of Manim is as follows: ![manim-illustration](https://raw.githubusercontent.com/ManimCommunity/manim/main/docs/source/_static/command.png) The `-p` flag in the command above is for previewing, meaning the video file will automatically open when it is done rendering. The `-ql` flag is for a faster rendering at a lower quality. Some other useful flags include: - `-s` to skip to the end and just show the final frame. - `-n ` to skip ahead to the `n`'th animation of a scene. - `-f` show the file in the file browser. For a thorough list of command line arguments, visit the [documentation](https://docs.manim.community/en/stable/guides/configuration.html). ## Documentation Documentation is in progress at [ReadTheDocs](https://docs.manim.community/). ## Docker The community also maintains a docker image (`manimcommunity/manim`), which can be found [on DockerHub](https://hub.docker.com/r/manimcommunity/manim). Instructions on how to install and use it can be found in our [documentation](https://docs.manim.community/en/stable/installation/docker.html). ## Help with Manim If you need help installing or using Manim, feel free to reach out to our [Discord Server](https://www.manim.community/discord/) or [Reddit Community](https://www.reddit.com/r/manim). If you would like to submit a bug report or feature request, please open an issue. ## Contributing Contributions to Manim are always welcome. In particular, there is a dire need for tests and documentation. For contribution guidelines, please see the [documentation](https://docs.manim.community/en/stable/contributing.html). However, please note that Manim is currently undergoing a major refactor. In general, contributions implementing new features will not be accepted in this period. The contribution guide may become outdated quickly; we highly recommend joining our [Discord server](https://www.manim.community/discord/) to discuss any potential contributions and keep up to date with the latest developments. Most developers on the project use `uv` for management. You'll want to have uv installed and available in your environment. Learn more about `uv` at its [documentation](https://docs.astral.sh/uv/) and find out how to install manim with uv at the [manim dev-installation guide](https://docs.manim.community/en/latest/contributing/development.html) in the manim documentation. ## How to Cite Manim We acknowledge the importance of good software to support research, and we note that research becomes more valuable when it is communicated effectively. To demonstrate the value of Manim, we ask that you cite Manim in your work. Currently, the best way to cite Manim is to go to our [repository page](https://github.com/ManimCommunity/manim) (if you aren't already) and click the "cite this repository" button on the right sidebar. This will generate a citation in your preferred format, and will also integrate well with citation managers. ## Code of Conduct Our full code of conduct, and how we enforce it, can be read on [our website](https://docs.manim.community/en/stable/conduct.html). ## License The software is double-licensed under the MIT license, with copyright by 3blue1brown LLC (see LICENSE), and copyright by Manim Community Developers (see LICENSE.community). ================================================ FILE: crowdin.yml ================================================ files: - source: /docs/i18n/gettext/**/*.pot translation: /docs/i18n/%two_letters_code%/LC_MESSAGES/**/%file_name%.po ================================================ FILE: docker/Dockerfile ================================================ # ── Stage 1: builder ───────────────────────────────────────────────────────── FROM python:3.14-slim AS builder RUN apt-get update -qq \ && apt-get install --no-install-recommends -y \ build-essential \ gcc \ cmake \ make \ pkg-config \ wget \ libcairo2-dev \ libffi-dev \ libpango1.0-dev \ libegl-dev \ && rm -rf /var/lib/apt/lists/* # Setup a minimal TeX Live installation (no ctex: drops ~100 MB of CJK fonts/packages) COPY docker/texlive-profile.txt /tmp/ ENV PATH=/usr/local/texlive/bin/armhf-linux:/usr/local/texlive/bin/aarch64-linux:/usr/local/texlive/bin/x86_64-linux:$PATH RUN wget -O /tmp/install-tl-unx.tar.gz http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz \ && mkdir /tmp/install-tl \ && tar -xzf /tmp/install-tl-unx.tar.gz -C /tmp/install-tl --strip-components=1 \ && /tmp/install-tl/install-tl --profile=/tmp/texlive-profile.txt \ && tlmgr install \ amsmath babel-english cbfonts-fd cm-super count1to doublestroke dvisvgm everysel \ fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin \ mathastext microtype multitoc physics prelim2e preview ragged2e relsize rsfs \ setspace standalone tipa wasy wasysym xcolor xetex xkeyval \ && rm -rf /tmp/install-tl /tmp/install-tl-unx.tar.gz # Install manim into an isolated virtualenv ENV VIRTUAL_ENV=/opt/venv RUN python -m venv $VIRTUAL_ENV ENV PATH="$VIRTUAL_ENV/bin:$PATH" COPY . /opt/manim WORKDIR /opt/manim RUN pip install --no-cache-dir .[jupyterlab] # ── Stage 2: runtime ───────────────────────────────────────────────────────── FROM python:3.14-slim # Runtime libs only: # - no ffmpeg: PyAV (av package) bundles its own ffmpeg libraries in av.libs/ # - OpenGL: keep EGL for headless rendering and libGL as required by moderngl/glcontext # - fonts-noto-core instead of fonts-noto (drops CJK noto fonts) RUN apt-get update -qq \ && apt-get install --no-install-recommends -y \ libcairo2 \ libpango-1.0-0 \ libpangocairo-1.0-0 \ libpangoft2-1.0-0 \ libffi8 \ libegl1 \ libgl1 \ ghostscript \ fonts-noto-core \ fontconfig \ && rm -rf /var/lib/apt/lists/* RUN fc-cache -fv # Copy TeX Live from builder ENV PATH=/usr/local/texlive/bin/armhf-linux:/usr/local/texlive/bin/aarch64-linux:/usr/local/texlive/bin/x86_64-linux:$PATH COPY --from=builder /usr/local/texlive /usr/local/texlive # Copy the pre-built virtualenv from builder ENV VIRTUAL_ENV=/opt/venv COPY --from=builder /opt/venv /opt/venv ENV PATH="$VIRTUAL_ENV/bin:$PATH" ARG NB_USER=manimuser ARG NB_UID=1000 ENV USER=${NB_USER} ENV NB_UID=${NB_UID} ENV HOME=/manim RUN adduser --disabled-password \ --gecos "Default user" \ --uid ${NB_UID} \ ${NB_USER} WORKDIR ${HOME} RUN chown -R ${NB_USER}:${NB_USER} ${HOME} && chmod 777 ${HOME} USER ${NB_USER} CMD ["/bin/bash"] ================================================ FILE: docker/readme.md ================================================ See the [main README](https://github.com/ManimCommunity/manim/blob/main/README.md) for some instructions on how to use this image. # Building the image The docker image corresponding to the checked out version of the git repository can be built by running ``` docker build -t manimcommunity/manim:TAG -f docker/Dockerfile . ``` from the root directory of the repository. Multi-platform builds are possible by running ``` docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag manimcommunity/manim:TAG -f docker/Dockerfile . ``` from the root directory of the repository. # Runtime notes - The image is built via a multi-stage Dockerfile (build dependencies are not carried into the runtime stage). - The image does not include the `ffmpeg` CLI binary. - The default TeX installation is minimal and does not include `ctex`. - Headless OpenGL rendering relies on EGL/GL runtime libraries available in the image. ================================================ FILE: docker/texlive-profile.txt ================================================ selected_scheme scheme-minimal TEXDIR /usr/local/texlive TEXMFCONFIG ~/.texlive/texmf-config TEXMFHOME ~/texmf TEXMFLOCAL /usr/local/texlive/texmf-local TEXMFSYSCONFIG /usr/local/texlive/texmf-config TEXMFSYSVAR /usr/local/texlive/texmf-var TEXMFVAR ~/.texlive/texmf-var option_doc 0 option_src 0 ================================================ FILE: docs/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build # Path base is the source directory SOURCEDIR = . BUILDDIR = ../build # Put it first so that "make" without argument is like "make help". help: @(cd source; $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)) .PHONY: help Makefile i18n # All the code is executed as if everything was launched in one shell. .ONESHELL: # Like make clean but also remove files generated by autosummary and # rendered videos. cleanall: clean @rm source/reference/* @rm -rf source/media @rm -f rendering_times.csv i18n: @(cd source; $(SPHINXBUILD) -M gettext "$(SOURCEDIR)" ../i18n/ -t skip-manim $(SPHINXOPTS) $(O);cd ../i18n;bash stripUntranslatable.sh) # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @(cd source; $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)) ================================================ FILE: docs/html ================================================ ================================================ FILE: docs/i18n/fr/LC_MESSAGES/index.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\n" "X-Crowdin-File-ID: 5163\n" "Language-Team: French\n" "Language: fr_FR\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/index.rst:7 msgid "Manim Community Overview" msgstr "Manim communauté - Vue d'ensemble" #: ../../source/index.rst:9 msgid "Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run." msgstr "Animer des concepts techniques est traditionellement plutôt compliqué puisqu'il est difficile de rendre les animations assez precises pour bien représenter ces concepts. ``Manim`` utilise Python pour génerer des animation en programmant, permettant de préciser de manière exacte leur execution." #: ../../source/index.rst:14 msgid "This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``." msgstr "Ce projet est encore en grande partie en cours de développement, mais nous éspérons que les informations fournies ici permettront aux nouveaux venus de mieux commencer à utiliser ``Manim``." #: ../../source/index.rst:20 msgid "All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!" msgstr "Le contenu de ces documentations est distribué sous licence MIT. C'est aussi vrai pour les exemples présentés, vous pouvez utilisez les codes librement dans vos projets !" #: ../../source/index.rst:23 msgid "We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter `_, `Reddit `_, or via `Discord `_." msgstr "Nous sommes curieux de voir les super projets que vous construisez avec cette librairie, partagez-les donc avec nous `sur Twitter `_, `Reddit `_, or sur `Discord `_. " #: ../../source/index.rst:27 msgid "In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage `_ or `our GitHub repository `_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_." msgstr "Si vous publiez votre travail fait avec Manim, nous apprécierions si vous ajoutiez un lien vers `notre site principal `_ ou vers `notre repo GitHub `_. Si vous utilisez Manim dans un contexte scientifique, des instructions afin de citer une certaine version de Manim sont disponibles (en anglais) `dans notre fichier README `_." #: ../../source/index.rst:36 msgid "As a quick reference, here are some often used modules, classes and methods:" msgstr "Comme rapide indications, voici certains des modules, classes et méthodes les plus utilisées:" #: ../../source/index.rst:38 msgid "Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," msgstr "Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," #: ../../source/index.rst:43 msgid "Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," msgstr "Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," ================================================ FILE: docs/i18n/fr/LC_MESSAGES/installation.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/installation.pot\n" "X-Crowdin-File-ID: 5165\n" "Language-Team: French\n" "Language: fr_FR\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/installation.rst:2 msgid "Installation" msgstr "Installation" #: ../../source/installation.rst:4 msgid "Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try." msgstr "Suivant comment vous souhaitez utiliser Manim, différentes options d'installation s'offrent à vous : Si vous voulez simplement vous amuser avec, les bloc-notes interactifs sur votre navigateur sont un moyen simple d'explorer les possibilités offertes par la bibliothèque, puisqu'ils ne nécessitent pas d'installer quoi que ce soit sur votre ordinateur. Allez donc voir à l'adresse https://try.manim.community pour tester notre tutoriel interactif." #: ../../source/installation.rst:10 msgid "Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker)." msgstr "Sinon, si vous souhaitez utiliser Manim pour travailler sur un projet d'animation, il vaut mieux installer la bibliothèque sur votre ordinateur (sur le Python de votre sytème, ou via Docker)." #: ../../source/installation.rst:16 msgid "Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :doc:`differences between Manim versions ` if you are unsure which version you should install." msgstr "Prenez garde, il y a plusieurs différentes versions de Manim. Les instructions sur ce site sont **seulement** pour la *version communautaire* (*community edition*). Découvrez en plus sur les :doc:`différences entre les versions de manim ` si vous n'êtes pas sûrs de quelle version installer." #: ../../source/installation.rst:22 msgid ":ref:`Installing Manim to your system's Python `" msgstr ":ref:`Installer Manim sur le Python de votre système `" #: ../../source/installation.rst:23 msgid ":ref:`Using Manim via Docker `" msgstr ":ref:`Utiliser Manim via Docker `" #: ../../source/installation.rst:24 msgid ":ref:`Interactive Jupyter notebooks via Binder / Google Colab `" msgstr ":ref:`Blocs-notes interactifs Jupyter via Binder / Google Colab `" #: ../../source/installation.rst:31 msgid "Installing Manim locally" msgstr "Installation de Manim sur l'ordinateur" #: ../../source/installation.rst:33 msgid "Manim is a Python library, and it can be `installed via pip `__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow." msgstr "Manim est une bibliothèque Python, et peut donc être `installée avec pip `__. Par contre, pour que Manim fonctionne correctement, quelques dépendances doivent être installées avant. Les pages suivantes offrent les instructions à suivre selon votre système d'exploitation." #: ../../source/installation.rst:41 msgid "Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord `__, or start a new Discussion `directly on GitHub `__." msgstr "Suivant la configuration particulière de votre ordinateur, le processus d'installation peut varier légèrement. Assurez-vous d'avoir essayé de suivre avec attention les étapes sur les pages ci-dessous, mais si vous faites face à un problème, nous serons heureux de vous aider : vous pouvez `rejoindre notre serveur Discord `__, ou vous pouvez lancer une nouvelle Discussion `directement sur GitHub `__." #: ../../source/installation.rst:57 msgid "Once Manim is installed locally, you can proceed to our :doc:`quickstart guide ` which walks you through rendering a first simple scene." msgstr "Une fois que Manim est installé sur votre ordinateur, vous pouvez allez lire notre :doc:`guide de démarage rapide ` qui va vous apprendre à rendre une première scène simpliste." #: ../../source/installation.rst:61 msgid "As mentioned above, do not worry if there are errors or other problems: consult our :doc:`troubleshooting guide ` for help, or get in touch with the community via `GitHub discussions `__ or `Discord `__." msgstr "Comme indiqué ci-dessus, ne vous inquétez pas si vous rencontrez des erreurs ou autres problèmes : consultez notre :doc:`guide de dépannage ` pour obtenir de l'aide, sinon, prenez contact avec la communauté via `les discussions GitHub `__ ou via `Discord `__." #: ../../source/installation.rst:73 msgid "Using Manim via Docker" msgstr "Utiliser Manim via Docker" #: ../../source/installation.rst:75 msgid "`Docker `__ is a virtualization tool that allows the distribution of encapsulated software environments (containers)." msgstr "`Docker `__ est un outil de virtualisation qui permet la distribution de logiciels en environnement confiné (*containers*)." #: ../../source/installation.rst:78 msgid "The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:" msgstr "Les pages suivantes contiennent plus d'informations à propos de l'image docker maintenue par la communauté, ``manimcommunity/manim`` :" #: ../../source/installation.rst:89 msgid "Interactive Jupyter notebooks for your browser" msgstr "Bloc-notes interactifs Jupyter sur votre navigateur" #: ../../source/installation.rst:91 msgid "Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks `__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook." msgstr "Le projet Manim contient une commande IPython ``%%manim`` prévue pour être utilisée dans des `blocs-notes Jupyter `__. Notre tutoriel interactif à l'adresse https://try.manim.community illustre la façon d'utiliser Manim dans un bloc-notes Jupyter." #: ../../source/installation.rst:96 msgid "The following pages explain how you can setup interactive environments like that yourself:" msgstr "Les pages suivantes expliquent comment mettre en place de tels environnements interactifs vous-même :" #: ../../source/installation.rst:105 msgid "Installation for developers" msgstr "Installation pour les développeurs" ================================================ FILE: docs/i18n/gettext/changelog/0.1.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.1.0-changelog.rst:3 msgid "v0.1.0" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:5 msgid "October 21, 2020" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:7 msgid "This is the first release of manimce after forking from 3b1b/manim. As such, developers have focused on cleaning up and refactoring the codebase while still maintaining backwards compatibility wherever possible." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:13 msgid "New Features" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:16 msgid "Command line" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:18 msgid "Output of 'manim --help' has been improved" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:19 msgid "Implement logging with the :code:`rich` library and a :code:`logger` object instead of plain ol' prints" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:20 msgid "Added a flag :code:`--dry_run`, which doesn't write any media" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:21 msgid "Allow for running manim with :code:`python3 -m manim`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:22 msgid "Refactored Tex Template management. You can now use custom templates with command line args using :code:`--tex_template`!" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:23 msgid "Re-add :code:`--save_frames` flag, which will save each frame as a png" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:24 msgid "Re-introduce manim feature that allows you to type manim code in :code:`stdin` if you pass a minus sign :code:`(-)` as filename" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:25 msgid "Added the :code:`--custom_folders` flag which yields a simpler output folder structure" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:26 msgid "Re-implement GIF export with the :code:`-i` flag (using this flag outputs ONLY a .gif file, and no .mp4 file)" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:27 msgid "Added a :code:`--verbose` flag" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:28 msgid "You can save the logs to a file by using :code:`--log_to_file`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:29 msgid "Read :code:`tex_template` from config file if not specified by :code:`--tex_template`." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:30 msgid "Add experimental javascript rendering with :code:`--use_js_renderer`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:31 msgid "Add :code:`-q/--quality [k|p|h|m|l]` flag and removed :code:`-m/-l` flags." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:32 msgid "Removed :code:`--sound` flag" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:36 msgid "Config system" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:38 msgid "Implement a :code:`manim.cfg` config file system, that consolidates the global configuration, the command line argument parsing, and some of the constants defined in :code:`constants.py`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:39 msgid "Added utilities for manipulating Manim’s :code:`.cfg` files." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:40 msgid "Added a subcommand structure for easier use of utilities managing :code:`.cfg` files" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:41 msgid "Also some variables have been moved from ``constants.py`` to the new config system:" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:43 msgid "``FRAME_HEIGHT`` to ``config[\"frame_width\"]``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:44 msgid "``TOP`` to ``config[\"frame_height\"] / 2 * UP``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:45 msgid "``BOTTOM`` to ``config[\"frame_height\"] / 2 * DOWN``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:46 msgid "``LEFT_SIDE`` to ``config[\"frame_width\"] / 2 * LEFT``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:47 msgid "``RIGHT_SIDE`` to ``config[\"frame_width\"] / 2 * RIGHT``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:48 msgid "``self.camera.frame_rate`` to ``config[\"frame_rate\"]``" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:54 msgid "Mobjects, Scenes, and Animations" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:56 msgid "Add customizable left and right bracket for :code:`Matrix` mobject and :code:`set_row_colors` method for matrix mobject" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:57 msgid "Add :code:`AddTeXLetterByLetter` animation" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:58 msgid "Enhanced GraphScene" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:60 msgid "You can now add arrow tips to axes" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:61 msgid "extend axes a bit at the start and/or end" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:62 msgid "have invisible axes" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:63 msgid "highlight the area between two curves" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:64 msgid "ThreeDScene now supports 3dillusion_camera_rotation" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:65 msgid "Add :code:`z_index` for manipulating depth of Objects on scene." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:66 msgid "Add a :code:`VDict` class: a :code:`VDict` is to a :code:`VGroup` what a :code:`dict` is to a :code:`list`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:67 msgid "Added Scene-caching feature. Now, if a partial movie file is unchanged in your code, it isn’t rendered again! [HIGHLY UNSTABLE We're working on it ;)]" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:68 msgid "Most :code:`get_` and :code:`set_` methods have been removed in favor of instance attributes and properties" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:69 msgid "The :code:`Container` class has been made into an AbstractBaseClass, i.e. in cannot be instantiated. Instead, use one of its children classes" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:70 msgid "The ``TextMobject`` and ``TexMobject`` objects have been deprecated, due to their confusing names, in favour of ``Tex`` and ``MathTex``. You can still, however, continue to use ``TextMobject`` and ``TexMobject``, albeit with Deprecation Warnings constantly reminding you to switch." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:71 msgid "Add a :code:`Variable` class for displaying text that continuously updates to reflect the value of a python variable." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:72 msgid "The ``Tex`` and ``MathTex`` objects allow you to specify a custom TexTemplate using the ``template`` keyword argument." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:73 msgid ":code:`VGroup` now supports printing the class names of contained mobjects and :code:`VDict` supports printing the internal dict of mobjects" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:74 msgid "Add all the standard easing functions" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:75 msgid ":code:`Scene` now renders when :code:`Scene.render()` is called rather than upon instantiation." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:76 msgid ":code:`ValueTracker` now supports increment using the `+=` operator (in addition to the already existing `increment_value` method)" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:77 msgid "Add :class:`PangoText` for rendering texts using Pango." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:81 msgid "Documentation" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:83 msgid "Added clearer installation instructions, tutorials, examples, and API reference [WIP]" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:87 msgid "Fixes" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:89 msgid "Initialization of directories has been moved to :code:`config.py`, and a bunch of bugs associated to file structure generation have been fixed" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:90 msgid "Nonfunctional file :code:`media_dir.txt` has been removed" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:91 msgid "Nonfunctional :code:`if` statements in :code:`scene_file_writer.py` have been removed" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:92 msgid "Fix a bug where trying to render the example scenes without specifying the scene would show all scene objects in the library" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:93 msgid "Many :code:`Exceptions` have been replaced for more specific exception subclasses" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:94 msgid "Fixed a couple of subtle bugs in :code:`ArcBetweenPoints`" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:98 msgid "Of interest to developers" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:100 msgid "Python code formatting is now enforced by using the :code:`black` tool" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:101 msgid "PRs now require two approving code reviews from community devs before they can be merged" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:102 msgid "Added tests to ensure stuff doesn't break between commits (For developers) [Uses Github CI, and Pytest]" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:103 msgid "Add contribution guidelines (for developers)" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:104 msgid "Added autogenerated documentation with sphinx and autodoc/autosummary [WIP]" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:105 msgid "Made manim internally use relative imports" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:106 msgid "Since the introduction of the :code:`TexTemplate` class, the files :code:`tex_template.tex` and :code:`ctex_template.tex` have been removed" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:107 msgid "Added logging tests tools." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:108 msgid "Added ability to save logs in json" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:109 msgid "Move to Poetry." msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:110 msgid "Colors have moved to an Enum" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:113 msgid "Other Changes" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:115 msgid "Cleanup 3b1b Specific Files" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:116 msgid "Rename package from manimlib to manim" msgstr "" #: ../../source/changelog/0.1.0-changelog.rst:117 msgid "Move all imports to :code:`__init__`, so :code:`from manim import *` replaces :code:`from manimlib.imports import *`" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.1.1-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.1.1-changelog.rst:3 msgid "v0.1.1" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:5 msgid "December 1, 2020" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:7 msgid "Changes since Manim Community release v0.1.0" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:10 msgid "Plugins" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:12 msgid "Provided a standardized method for plugin discoverability, creation, installation, and usage. See the :ref:`documentation `." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:16 msgid "Fixes" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:18 msgid "JsRender is optional to install. (via :pr:`697`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:19 msgid "Allow importing modules from the same directory as the input file when using ``manim`` from the command line (via :pr:`724`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:21 msgid "Remove some unnecessary or unpythonic methods from :class:`~.Scene` (``get_mobjects``, ``add_mobjects_among``, ``get_mobject_copies``), via :pr:`758`." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:24 msgid "Fix formatting of :class:`~.Code` (via :pr:`798`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:27 msgid "Configuration" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:29 msgid "Removed the ``skip_animations`` config option and added the ``Renderer.skip_animations`` attribute instead (via :pr:`696`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:31 msgid "The global ``config`` dict has been replaced by a global ``config`` instance of the new class :class:`~.ManimConfig`. This class has a dict-like API, so this should not break user code, only make it more robust. See the Configuration tutorial for details." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:35 msgid "Added the option to configure a directory for external assets (via :pr:`649`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:39 msgid "Documentation" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:41 msgid "Add ``:issue:`` and ``:pr:`` directives for simplifying linking to issues and pull requests on GitHub (via :pr:`685`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:43 msgid "Add a ``skip-manim`` tag for skipping the ``.. manim::`` directive when building the documentation locally (via :pr:`796`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:48 msgid "Mobjects, Scenes, and Animations" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:50 msgid "The ``alignment`` attribute to Tex and MathTex has been removed in favour of ``tex_environment``." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:51 msgid ":class:`~.Text` now uses Pango for rendering. ``PangoText`` has been removed. The old implementation is still available as a fallback as :class:`~.CairoText`." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:52 msgid "Variations of :class:`~.Dot` have been added as :class:`~.AnnotationDot` (a bigger dot with bolder stroke) and :class:`~.LabeledDot` (a dot containing a label)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:55 msgid "Scene.set_variables_as_attrs has been removed (via :pr:`692`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:56 msgid "Ensure that the axes for graphs (:class:`GraphScene`) always intersect (:pr:`580`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:57 msgid "Now Mobject.add_updater does not call the newly-added updater by default (use ``call_updater=True`` instead) (via :pr:`710`)" msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:59 msgid "VMobject now has methods to determine and change the direction of the points (via :pr:`647`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:60 msgid "Added BraceBetweenPoints (via :pr:`693`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:61 msgid "Added ArcPolygon and ArcPolygonFromArcs (via :pr:`707`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:62 msgid "Added Cutout (via :pr:`760`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:63 msgid "Added Mobject raise not implemented errors for dunder methods and implementations for VGroup dunder methods (via :pr:`790`)." msgstr "" #: ../../source/changelog/0.1.1-changelog.rst:64 msgid "Added :class:`~.ManimBanner` for a animated version of our logo and banner (via :pr:`729`)" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.10.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.10.0-changelog.rst:3 msgid "v0.10.0" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:5 msgid "September 01, 2021" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:10 msgid "A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:14 msgid "Animfysyk +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:15 #: ../../source/changelog/0.10.0-changelog.rst:48 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:16 msgid "Christian Clauss" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:17 msgid "Daniel Adelodun +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:18 msgid "Darigov Research" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:19 #: ../../source/changelog/0.10.0-changelog.rst:49 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:20 msgid "Eric Biedert +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:21 #: ../../source/changelog/0.10.0-changelog.rst:53 msgid "Harivinay" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:22 #: ../../source/changelog/0.10.0-changelog.rst:55 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:23 msgid "Jephian Lin +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:24 msgid "Joy Bhalla +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:25 #: ../../source/changelog/0.10.0-changelog.rst:60 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:26 msgid "Lalourche +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:27 msgid "Max Stoumen" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:28 #: ../../source/changelog/0.10.0-changelog.rst:61 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:29 #: ../../source/changelog/0.10.0-changelog.rst:62 msgid "Oliver" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:30 msgid "Partha Das +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:31 msgid "Raj Dandekar +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:32 msgid "Rohan Sharma +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:33 #: ../../source/changelog/0.10.0-changelog.rst:65 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:34 msgid "Václav Hlaváč +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:35 msgid "asjadaugust +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:36 #: ../../source/changelog/0.10.0-changelog.rst:66 msgid "ccn" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:37 #: ../../source/changelog/0.10.0-changelog.rst:67 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:38 #: ../../source/changelog/0.10.0-changelog.rst:69 msgid "sparshg" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:39 msgid "vinnniii15 +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:40 msgid "vladislav doster +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:41 msgid "xia0long +" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:44 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:47 msgid "Aathish Sivasubrahmanian" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:50 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:51 msgid "Eric Biedert" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:52 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:54 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:56 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:57 msgid "Jephian Lin" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:58 msgid "Joy Bhalla" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:59 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:63 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:64 msgid "Raj Dandekar" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:68 msgid "ralphieraccoon" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:72 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:74 msgid "A total of 59 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:77 msgid "Breaking changes" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:81 msgid ":pr:`1843`: Dropped redundant OpenGL files and add metaclass support for :class:`~.Surface`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:80 msgid "``OpenGL`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:81 msgid "``ParametricSurface`` has been renamed to :class:`~.Surface`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:84 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:86 msgid ":pr:`1941`: Added examples, tests and improved documentation for :mod:`~.coordinate_systems`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:89 msgid ":pr:`1694`: Added ``font_size`` parameter for :class:`~.Tex` and :class:`~.Text`, replaced ``scale`` parameters with ``font_size``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:92 msgid ":pr:`1860`: Removed :class:`~.GraphScene`, :class:`~.NumberLineOld` and parameters for :class:`~.ChangingDecimal`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:96 msgid "New features" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:99 msgid ":pr:`1929`: Implementing a ``zoom`` parameter for :meth:`.ThreeDScene.move_camera`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:99 msgid "Zooming into a :class:`~.ThreeDScene` can now be done by calling, for example, ``self.move_camera(zoom=2)`` in the ``construct`` method." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:101 msgid ":pr:`1980`: Added a ``dissipating_time`` keyword argument to :class:`~.TracedPath` to allow animating a dissipating path" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:105 msgid ":pr:`1899`: Allow switching the renderer to OpenGL at runtime" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:105 msgid "Previously, the metaclass approach only changed the inheritance chain to switch between OpenGL and cairo mobjects when the class objects are initialized, i.e., at import time. This PR also triggers the changes to the inheritance chain when the value of ``config.renderer`` is changed." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:107 msgid ":pr:`1828`: Added configuration option ``zero_pad`` for zero padding PNG file names" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:111 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:113 msgid ":pr:`1882`: Added OpenGL support for :class:`~.PMobject` and its subclasses" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:116 msgid ":pr:`1881`: Added methods :meth:`.Angle.get_lines` and :meth:`.Angle.get_value` to :class:`~.Angle`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:119 msgid ":pr:`1952`: Added the option to save last frame for OpenGL" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:122 msgid ":pr:`1922`: Fixed IPython interface to exit cleanly when OpenGL renderer raises an error" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:125 msgid ":pr:`1923`: Fixed CLI help text for ``manim init`` subcommand so that it is not truncated" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:129 msgid ":pr:`1868`: Added OpenGL support to IPython magic" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:129 msgid "The OpenGL renderer can now be used in jupyter notebooks when using the ``%%manim`` magic command." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:131 msgid ":pr:`1841`: Reduced default resolution of :class:`~.Dot3D`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:134 msgid ":pr:`1866`: Allow passing keyword argument ``corner_radius`` to :class:`~.SurroundingRectangle`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:137 msgid ":pr:`1847`: Allow :class:`~.Cross` to be created without requiring a mobject" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:141 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:143 msgid ":pr:`1985`: Use ``height`` to determine ``font_size`` instead of the ``_font_size`` attribute" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:146 msgid ":pr:`1758`: Fixed scene selection being ignored when using the OpenGL renderer" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:149 msgid ":pr:`1871`: Fixed broken :meth:`.VectorScene.vector_to_coords`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:152 msgid ":pr:`1973`: Fixed indexing of :meth:`.Table.get_entries` to respect row length" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:155 msgid ":pr:`1950`: Fixed passing custom arrow shapes to :class:`~.CurvedArrow`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:158 msgid ":pr:`1967`: Fixed :attr:`.Axes.coordinate_labels` referring to the entire axis, not just its labels" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:161 msgid ":pr:`1951`: Fixed :meth:`.Axes.get_line_graph` returning a graph rendered below the axes" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:164 msgid ":pr:`1943`: Added ``buff`` keyword argument to :class:`~.BraceLabel`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:167 msgid ":pr:`1938`: Fixed :class:`~.Rotate` for angles that are multiples of :math:`2\\pi`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:170 msgid ":pr:`1924`: Made arrow tips rotate ``IN`` and ``OUT`` properly" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:173 msgid ":pr:`1931`: Fixed ``row_heights`` in :meth:`.Mobject.arrange_in_grid`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:176 msgid ":pr:`1893`: Fixed CLI error when rendering a file containing a single scene without specifying the scene name" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:179 msgid ":pr:`1744`: Fixed bug in :class:`~.NumberPlane` with strictly positive or strictly negative values for ``x_range`` and ``y_range``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:182 msgid ":pr:`1887`: Fixed ``custom_config`` not working in ``frames_comparison``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:185 msgid ":pr:`1879`: Fixed how the installed version is determined by Poetry" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:189 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:191 msgid ":pr:`1979`: Corrected Japanese phrases in documentation" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:194 msgid ":pr:`1976`: Fixed labelling of languages in documentation example" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:197 msgid ":pr:`1949`: Rewrite installation instructions from scratch" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:200 msgid ":pr:`1963`: Added sitemap to ``robots.txt``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:203 msgid ":pr:`1939`: Fixed formatting of parameter description of :class:`~.NumberPlane`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:206 msgid ":pr:`1918`: Fixed a typo in the text tutorial" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:209 msgid ":pr:`1915`: Improved the wording of the installation instructions for Google Colab" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:212 msgid ":pr:`1906`: Improved language and overall consistency in ``README``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:215 msgid ":pr:`1880`: Updated tutorials to use ``.animate`` instead of :class:`~.ApplyMethod`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:218 msgid ":pr:`1877`: Remove duplicated imports in some documentation examples" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:221 msgid ":pr:`1869`: Fixed duplicated Parameters section in :meth:`.Mobject.arrange_in_grid`" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:225 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:227 msgid ":pr:`1894`: Fixed an OpenGL test" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:231 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:233 msgid ":pr:`1987`: Added support for using OpenGL in subprocess in Windows pipeline" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:236 msgid ":pr:`1964`: Added ``CITATION.cff`` and a method to automatically update this citation with new releases" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:239 msgid ":pr:`1856`: Modified Dockerfile to support multi-platform builds via ``docker buildx``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:242 msgid ":pr:`1955`: Partially support OpenGL rendering with Docker" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:245 msgid ":pr:`1896`: Made RTD apt install FFMPEG instead of installing a Python binding" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:248 msgid ":pr:`1864`: Shortened and simplified PR template" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:251 msgid ":pr:`1853`: Updated Sphinx to 4.1.2" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:255 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:257 msgid ":pr:`1960`: Ignore fewer flake8 errors" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:260 msgid ":pr:`1947`: Set flake8 not to ignore undefined names in Python code" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:263 msgid ":pr:`1948`: flake8: Set max-line-length instead of ignoring long lines" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:268 msgid ":pr:`1956`: Upgrade to modern Python syntax" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:267 msgid "This pull request was created `with the command `__ ``pyupgrade --py36-plus **/*.py``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:268 msgid "Python f-strings simplify the code and `should speed up execution `__." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:271 msgid ":pr:`1898`: Replaced ``self.data[\"attr\"]`` and ``self.uniforms[\"attr\"]`` with ``self.attr``" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:271 msgid "In particular, ``OpenGLVMobject.points`` can now be accessed directly." msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:273 msgid ":pr:`1934`: Improved code quality by implementing suggestions from LGTM" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:276 msgid ":pr:`1861`: Updated ``dearpygui`` version to 0.8.x" msgstr "" #: ../../source/changelog/0.10.0-changelog.rst:280 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.11.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.11.0-changelog.rst:3 msgid "v0.11.0" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:5 msgid "October 02, 2021" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:10 msgid "A total of 31 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:14 #: ../../source/changelog/0.11.0-changelog.rst:40 msgid "Aathish Sivasubrahmanian" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:15 #: ../../source/changelog/0.11.0-changelog.rst:41 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:16 msgid "Charlie +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:17 msgid "Christopher Besch +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:18 #: ../../source/changelog/0.11.0-changelog.rst:43 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:19 msgid "Evan Boehs +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:20 #: ../../source/changelog/0.11.0-changelog.rst:45 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:21 #: ../../source/changelog/0.11.0-changelog.rst:46 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:22 msgid "Jerónimo Squartini" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:23 #: ../../source/changelog/0.11.0-changelog.rst:49 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:24 msgid "Meredith Espinosa +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:25 #: ../../source/changelog/0.11.0-changelog.rst:51 msgid "Mysaa" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:26 #: ../../source/changelog/0.11.0-changelog.rst:52 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:27 msgid "Nicolai Weitkemper +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:28 #: ../../source/changelog/0.11.0-changelog.rst:54 msgid "Oliver" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:29 #: ../../source/changelog/0.11.0-changelog.rst:56 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:30 msgid "Tim +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:31 #: ../../source/changelog/0.11.0-changelog.rst:59 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:32 msgid "imadjamil +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:33 msgid "leleogere +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:34 msgid "Максим Заякин +" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:37 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:42 msgid "Charlie" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:44 msgid "Evan Boehs" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:47 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:48 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:50 msgid "Mark Miller" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:53 msgid "Nicolai Weitkemper" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:55 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:57 msgid "Skaft" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:58 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:60 msgid "leleogere" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:63 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:65 msgid "A total of 55 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:68 msgid "Breaking changes" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:71 msgid ":pr:`1990`: Changed and improved the implementation of :meth:`.CoordinateSystem.get_area` to work without Riemann rectangles" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:71 msgid "This changes how :meth:`.CoordinateSystem.get_area` is implemented. To mimic the old behavior (tiny Riemann rectangles), use :meth:`.CoordinateSystem.get_riemann_rectangles` with a small value for ``dx``." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:74 msgid ":pr:`2095`: Changed angles for polar coordinates to use math convention" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:74 msgid "This PR switches the parameter names ``phi`` and ``theta`` in :func:`cartesian_to_spherical` and :func:`spherical_to_cartesian` to align with the `usual definition in mathematics `__." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:77 msgid "Highlights" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:80 msgid ":pr:`2094`: Implemented :class:`~.ImplicitFunction` and :meth:`.CoordinateSystem.get_implicit_curve` for plotting implicit curves" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:80 msgid "An :class:`~.ImplicitFunction` that plots the points :math:`(x, y)` which satisfy some equation :math:`f(x,y) = 0`." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:82 msgid ":pr:`2075`: Implemented :meth:`.Mobject.set_default`, a mechanism for changing default values of keyword arguments" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:87 msgid ":pr:`1998`: Added support for Boolean Operations on VMobjects" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:86 msgid "This PR introduces boolean operations for :class:`~.VMobject`; see details and examples at :class:`~.Union`, :class:`~.Difference`, :class:`~.Intersection` and :class:`~.Exclusion`." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:90 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:92 msgid ":pr:`2123`: Renamed ``distance`` parameter of :class:`.ThreeDScene` and :class:`.ThreeDCamera` to ``focal_distance``" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:95 msgid ":pr:`2102`: Deprecated :class:`~.SampleSpaceScene` and :class:`~.ReconfigurableScene`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:98 msgid ":pr:`2061`: Removed deprecated ``u_min``, ``u_max``, ``v_min``, ``v_max`` in :class:`~.Surface`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:101 msgid ":pr:`2024`: Deprecated redundant methods :meth:`.Mobject.rotate_in_place`, :meth:`.Mobject.scale_in_place`, :meth:`.Mobject.scale_about_point`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:104 msgid ":pr:`1991`: Deprecated :meth:`.VMobject.get_points`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:108 msgid "New features" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:110 msgid ":pr:`2118`: Added 3D support for :class:`~.ArrowVectorField` and :class:`~.StreamLines`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:113 msgid ":pr:`1469`: Added :meth:`.VMobject.proportion_from_point` to measure the proportion of points along a Bezier curve" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:117 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:119 msgid ":pr:`2111`: Improved setting of OpenGL colors" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:122 msgid ":pr:`2113`: Added OpenGL compatibility to :meth:`.ThreeDScene.begin_ambient_camera_rotation` and :meth:`.ThreeDScene.move_camera`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:125 msgid ":pr:`2016`: Added OpenGL support for :mod:`~.mobject.boolean_ops`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:128 msgid ":pr:`2084`: Added :meth:`~Table.get_highlighted_cell` and fixed :meth:`~Table.add_highlighted_cell`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:131 msgid ":pr:`2013`: Removed unnecessary check in :class:`~.TransformMatchingAbstractBase`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:134 msgid ":pr:`1971`: Added OpenGL support for :class:`~.StreamLines`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:137 msgid ":pr:`2041`: Added config option to enable OpenGL wireframe for debugging" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:141 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:143 msgid ":pr:`2070`: Fixed :meth:`~OpenGLRenderer.get_frame` when window is created" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:146 msgid ":pr:`2071`: Fixed :class:`~AnimationGroup` OpenGL compatibility" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:149 msgid ":pr:`2108`: Fixed swapped axis step values in :class:`~.NumberPlane`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:152 msgid ":pr:`2072`: Added OpenGL compatibility for :class:`~.Cube`." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:155 msgid ":pr:`2060`: Fixed OpenGL compatibility issue for meth:`~Line.set_opacity`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:158 msgid ":pr:`2037`: Fixed return value of :meth:`~.OpenGLMobject.apply_complex_function`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:161 msgid ":pr:`2039`: Added OpenGL compatibility for :meth:`~Cylinder.add_bases`." msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:164 msgid ":pr:`2066`: Fixed error raised by logging when cache is full" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:167 msgid ":pr:`2026`: Fixed OpenGL shift animation for :class:`~.Text`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:170 msgid ":pr:`2028`: Fixed OpenGL overriding SVG fill color" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:173 msgid ":pr:`2043`: Fixed bug where :meth:`.NumberLine.add_labels` cannot accept non-mobject labels" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:176 msgid ":pr:`2011`: Fixed ``-a`` flag for OpenGL rendering" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:179 msgid ":pr:`1994`: Fix :meth:`~.input_to_graph_point` when passing a line graph (from :meth:`.Axes.get_line_graph`)" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:182 msgid ":pr:`2017`: Avoided using deprecated ``get_points`` method and fixed :class:`~.OpenGLPMPoint` color" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:186 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:188 msgid ":pr:`2131`: Copyedited the configuration tutorial in the documentation" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:191 msgid ":pr:`2120`: Changed ``manim_directive`` to use a clean configuration via ``tempconfig``" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:194 msgid ":pr:`2122`: Fixed broken links in inheritance graphs by moving them to ``reference.rst``" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:197 msgid ":pr:`2115`: Improved docstring of :meth:`.PMobject.add_points`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:200 msgid ":pr:`2116`: Made type hint for ``line_spacing`` argument of :class:`~.Paragraph` more accurate" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:203 msgid ":pr:`2117`: Changed the way the background color was set in a documentation example to avoid leaking the setting to other examples" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:206 msgid ":pr:`2101`: Added note that translation process is not ready" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:209 msgid ":pr:`2055`: Fixed parameter types of :meth:`.Graph.add_edges` and :meth:`.Graph.add_vertices`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:212 msgid ":pr:`862`: Prepared documentation for translation (still work in progress)" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:215 msgid ":pr:`2035`: Fixed broken link in README" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:218 msgid ":pr:`2020`: Corrected paths to user-wide configuration files for MacOS and Linux" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:222 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:224 msgid ":pr:`2008`: Reuse CLI flag tests for OpenGL" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:227 msgid ":pr:`2080`: Reused :class:`~.Mobject` tests for :class:`~.OpenGLMobject`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:231 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:233 msgid ":pr:`2004`: Cancel previous workflows in the same branch in Github Actions" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:237 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:239 msgid ":pr:`2050`: Make colour aliases IDE-friendly" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:242 msgid ":pr:`2126`: Fixed whitespace in info message issued by :meth:`.SceneFileWriter.clean_cache`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:245 msgid ":pr:`2124`: Upgraded several dependencies (in particular: ``skia-pathops``)" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:248 msgid ":pr:`2001`: Fixed several warnings issued by LGTM" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:251 msgid ":pr:`2064`: Removed duplicate insert shader directory" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:254 msgid ":pr:`2027`: Improved wording in info message issued by :meth:`.SceneFileWriter.clean_cache`" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:257 msgid ":pr:`1968`: Sharpened Flake8 configuration and fixed resulting warnings" msgstr "" #: ../../source/changelog/0.11.0-changelog.rst:261 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.12.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.12.0-changelog.rst:3 msgid "v0.12.0" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:5 msgid "November 02, 2021" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:10 msgid "A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:14 msgid "Anima. +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:15 msgid "Arcstur +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:16 #: ../../source/changelog/0.12.0-changelog.rst:47 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:17 #: ../../source/changelog/0.12.0-changelog.rst:48 msgid "Christopher Besch" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:18 #: ../../source/changelog/0.12.0-changelog.rst:49 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:19 msgid "David Yang +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:20 msgid "Dhananjay Goratela +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:21 msgid "Ethan Rooke +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:22 msgid "Eugene Chung +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:23 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:24 msgid "Gustav-Rixon +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:25 #: ../../source/changelog/0.12.0-changelog.rst:56 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:26 msgid "Josiah Winslow +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:27 #: ../../source/changelog/0.12.0-changelog.rst:58 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:28 msgid "Martmists +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:29 msgid "Michael Hill +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:30 #: ../../source/changelog/0.12.0-changelog.rst:60 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:31 msgid "Nick +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:32 msgid "NotWearingPants +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:33 msgid "Peeter Joot +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:34 #: ../../source/changelog/0.12.0-changelog.rst:63 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:35 msgid "Viicos +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:36 msgid "heitor +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:37 #: ../../source/changelog/0.12.0-changelog.rst:65 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:38 msgid "kieran-pringle +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:39 msgid "Виктор Виктор +" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:42 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:45 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:46 msgid "Anima." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:50 msgid "David Yang" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:51 msgid "Dhananjay Goratela" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:52 msgid "Ethan Rooke" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:53 msgid "Eugene Chung" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:54 msgid "Gustav-Rixon" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:55 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:57 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:59 msgid "Mysaa" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:61 msgid "Nick" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:62 msgid "Oliver" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:64 msgid "Viicos" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:66 msgid "kieran-pringle" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:69 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:71 msgid "A total of 52 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:74 msgid "Highlights" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:79 msgid ":pr:`1812`: Implemented logarithmic scaling for :class:`~.NumberLine` / :class:`~.Axes`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:77 msgid "This implements scaling bases that can be passed to the ``scaling`` keyword argument of :class:`.NumberLine`. See :class:`.LogBase` (for a logarithmic scale) and :class:`.LinearBase` (for the default scale) for more details and examples." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:85 msgid ":pr:`2152`: Introduced API for scene sections via :meth:`.Scene.next_section`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:82 msgid "Sections divide a scene into multiple parts, resulting in multiple output videos (when using the ``--save_sections`` flag). The cuts between two sections are defined by the user in the :meth:`~.Scene.construct` method. Each section has an optional name and type, which can be used by a plugin (`see an example `__). You can skip rendering specific sections with the ``skip_animations`` keyword argument." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:88 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:90 msgid ":pr:`1926`: OpenGL: changed ``submobjects`` to be a property" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:93 msgid ":pr:`2245`: Removed deprecated method ``get_center_point`` and parameters ``azimuth_label_scale``, ``number_scale_value``, ``label_scale``, ``scale_factor``, ``size``, ``x_min``, ``x_max``, ``delta_x``, ``y_min``, ``y_max``, ``delta_y``" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:96 msgid ":pr:`2187`: Renamed ``get_graph`` and its variants to :meth:`~.CoordinateSystem.plot`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:99 msgid ":pr:`2065`: Deprecated :class:`~.FullScreenFadeRectangle` and :class:`~.PictureInPictureFrame`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:103 msgid "New features" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:105 msgid ":pr:`2025`: Implemented :meth:`.CoordinateSystem.input_to_graph_coords` and fixed :meth:`.CoordinateSystem.angle_of_tangent`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:108 msgid ":pr:`2151`: Added option to set the input file from a config file" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:111 msgid ":pr:`2128`: Added keyword arguments ``match_center``, ``match_width`` etc. to :meth:`.Mobject.become`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:114 msgid ":pr:`2162`: Implemented :meth:`.MovingCamera.auto_zoom` for automatically zooming onto specified mobjects" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:117 msgid ":pr:`2236`: Added ``skip_animations`` argument to :meth:`.Scene.next_section`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:120 msgid ":pr:`2196`: Implemented :meth:`.Line3D.parallel_to` and :meth:`.Line3D.perpendicular_to`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:124 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:128 msgid ":pr:`2138`: Fixed example for :meth:`~.Vector.coordinate_label` and added more customization for :class:`~.Matrix`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:127 msgid "Additional keyword arguments for :meth:`~.Vector.coordinate_label` are passed to the constructed matrix." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:128 msgid ":class:`~.Matrix` now accepts a ``bracket_config`` keyword argument." msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:130 msgid ":pr:`2139`: Changed the color of :class:`~.NumberLine` from ``LIGHT_GREY`` to ``WHITE``" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:133 msgid ":pr:`2157`: Added :meth:`.CoordinateSystem.plot_polar_graph`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:136 msgid ":pr:`2243`: Fixed wasteful recursion in :meth:`.Mobject.get_merged_array`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:139 msgid ":pr:`2205`: Improved last frame output handling for the OpenGL renderer" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:142 msgid ":pr:`2172`: Added ``should_render`` attribute to disable rendering mobjects" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:145 msgid ":pr:`2182`: Changed the default width of videos in Jupyter notebooks to 60%" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:149 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:151 msgid ":pr:`2244`: Fixed :meth:`.CoordinateSystem.get_area` when using few plot points and a boundary graph" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:154 msgid ":pr:`2232`: Fixed :class:`.Graph` stopping to update after animating additions/deletions of vertices or edges" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:157 msgid ":pr:`2142`: Fixed issue with duplicates in OpenGL family and added tests" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:160 msgid ":pr:`2168`: Fixed order of return values of :func:`.space_ops.cartesian_to_spherical`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:163 msgid ":pr:`2160`: Made projection shaders compatible with :class:`.StreamLines`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:166 msgid ":pr:`2140`: Fixed passing color lists to :meth:`.Mobject.set_color` for the OpenGL renderer" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:169 msgid ":pr:`2211`: Fixed animations not respecting the specified rate function" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:172 msgid ":pr:`2161`: Fixed ``IndexOutOfBoundsError`` in TeX logging" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:175 msgid ":pr:`2148`: Fixed :class:`~.Arrow` tip disorientation with :meth:`.Line.put_start_and_end_on`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:178 msgid ":pr:`2192`: Fixed :func:`.svg_path.string_to_numbers` sometimes returning strings" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:181 msgid ":pr:`2185`: Fixed type mismatch for height and width parameters of :class:`~.Text`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:185 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:187 msgid ":pr:`2228`: Added a new boolean operation example to the gallery" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:190 msgid ":pr:`2239`: Removed erroneous raw string from text tutorial" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:193 msgid ":pr:`2184`: Moved comments in :class:`~.VMobject` to documentation" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:196 msgid ":pr:`2217`: Removed superfluous dots in documentation of :class:`.Section`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:199 msgid ":pr:`2215`: Fixed typo in docstring of :meth:`.ThreeDAxes.get_z_axis_label`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:202 msgid ":pr:`2212`: Fixed Documentation for Sections" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:205 msgid ":pr:`2201`: Fixed a typo in the documentation" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:208 msgid ":pr:`2165`: Added Crowdin configuration and changed source files to ``.pot`` format" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:211 msgid ":pr:`2130`: Transferred troubleshooting installation related snippets from Discord to the documentation" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:214 msgid ":pr:`2176`: Modified :meth:`.Mobject.set_default` example to prevent leaking across the docs" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:218 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:220 msgid ":pr:`2197`: Added tests for resolution flag" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:223 msgid ":pr:`2146`: Increased test coverage for OpenGL renderer" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:227 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:229 msgid ":pr:`2191`: Removed ``add-trailing-comma`` pre-commit hook" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:233 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:235 msgid ":pr:`2136`: Added type hints to all colors" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:238 msgid ":pr:`2220`: Cleanup: let ``Scene.renderer.time`` return something that makes sense" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:241 msgid ":pr:`2222`: Updated Classifiers in ``pyproject.toml``: removed Python 3.6, added Python 3.9" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:244 msgid ":pr:`2213`: Removed redundant ``partial_movie_files`` parameter in :meth:`.SceneFileWriter.combine_to_movie`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:251 msgid ":pr:`2200`: Addressed some maintenance TODOs" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:248 msgid "Changed an `Exception` to `ValueError`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:249 msgid "Fixed :meth:`.MappingCamera.points_to_pixel_coords` by adding the ``mobject`` argument of the parent" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:250 msgid "Rounded up width in :class:`.SplitScreenCamera`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:251 msgid "Added docstring to :meth:`.Camera.capture_mobject`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:253 msgid ":pr:`2194`: Added type hints to :mod:`.utils.images`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:256 msgid ":pr:`2171`: Added type hints to :mod:`.utils.ipython_magic`" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:259 msgid ":pr:`2164`: Improved readability of regular expression" msgstr "" #: ../../source/changelog/0.12.0-changelog.rst:263 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.13.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.13.0-changelog.rst:3 msgid "v0.13.0" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:5 msgid "December 04, 2021" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:10 msgid "A total of 27 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:14 #: ../../source/changelog/0.13.0-changelog.rst:38 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:15 #: ../../source/changelog/0.13.0-changelog.rst:39 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:16 #: ../../source/changelog/0.13.0-changelog.rst:40 msgid "Christopher Besch" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:17 #: ../../source/changelog/0.13.0-changelog.rst:41 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:18 msgid "Filip +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:19 msgid "John Ingles +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:20 #: ../../source/changelog/0.13.0-changelog.rst:45 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:21 msgid "Lucas Ricci +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:22 msgid "Marcin Serwin +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:23 msgid "Mysaa" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:24 #: ../../source/changelog/0.13.0-changelog.rst:47 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:25 msgid "Ricky +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:26 #: ../../source/changelog/0.13.0-changelog.rst:50 msgid "Viicos" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:27 msgid "ask09ok +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:28 msgid "citrusmunch +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:29 #: ../../source/changelog/0.13.0-changelog.rst:52 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:30 msgid "mostlyaman +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:31 msgid "vmiezys +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:32 msgid "zhujisheng +" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:35 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:42 msgid "Filip" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:43 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:44 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:46 msgid "Lucas Ricci" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:48 msgid "Oliver" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:49 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:51 msgid "ask09ok" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:53 msgid "mostlyaman" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:56 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:58 msgid "A total of 39 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:61 msgid "Highlights" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:63 msgid ":pr:`2313`: Finalized translation process and documentation" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:67 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:75 msgid ":pr:`2331`: Removed deprecations up to ``v0.12.0``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:70 msgid "Removed ``distance`` parameters from :class:`~.ThreeDCamera` (replacement: ``focal_distance``)" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:71 msgid "Removed ``min_distance_to_new_point`` parameter from :class:`~.TracedPath`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:72 msgid "Removed ``positive_space_ratio`` and ``dash_spacing`` parameters from :class:`~.DashedVMobject`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:73 msgid "Removed ``_in_place`` methods from :mod:`.mobject`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:74 msgid "Removed ``ReconfigurableScene``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:75 msgid "Removed ``SampleSpaceScene``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:77 msgid ":pr:`2312`: Replaced all occurrences of ``set_submobjects``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:81 msgid "New features" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:85 msgid ":pr:`2314`: Added basic support for adding subcaptions via :meth:`.Scene.add_subcaption`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:84 msgid "New method :meth:`.Scene.add_subcaption`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:85 msgid "New keyword arguments ``subcaption``, ``subcaption_duration``, ``subcaption_offset`` for :meth:`.Scene.play`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:87 msgid ":pr:`2267`: Implemented :meth:`.CoordinateSystem.plot_antiderivative_graph`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:91 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:93 msgid ":pr:`2347`: Moved ``manim_directive.py`` to ``manim.utils.docbuild``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:96 msgid ":pr:`2340`: Added documentation for :mod:`.animation.growing` and improved :class:`.SpinInFromNothing`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:99 msgid ":pr:`2343`: Replaced current tree layout algorithm with SageMath's for improved layout of large trees" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:102 msgid ":pr:`2351`: Added missing ``**kwargs`` parameter to :meth:`.Table.add_highlighted_cell`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:105 msgid ":pr:`2344`: Resized SVG logos, fit content to canvas" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:109 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:111 msgid ":pr:`2359`: Resolved ``ValueError`` when calling ``manim cfg write``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:114 msgid ":pr:`2276`: Fixed bug with alignment of z-axis in :class:`~.ThreeDAxes`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:117 msgid ":pr:`2325`: Several improvements to handling of ``quality`` argument" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:120 msgid ":pr:`2335`: Fixed bug with zooming camera and :class:`~.PointCloud`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:123 msgid ":pr:`2328`: Fixed bug causing incorrect RGBA values to be passed to cairo" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:126 msgid ":pr:`2292`: Fixed positioning of :class:`~.Flash`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:129 msgid ":pr:`2262`: Fixed wrong cell coordinates with :meth:`.Table.get_cell` after scaling" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:132 msgid ":pr:`2280`: Fixed :class:`~.DecimalNumber` color when number of displayed digits changes" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:136 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:138 msgid ":pr:`2354`: Port over docs and typings from ``mobject.py`` and ``vectorized_mobject.py`` to their OpenGL counterparts" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:141 msgid ":pr:`2350`: Added mention of Manim sideview extension for VS Code" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:144 msgid ":pr:`2342`: Removed :meth:`~.CoordinateSystem.get_graph` usage from :class:`~.Axes` example" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:147 msgid ":pr:`2216`: Edited and added new sections to the quickstart tutorial" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:150 msgid ":pr:`2279`: Added documentation for discontinuous functions" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:153 msgid ":pr:`2319`: Swapped ``dotL`` and ``dotR`` in :meth:`.Mobject.interpolate` example" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:156 msgid ":pr:`2230`: Copyedited building blocks tutorial" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:159 msgid ":pr:`2310`: Clarified that Manim does not support Python 3.10 yet in the documentation" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:162 msgid ":pr:`2294`: Made documentation front page more concise and rearranged order of tutorials" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:165 msgid ":pr:`2287`: Replace link to old interactive notebook" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:169 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:171 msgid ":pr:`2346`: Made ``frames_comparsion`` decorator for frame testing a proper module of the library" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:174 msgid ":pr:`2318`: Added tests for ``remover`` keyword argument of :class:`~.AnimationGroup`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:177 msgid ":pr:`2301`: Added a test for :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:180 msgid ":pr:`2274`: Optimized some tests to reduce duration" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:183 msgid ":pr:`2272`: Added test for :class:`~.Broadcast`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:187 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:189 msgid ":pr:`2327`: Corrected type hint for ``labels`` keyword argument of :class:`~.Graph`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:192 msgid ":pr:`2329`: Remove unintended line break in README" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:195 msgid ":pr:`2305`: Corrected type hint ``discontinuities`` argument for :class:`~.ParametricFunction`" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:198 msgid ":pr:`2300`: Add contact email for PyPi" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:202 msgid "New releases" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:204 msgid ":pr:`2353`: Prepare new release: ``v0.13.0``" msgstr "" #: ../../source/changelog/0.13.0-changelog.rst:208 msgid "Unclassified changes" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.13.1-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.13.1-changelog.rst:3 msgid "v0.13.1" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:5 msgid "December 05, 2021" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:10 msgid "A total of 2 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:14 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:17 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:20 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:23 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:25 msgid "A total of 2 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:28 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:30 msgid ":pr:`2363`: Fixed broken IPython magic command" msgstr "" #: ../../source/changelog/0.13.1-changelog.rst:34 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.14.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.14.0-changelog.rst:3 msgid "v0.14.0" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:5 msgid "January 07, 2022" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:10 msgid "A total of 29 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:14 #: ../../source/changelog/0.14.0-changelog.rst:38 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:15 msgid "BorisTheBrave +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:16 #: ../../source/changelog/0.14.0-changelog.rst:41 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:17 #: ../../source/changelog/0.14.0-changelog.rst:42 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:18 msgid "Gergely Bencsik +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:19 #: ../../source/changelog/0.14.0-changelog.rst:45 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:20 msgid "Jihoon +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:21 msgid "Kian Kasad +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:22 msgid "Kiran-Raj-Dev +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:23 #: ../../source/changelog/0.14.0-changelog.rst:47 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:24 msgid "Leo Xu +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:25 #: ../../source/changelog/0.14.0-changelog.rst:50 msgid "Marcin Serwin" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:26 msgid "Matt Gleich +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:27 #: ../../source/changelog/0.14.0-changelog.rst:51 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:28 msgid "Steven nguyen +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:29 msgid "Vectozavr +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:30 #: ../../source/changelog/0.14.0-changelog.rst:54 msgid "Viicos" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:31 msgid "citrusmunch" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:32 msgid "netwizard22 +" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:35 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:39 msgid "BorisTheBrave" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:40 msgid "Christopher Besch" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:43 msgid "Gergely Bencsik" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:44 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:46 msgid "Kiran-Raj-Dev" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:48 msgid "Leo Xu" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:49 msgid "Lucas Ricci" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:52 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:53 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:55 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:58 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:60 msgid "A total of 29 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:63 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:69 msgid ":pr:`2390`: Removed deprecations up to `v0.13.0`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:66 msgid "Removed ``get_graph``, ``get_implicit_curve``, ``get_derivative_graph``, ``get_line_graph`` and ``get_parametric_curve`` in favour of their ``plot`` variants" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:67 msgid "Removed ``FullScreenFadeRectangle`` and ``PictureInPictureFrame``" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:68 msgid "Removed ``path_arc`` parameter from :class:`~.SpinInFromNothing`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:69 msgid "Removed ``set_submobjects`` method from ``opengl_mobject.py``" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:72 msgid "New features" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:75 msgid ":pr:`2341`: Update :class:`~.Text` to use new ``ManimPango`` color setting" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:75 msgid ":class:`~.Text` class now uses color setting introduced in ``ManimPango 0.4.0`` for color and gradient." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:78 msgid ":pr:`2397`: Added ``label_constructor`` parameter for :class:`~.NumberLine`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:78 msgid "Allows changing the class that will be used to construct :class:`~.Axes` and :class:`~.NumberLine` labels by default. Makes it possible to easily use :class:`~.Text` for labels if needed." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:81 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:83 msgid ":pr:`2383`: Made :meth:`.Surface.set_fill_by_value` support gradients along different axes" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:86 msgid ":pr:`2388`: Added ``about_point`` keyword argument to :class:`~.ApplyMatrix`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:89 msgid ":pr:`2395`: Add documentation for paths functions" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:94 msgid ":pr:`2372`: Improved :class:`~.DashedVMobject`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:93 msgid ":class:`~.DashedVMobject` used to create stretched and uneven dashes on most plotted curves. Now the dash lengths are equalized. An option is reserved to use the old method. New keyword argument: ``dash_offset``. This parameter shifts the starting point." msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:97 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:99 msgid ":pr:`2409`: Fixed performance degradation by trimming empty curves from paths when calling :meth:`.VMobject.align_points`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:102 msgid ":pr:`2392`: Fixed ``ZeroDivisionError`` in :mod:`~.mobject.three_dimensions`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:105 msgid ":pr:`2362`: Fixed phi updater in :meth:`.ThreeDScene.begin_3dillusion_camera_rotation`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:109 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:111 msgid ":pr:`2415`: Removed instructions on using and installing Docker in README" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:114 msgid ":pr:`2414`: Made improvements to the :doc:`/guides/configuration` tutorial" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:117 msgid ":pr:`2423`: Changed recommendation to ``mactex-no-gui`` from ``mactex`` for macOS install" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:120 msgid ":pr:`2407`: Clarified docstrings of :meth:`.Mobject.animate`, :meth:`.Mobject.set` and :class:`~.Variable`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:123 msgid ":pr:`2352`: Added Crowdin badge" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:126 msgid ":pr:`2371`: Added ``dvips`` to list of required LaTeX packages on Linux" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:129 msgid ":pr:`2403`: Improved docstring of :class:`~.ApplyMethod` and removed propagated ``__init__`` docstring" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:132 msgid ":pr:`2391`: Fixed typo in parameter name in documentation of :class:`~.NumberLine`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:135 msgid ":pr:`2368`: Added note in Internationalization" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:139 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:141 msgid ":pr:`2408`: Removed various return annotations that were stifling type inference" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:144 msgid ":pr:`2424`: Removed ``strings.py``" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:147 msgid ":pr:`1972`: Added support for MyPy" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:150 msgid ":pr:`2410`: Fixed Flake8" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:153 msgid ":pr:`2401`: Fixed type annotations in :mod:`.mobject.three_dimensions`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:156 msgid ":pr:`2405`: Removed some unused OpenGL files" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:159 msgid ":pr:`2399`: Fixed type annotations in :mod:`~.mobject.table`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:162 msgid ":pr:`2385`: Made comments in quickstart tutorial more precise" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:165 msgid ":pr:`2377`: Fixed type hint for an argument of :class:`~.MoveAlongPath`" msgstr "" #: ../../source/changelog/0.14.0-changelog.rst:169 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.15.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.15.0-changelog.rst:3 msgid "v0.15.0" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:5 msgid "February 26, 2022" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:10 msgid "A total of 34 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:14 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:15 msgid "AnonymoZ +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:16 #: ../../source/changelog/0.15.0-changelog.rst:44 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:17 #: ../../source/changelog/0.15.0-changelog.rst:46 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:18 msgid "Eshaan Naga Venkata +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:19 msgid "Faruk D. +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:20 #: ../../source/changelog/0.15.0-changelog.rst:48 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:21 msgid "Kevin Cen +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:22 #: ../../source/changelog/0.15.0-changelog.rst:50 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:23 msgid "Leo Xu" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:24 msgid "Lucas Ricci" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:25 #: ../../source/changelog/0.15.0-changelog.rst:52 msgid "Marcin Serwin" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:26 msgid "Michael McNeil Forbes +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:27 msgid "Mysaa" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:28 #: ../../source/changelog/0.15.0-changelog.rst:53 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:29 msgid "Pierre Couy +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:30 msgid "Simon Ellmann +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:31 msgid "Tommy Chu +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:32 msgid "Viicos" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:33 #: ../../source/changelog/0.15.0-changelog.rst:58 msgid "ad_chaos" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:34 msgid "betafcc +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:35 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:36 #: ../../source/changelog/0.15.0-changelog.rst:60 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:37 msgid "vmoros +" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:38 msgid "鹤翔万里" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:41 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:45 msgid "Christopher Besch" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:47 msgid "Eshaan Naga Venkata" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:49 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:51 msgid "Marcin Kurczewski" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:54 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:55 msgid "RomainJMend" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:56 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:57 msgid "Tommy Chu" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:59 msgid "betafcc" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:63 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:65 msgid "A total of 71 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:68 msgid "Breaking changes" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:71 msgid ":pr:`2476`: Improved structure of the :mod:`.mobject` module" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:71 msgid "Arrow tips now have to be imported from ``manim.mobject.geometry.tips`` instead of ``manim.mobject.geometry``." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:75 msgid ":pr:`2387`: Refactored :class:`~.BarChart` and made it inherit from :class:`~.Axes`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:74 msgid ":class:`~.BarChart` now inherits from :class:`~.Axes`, allowing it to use :class:`~.Axes`' methods. Also improves :class:`~.BarChart`'s configuration and ease of use." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:75 msgid "Added :meth:`~.BarChart.get_bar_labels` to annotate the value of each bar of a :class:`~.BarChart`." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:78 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:81 msgid ":pr:`2568`: Removed Deprecated Methods" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:81 msgid "Removed methods and classes that were deprecated since v0.10.0 and v0.11.0" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:83 msgid ":pr:`2457`: Deprecated :class:`.ShowCreationThenFadeOut`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:87 msgid "New features" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:89 msgid ":pr:`2442`: Added ``media_embed`` config option to control whether media in Jupyter notebooks is embedded" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:96 msgid ":pr:`2504`: Added finer control over :meth:`.Scene.wait` being static (i.e., no updaters) or not" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:93 msgid "Added keyword argument ``frozen_frame`` to :class:`.Wait` and :meth:`.Scene.wait`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:94 msgid "New convenience method: :meth:`.Scene.pause` (alias for ``Scene.wait(frozen_frame=True)``)" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:95 msgid "Changed default behavior for OpenGL updaters: updater functions are now not called by default when they are added" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:96 msgid "Changed default behavior of :meth:`.Scene.should_mobjects_update`: made it respect the set value of ``Wait.frozen_frame``, changed automatic determination of frozen frame state to also consider Scene updaters" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:99 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:101 msgid ":pr:`2478`: Alternative scaling for tree graph layout" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:104 msgid ":pr:`2565`: Allowed passing vertex configuration keyword arguments to :meth:`.Graph.add_edges`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:107 msgid ":pr:`2467`: :class:`~.MathTex`, :class:`~.Tex`, :class:`~.Text` and :class:`~.MarkupText` inherit color from their parent mobjects" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:110 msgid ":pr:`2537`: Added support for PySide coordinate system" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:113 msgid ":pr:`2158`: Added OpenGL compatibility to :meth:`.ThreeDScene.add_fixed_orientation_mobjects` and :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:116 msgid ":pr:`2535`: Implemented performance enhancement for :meth:`.VMobject.insert_n_curves_to_point_list`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:119 msgid ":pr:`2516`: Cached view matrix for :class:`~.OpenGLCamera`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:122 msgid ":pr:`2508`: Improve performance for :meth:`.Mobject.become`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:125 msgid ":pr:`2332`: Changed ``color``, ``stroke_color`` and ``fill_color`` attributes to properties" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:131 msgid ":pr:`2396`: Fixed animations introducing or removing objects" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:129 msgid ":class:`.ShowPassingFlash` now removes objects when the animation is finished" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:130 msgid "Added ``introducer`` keyword argument to :class:`.Animation` analogous to ``remover``" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:131 msgid "Updated :class:`.Graph` vertex addition handling" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:134 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:136 msgid ":pr:`2574`: Improved Error in :mod:`.utils.tex_file_writing`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:139 msgid ":pr:`2580`: Fixed :func:`.find_intersection` in :mod:`.space_ops`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:142 msgid ":pr:`2576`: Fixed a bug with animation of removal of edges from a :class:`.Graph`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:145 msgid ":pr:`2556`: Fixed showing highlighted cells when creating :class:`.Table`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:148 msgid ":pr:`2559`: Fix setting line numbers in :class:`.Text` when using ManimPango settings" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:151 msgid ":pr:`2557`: Fixed logger bug in :meth:`.Camera.make_background_from_func`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:154 msgid ":pr:`2548`: Fixed :class:`.Axes` plotting bug with logarithmic x-axis" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:157 msgid ":pr:`1547`: Fixed certain unicode characters in users' paths causing issues on Windows" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:160 msgid ":pr:`2526`: Fixed segfault when using ``--enable_gui``" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:163 msgid ":pr:`2538`: Fixed flickering OpenGL preview when using ``frozen_frame``" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:166 msgid ":pr:`2528`: Fixed custom naming of gifs and added some tests" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:169 msgid ":pr:`2487`: Fixed :meth:`.ThreeDCamera.remove_fixed_orientation_mobjects`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:172 msgid ":pr:`2530`: Use single source of truth for default text values" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:175 msgid ":pr:`2494`: Fixed an issue related to previewing gifs" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:178 msgid ":pr:`2490`: Fixed order of transformation application in :class:`~.SVGMobject`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:181 msgid ":pr:`2357`: Fixed ``screeninfo.get_monitors`` for MacOS" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:184 msgid ":pr:`2444`: Fixed :meth:`.VectorScene.add_axes`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:188 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:190 msgid ":pr:`2560`: Refactored more docstrings in :mod:`.geometry`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:193 msgid ":pr:`2571`: Refactored docstrings in :mod:`.graphing`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:196 msgid ":pr:`2569`: Refactored docstrings in :mod:`.geometry`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:198 msgid ":pr:`2549`: Added a page for internals which links to our GitHub wiki" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:201 msgid ":pr:`2458`: Improved documentation for :class:`.Rotate`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:204 msgid ":pr:`2459`: Added examples to some transform animations" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:207 msgid ":pr:`2517`: Added guide on profiling and improving performance" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:210 msgid ":pr:`2518`: Added imports to examples for ``deprecation`` decorator" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:213 msgid ":pr:`2499`: Improved help text for ``--write_to_movie``" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:216 msgid ":pr:`2465`: Added documentation for :func:`.index_labels`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:219 msgid ":pr:`2495`: Updated minimal LaTeX installation instructions" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:222 msgid ":pr:`2500`: Added note about contributions during refactor period" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:225 msgid ":pr:`2431`: Changed example in :meth:`.Surface.set_fill_by_value`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:228 msgid ":pr:`2485`: Fixed some typos in documentation" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:231 msgid ":pr:`2493`: Fixed typo in documentation for parameters of :class:`.Square`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:234 msgid ":pr:`2482`: Updated Python version requirement in installation guide" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:237 msgid ":pr:`2438`: Removed unnecessary rotation from example" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:240 msgid ":pr:`2468`: Hid more private methods from the docs" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:243 msgid ":pr:`2466`: Fixed a typo in the documentation for plugins" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:246 msgid ":pr:`2448`: Improvements to the ``.pot`` files cleaning system" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:249 msgid ":pr:`2436`: Fixed typo and improved example in building blocks tutorial" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:253 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:255 msgid ":pr:`2554`: Removed ``Remove-Item`` calls for MSYS2 Python" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:258 msgid ":pr:`2531`: Added a GitHub Action for automatic validation of citation metadata" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:261 msgid ":pr:`2536`: Upgraded version of setup-ffmpeg CI action" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:264 msgid ":pr:`2484`: Updated tinytex download URL" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:268 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:270 msgid ":pr:`2573`: Moved :mod:`.value_tracker` back inside :mod:`.mobject`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:273 msgid ":pr:`2566`: Removed unused livestream-related imports and functions from :mod:`.scene_file_writer`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:276 msgid ":pr:`2524`: Reworked :mod:`.space_ops`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:279 msgid ":pr:`2519`: Removed outdated comment" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:282 msgid ":pr:`2503`: Removed unused imports" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:285 msgid ":pr:`2475`: Removed setuptools dependency" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:288 msgid ":pr:`2472`: Removed unnecessary comment in :mod:`.simple_functions`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:291 msgid ":pr:`2429`: Upgraded to future-style type annotations" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:294 msgid ":pr:`2464`: Bump pillow from 8.4.0 to 9.0.0" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:297 msgid ":pr:`2376`: Updated dependencies for Python 3.10" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:305 msgid ":pr:`2437`: Cleaned up :mod:`.simple_functions`" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:301 msgid "Removed ``fdiv`` as in all cases where it was used, it was just doing the same thing as numpy array division." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:302 msgid "Replaced old implementation of the choose function with scipy's implementation" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:303 msgid "Use ``lru_cache`` (least recently used cache) for caching the choose function. Since it's only used for beziers, only 2 choose k and 3 choose k will be used, hence a size of 10 should be enough." msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:304 msgid "Removed ``clip_in_place`` in favor of ``np.clip``" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:305 msgid "Removed one use of ``clip_in_place`` that wasn't actually doing anything" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:307 msgid ":pr:`2439`: Removed twitter template from scripts" msgstr "" #: ../../source/changelog/0.15.0-changelog.rst:311 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.15.1-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.15.1-changelog.rst:3 msgid "v0.15.1" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:5 msgid "March 08, 2022" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:10 msgid "A total of 9 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:14 #: ../../source/changelog/0.15.1-changelog.rst:24 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:15 msgid "Nicolai Weitkemper" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:16 msgid "Yuchen +" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:17 #: ../../source/changelog/0.15.1-changelog.rst:28 msgid "ad_chaos" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:20 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:23 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:25 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:26 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:27 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:29 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:32 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:34 msgid "A total of 9 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:37 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:39 msgid ":pr:`2602`: Support groups in :class:`.TransformMatchingTex`" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:43 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:45 msgid ":pr:`2594`: Fixed render flow issues with introducer animations" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:48 msgid ":pr:`2584`: Fixed bug with invalid color type ``None``" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:51 msgid ":pr:`2587`: Fixed bug with rendering Tex string that contain ``%``" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:54 msgid ":pr:`2593`: Fixed bug with displaying images in Jupyter Notebooks when ``config.media_embed`` is set to ``False``" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:58 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:60 msgid ":pr:`2570`: Refactored docstrings in :mod:`.coordinate_systems`" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:63 msgid ":pr:`2603`: Reduced the number of warnings during documentation build" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:67 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:69 msgid ":pr:`2578`: Fixed incorrect type hint for color property of :class:`.Text`" msgstr "" #: ../../source/changelog/0.15.1-changelog.rst:73 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.15.2-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.15.2-changelog.rst:3 msgid "v0.15.2" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:5 msgid "April 25, 2022" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:10 msgid "A total of 33 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:14 msgid "Bailey Powers +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:15 #: ../../source/changelog/0.15.2-changelog.rst:44 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:16 msgid "Dan Walsh +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:17 msgid "Darigov Research" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:18 #: ../../source/changelog/0.15.2-changelog.rst:46 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:19 msgid "David Millard +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:20 msgid "Hamidreza Hashemi +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:21 #: ../../source/changelog/0.15.2-changelog.rst:49 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:22 #: ../../source/changelog/0.15.2-changelog.rst:50 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:23 msgid "Jonathan Alpert +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:24 msgid "Joy Bhalla" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:25 msgid "Kian Cross +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:26 msgid "Luca +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:27 msgid "Mohsin Shaikh +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:28 #: ../../source/changelog/0.15.2-changelog.rst:53 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:29 msgid "Prismo +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:30 #: ../../source/changelog/0.15.2-changelog.rst:55 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:31 msgid "WillSoltas +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:32 #: ../../source/changelog/0.15.2-changelog.rst:56 msgid "ad_chaos" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:33 msgid "darkways +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:34 msgid "dawn*squirryl +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:35 #: ../../source/changelog/0.15.2-changelog.rst:59 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:36 #: ../../source/changelog/0.15.2-changelog.rst:60 msgid "peaceheis" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:37 msgid "sparshg" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:38 msgid "trickypr +" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:41 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:45 msgid "Dan Walsh" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:47 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:48 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:51 msgid "Jonathan Alpert" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:52 msgid "Luca" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:54 msgid "Prismo" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:57 msgid "darkways" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:58 msgid "hickmott99" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:63 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:65 msgid "A total of 39 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:68 msgid "New features" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:74 msgid ":pr:`1975`: Improved CLI help page styling" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:71 msgid "Updates dependencies on Click and Cloup libraries for CLI help page styling." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:72 msgid "Removed the dependency on click-default-group." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:73 msgid "Added ``no_args_is_help`` parameter for ``manim render`` to allow easy access to help page." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:74 msgid "Added note to ``manim`` help page epilog on how to access other command help pages." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:77 msgid ":pr:`2404`: Add :class:`.SpiralIn` Animation" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:77 msgid "Make :class:`.ManimBanner` to use :class:`.SpiralIn`." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:79 msgid ":pr:`2534`: Implement :class:`~.OpenGLImageMobject`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:82 msgid ":pr:`2684`: Created a more accessible way to create Angles with line.py angle function - :meth:`.Angle.from_three_points`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:86 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:88 msgid ":pr:`2062`: Reuse shader wrappers and shader data" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:92 msgid ":pr:`2642`: Migrated ``file_ops.py`` and ``scene_file_writer.py`` from os.path to Pathlib" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:92 msgid "In ``file_ops.py`` and ``scene_file_writer.py``: Uses of str type file names have been mostly (see further information) converted to pathlib's Path objects. Uses of ``os.path`` methods have been converted to equivalent pathlib methods." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:94 msgid ":pr:`2655`: Fix :func:`.assert_is_mobject_method` when using OpenGL" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:97 msgid ":pr:`2665`: Improved handling of attributes when using the ``.animate`` syntax" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:102 msgid ":pr:`2674`: Document and type ``simple_functions.py``" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:101 msgid "Add documentation for ``simple_functions.py``." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:102 msgid "Small additions with some extra clarity for these functions." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:105 msgid ":pr:`2693`: Allow using :meth:`.MovingCamera.auto_zoom` without animation" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:105 msgid "Allows auto zooming camera without having to play an animation by passing an ``animation=False`` argument" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:108 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:110 msgid ":pr:`2546`: Fixed a file logging bug and some maintenance" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:116 msgid ":pr:`2597`: Fix Bug in :class:`.Uncreate` with ``rate_func`` via introducing new parameter ``reversed`` to :class:`.Animation`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:114 msgid "Refractor the :class:`.Uncreate`. The new implementation uses a flag member ``reversed``. Set it to ``True`` and its superclass handles the reverse." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:115 msgid "Introduce a bool parameter ``reversed`` to :class:`.Animation`. It decides whether the animation needs to be played backwards. Default to be False." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:116 msgid "Add conditional branches in :meth:`.Animation.get_sub_alpha`. If the parameter ``reversed`` is True, it would set ``rate_func(t)`` to ``rate_func(1 - t)``." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:118 msgid ":pr:`2613`: Fixed bug in :meth:`.Circle.point_at_angle` when the angle is not in the interval :math:`[0, 2\\pi]`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:121 msgid ":pr:`2634`: Fix background lines drawn twice in :class:`.NumberPlane`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:124 msgid ":pr:`2648`: Handle user-defined centers for Wiggle animation" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:128 msgid ":pr:`2658`: Fix arguments of overridden ``set_style`` for :class:`.BackgroundRectangle`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:128 msgid "Using :class:`.Write` animation on a :class:`.Text` object with ``.add_background_rectangle()`` applied no longer generates a ``TypeError``." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:130 msgid ":pr:`2668`: (Re)set background color of :class:`.OpenGLRenderer` when initializing scene" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:133 msgid ":pr:`2676`: Fixed propagation of custom attributes in animations for the OpenGL renderer" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:136 msgid ":pr:`2688`: Fixed two minor issues of :class:`.SpiralIn` and :class:`.ManimBanner`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:140 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:142 msgid ":pr:`2609`: Copyedit troubleshooting.rst" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:145 msgid ":pr:`2610`: Add example PolygonOnAxes" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:148 msgid ":pr:`2617`: Re-added :mod:`.value_tracker` documentation" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:151 msgid ":pr:`2619`: Improve Example for arrange_in_grid" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:154 msgid ":pr:`2620`: Fixed typo in :meth:`.Animation.is_introducer`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:158 msgid ":pr:`2640`: Copyedited Documentation" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:158 msgid "Reviewed ``tutorials/configurations.rst``. Edited simple mistakes such as Manim not being capitalized and commas." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:160 msgid ":pr:`2649`: Document and type utils/iterables.py" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:163 msgid ":pr:`2651`: Update copyright year in documentation to 2020-2022" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:165 msgid ":pr:`2663`: Added documentation for scene updater functions" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:168 msgid ":pr:`2686`: Add instructions to install extra dependencies with poetry" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:172 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:174 msgid ":pr:`2561`: Run tests on Linux-aarch64" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:177 msgid ":pr:`2656`: Fixed incompatibility with black version" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:181 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:184 msgid ":pr:`2630`: Remove WebGL renderer" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:184 msgid "The WebGL renderer is broken and unmaintained. The support for it in Manim is removed." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:186 msgid ":pr:`2652`: Update ``cloup`` version to 0.13.0 from 0.7.0" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:189 msgid ":pr:`2678`: Require ``backports-cached-property`` only for Python < 3.8" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:193 msgid ":pr:`2685`: Migrate from ``os.path`` to ``pathlib`` in testing scripts" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:193 msgid "This pull request changes a number of instances of ``os.path`` to Pathlib objects and functions. In addition, this PR modifies the SVGMobject constructor to accept both a Pathlib object or a string variable pathname its constructor." msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:195 msgid ":pr:`2691`: Removed :class:`CameraFrame`" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:198 msgid ":pr:`2696`: Made changelog generation run in parallel plus further improvements to ``scripts/dev_changelog.py``" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:201 msgid ":pr:`2697`: Sort PRs by number in changelog sections before writing" msgstr "" #: ../../source/changelog/0.15.2-changelog.rst:205 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.16.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.16.0-changelog.rst:3 msgid "v0.16.0" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:5 msgid "July 13, 2022" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:10 msgid "A total of 44 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:14 #: ../../source/changelog/0.16.0-changelog.rst:51 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:15 msgid "Baroudi Aymen +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:16 #: ../../source/changelog/0.16.0-changelog.rst:52 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:17 msgid "Charalampos Georgiou +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:18 msgid "Cindy Park +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:19 msgid "Ejar +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:20 msgid "Francesco Frassinelli +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:21 msgid "Francisco Manríquez Novoa +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:22 msgid "Jacob Evan Shreve +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:23 msgid "Jaime Santos +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:24 #: ../../source/changelog/0.16.0-changelog.rst:58 msgid "Jonathan Alpert" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:25 msgid "Joshua Mankelow +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:26 msgid "Kevin Lubick +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:27 #: ../../source/changelog/0.16.0-changelog.rst:60 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:28 msgid "Lingren Kong +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:29 msgid "Logen +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:30 #: ../../source/changelog/0.16.0-changelog.rst:61 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:31 msgid "Noam Zaks" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:32 msgid "Pedro Lamkowski +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:33 #: ../../source/changelog/0.16.0-changelog.rst:64 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:34 msgid "Simeon Widdis" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:35 #: ../../source/changelog/0.16.0-changelog.rst:66 msgid "Sparsh Goenka" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:36 msgid "TornaxO7 +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:37 msgid "Tristan Schulz +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:38 msgid "WillSoltas" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:39 #: ../../source/changelog/0.16.0-changelog.rst:69 msgid "ad_chaos" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:40 msgid "conor-oneill-2 +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:41 msgid "fcrozatier +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:42 msgid "mooncaker816 +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:43 msgid "niklebedenko +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:44 msgid "nyabkun +" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:45 msgid "quark67" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:48 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:53 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:54 msgid "Francesco Frassinelli" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:55 msgid "Francisco Manríquez Novoa" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:56 msgid "Gianluca Gippetto" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:57 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:59 msgid "Kevin Lubick" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:62 msgid "Pedro Lamkowski" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:63 msgid "Philipp Imhof" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:65 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:67 msgid "TornaxO7" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:68 msgid "Tristan Schulz" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:70 msgid "hickmott99" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:73 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:75 msgid "A total of 56 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:78 msgid "Highlights" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:82 msgid ":pr:`2550`: New thematic guide: a deep dive into the internals of the library" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:81 msgid "This new :doc:`thematic guide ` aims to be a comprehensive walkthrough describing all the things that Manim does when you run it to produce a video." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:84 msgid ":pr:`2732`: Improved overall structure of deployed documentation; added a dedicated :doc:`FAQ section `" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:90 msgid ":pr:`2749`: Added :class:`.ChangeSpeed`, an animation wrapper that allows to smoothly change the speed at which an animation is played" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:88 msgid "The speed of any animation can be changed by wrapping the animation with :class:`.ChangeSpeed` and passing a dictionary as ``speedinfo`` whose keys are the relative animation run time stamps and whose values are the absolute speed factors; e.g., ``{0.5: 2, 0.75: 0.25}`` smoothly speeds up the animation by a factor of 2 once it has been completed to 50%, and then it is smoothly slowed down to 1/4 of the default run speed after 75% of the animation are completed. The ``run_time`` of the animation will be adjusted to match the changed play speed." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:90 msgid "It is also possible to add time-based updaters that respect the change in speed, use the auxiliary :meth:`.ChangeSpeed.add_updater` method to do so." msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:93 msgid "New features" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:95 msgid ":pr:`2667`: Made FFmpeg executable path configurable" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:98 msgid ":pr:`2739`: Added vectorized plotting functionality via keyword argument ``use_vectorized`` to improve performance" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:102 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:104 msgid ":pr:`2186`: Enabled filling color by value for :class:`.OpenGLSurface`, replaced ``colors`` keyword argument of :meth:`.Surface.set_fill_by_value` with ``colorscale``" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:107 msgid ":pr:`2288`: Added warning when attempting to add same mobject as child twice" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:112 msgid ":pr:`2707`: Fixed missing ``get_nth_curve_length_pieces`` method of :class:`.OpenGLVMobject`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:111 msgid "Removed duplicate definition of ``get_curve_functions_with_lengths`` in ``OpenGLVMobject``" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:112 msgid "Added definition of ``get_nth_curve_length_pieces`` to ``OpenGLVMobject``" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:114 msgid ":pr:`2709`: Improved the look of the brackets of :class:`.Matrix`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:117 msgid ":pr:`2714`: Fixed :meth:`.OpenGLVMobject.pointwise_become_partial` to improve stroke rendering" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:120 msgid ":pr:`2727`: Slight performance improvement for :class:`.ArrowVectorField` and Bézier curve computation" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:123 msgid ":pr:`2728`: Added :meth:`.VectorField.fit_to_coordinate_system` to fit a vector field to a given coordinate system" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:126 msgid ":pr:`2730`: Added note to let users find documentation of default CLI subcommand easier" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:129 msgid ":pr:`2746`: Installed ghostscript in the docker image" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:132 msgid ":pr:`2841`: Added :func:`.split_quadratic_bezier` and :func:`.subdivide_quadratic_bezier`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:135 msgid ":pr:`2842`: CLI: Moved functionality from ``manim new`` to ``manim init`` and added deprecation warning for ``manim new``" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:138 msgid ":pr:`2866`: Reorganize test files to match library module structure" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:142 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:144 msgid ":pr:`2567`: Use tempconfig for every scene render" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:147 msgid ":pr:`2638`: Fixed :meth:`BarChart.change_bar_values` not updating when height is 0" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:150 msgid ":pr:`2661`: Fixed tip resize functionality for :class:`.Axes` to match documentation" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:153 msgid ":pr:`2703`: Default to utf-8 when reading files in :class:`.Code`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:156 msgid ":pr:`2721`: Fixed bad text slicing for lines in :class:`.Paragraph`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:159 msgid ":pr:`2725`: Fixed wrong indentation in :class:`.Code`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:162 msgid ":pr:`2734`: Fixed OpenGL segfaults when running :meth:`.Scene.play` or :meth:`.Scene.wait` in interactive mode" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:165 msgid ":pr:`2753`: Fixed multiplatform builds for docker images in pipeline" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:168 msgid ":pr:`2757`: Added missing ``__init__.py`` file in :mod:`.docbuild` module" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:171 msgid ":pr:`2770`: Fixed bug in :meth:`.VMobject.proportion_from_point` that caused proportions greater than 1 to be returned" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:174 msgid ":pr:`2826`: Fixed leaked mobjects coming from :class:`.TransformMatchingAbstractBase`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:177 msgid ":pr:`2870`: Fixed issue with ``manim init scene SCENE_NAME filename.py`` and removed necessity of ``main.py`` to be present in working directory" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:181 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:183 msgid ":pr:`2704`: Updated URL to Pango Markup formatting page" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:186 msgid ":pr:`2716`: Improved the order of the reference manuals" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:189 msgid ":pr:`2720`: Fixed typo in docstring of :class:`.Angle`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:192 msgid ":pr:`2722`: Fixed typos in docstrings of classes in :mod:`.mobject.table`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:195 msgid ":pr:`2726`: Edited note on :class:`.NumberPlane` length and added another example" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:198 msgid ":pr:`2740`: Fixed documentation of :meth:`.Cylinder.get_direction`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:201 msgid ":pr:`2755`: Fixed docstring of :meth:`.VMobject.get_end_anchors`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:204 msgid ":pr:`2760`: Removed ``cmake`` from the MacOS installation section" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:207 msgid ":pr:`2767`: Added more questions and answers to FAQ section, new :doc:`OpenGL FAQ `" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:210 msgid ":pr:`2771`: Added documentation and testing for ``path_func`` keyword argument of :class:`.Transform`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:213 msgid ":pr:`2828`: Removed suggestion issue template, added FAQ answer regarding proposing new features" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:216 msgid ":pr:`2849`: Added example for ``path_arc`` keyword argument of :class:`.Transform`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:219 msgid ":pr:`2851`: Added an example on constructing a (neural) network using a partite :class:`.Graph`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:222 msgid ":pr:`2855`: Added implicit ``docker.io/`` URL base in reference to docker images" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:225 msgid ":pr:`2861`: Added docstring for :meth:`.CoordinateSystem.plot_parametric_curve`" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:229 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:231 msgid ":pr:`2743`: Replaced ``assert`` statements with with assertion functions from ``np.testing``" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:235 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:237 msgid ":pr:`2700`: CI: updated Python versions" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:240 msgid ":pr:`2701`: CI: added a workflow to publish docker image after releases and commits to main branch" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:244 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:246 msgid ":pr:`2680`: Increased minimum required version of ``numpy`` to 1.19" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:249 msgid ":pr:`2687`: Migrated from ``os.path`` to ``pathlib`` in :class:`.SVGMobject` and other locations" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:252 msgid ":pr:`2715`: Updated deprecated ``pillow`` constants" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:255 msgid ":pr:`2735`: Bump pyjwt from 2.3.0 to 2.4.0" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:258 msgid ":pr:`2748`: Bump pillow from 9.1.0 to 9.1.1" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:261 msgid ":pr:`2751`: Fixed flake C417 and improved a comment" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:264 msgid ":pr:`2825`: Bump notebook from 6.4.11 to 6.4.12" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:267 msgid ":pr:`2864`: Updated lockfile" msgstr "" #: ../../source/changelog/0.16.0-changelog.rst:271 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.2.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.2.0-changelog.rst:3 msgid "v0.2.0" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:5 msgid "January 1, 2021" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:7 msgid "The changes since Manim Community release v0.1.1 are listed below." msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:10 msgid "Breaking Changes" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:12 msgid "Remove all CONFIG dictionaries and all calls to ``digest_config`` and allow passing options directly to the constructor of the corresponding classes (:pr:`783`)." msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:15 msgid "Practically, this means that old constructions using ``CONFIG`` like::" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:22 msgid "where corresponding objects were then instantiated as ``my_mobject = SomeMobject()`` should now be created simply using ``my_mobject = SomeMobject(my_awesome_property=42)``." msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:25 msgid "Remove old syntax for animating mobject methods by passing the methods and arguments to ``self.play``, and use a new syntax featuring the ``animate`` property (:pr:`881`)." msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:28 msgid "For example: the old-style ``play`` call ::" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:33 msgid "should be replaced with the new following call using the ``animate`` property::" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:38 msgid "New Features" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:40 msgid "Added creation animation for :class:`~.ManimBanner` (:pr:`814`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:41 msgid "Added some documentation to :meth:`~.Scene.construct` (:pr:`753`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:42 msgid "Added a black and white monochromatic version of Manim's logo (:pr:`826`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:43 msgid "Added support for a plugin system (``manim plugin`` subcommand + documentation) (:pr:`784`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:44 msgid "Implemented ``__add__``, ``__iadd__``, ``__sub__``, and ``__isub__`` for :class:`~.Mobject` (allowing for notation like ``some_vgroup + some_mobject``) (:pr:`790`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:45 msgid "Added type hints to several files in the library (:pr:`835`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:46 msgid "Added some examples to :mod:`~.animation.creation` (:pr:`820`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:47 msgid "Added some examples to :class:`~.DashedLine` and :class:`~.CurvesAsSubmobjects` (:pr:`833`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:48 msgid "Added new implementation for text rendered with Pango, :class:`~.MarkupText`, which can be formatted with an HTML-like syntax (:pr:`855`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:49 msgid "Added Fading in and out examples and deprecation of ``FadeInFromDown`` and ``FadeOutAndShiftDown`` (:pr:`827`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:50 msgid "Added example for :class:`~.MoveAlongPath` to the docs (:pr:`873`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:51 msgid "Added ambient rotate for other angles - theta, phi, gamma (:pr:`660`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:52 msgid "Use custom bindings for Pango (:pr:`878`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:53 msgid "Added :class:`~.Graph`, a basic implementation for (graph theory) graphs (:pr:`861`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:54 msgid "Allow for chaining methods when using the new ``.animate`` syntax in :meth:`~.Scene.play` (:pr:`889`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:57 msgid "Bugfixes" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:59 msgid "Fix doctests in .rst files (:pr:`797`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:60 msgid "Fix failing doctest after adding ``manim plugin`` subcommand (:pr:`831`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:61 msgid "Normalize the direction vector in :meth:`~.mobject_update_utils.always_shift` (:pr:`839`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:62 msgid "Add ``disable_ligatures`` to :class:`~.Text` (via :pr:`804`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:63 msgid "Make scene caching aware of order of Mobjects (:pr:`845`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:64 msgid "Fix :class:`~.CairoText` to work with new config structure (:pr:`858`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:65 msgid "Added missing argument to classes inheriting from :class:`~.Matrix` (:pr:`859`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:66 msgid "Fixed: ``z_index`` of mobjects contained in others as submobjects is now properly respected (:pr:`872`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:67 msgid "Let :meth:`~.ParametricSurface.set_fill_by_checkboard` return the modified surface to allow method chaining (:pr:`883`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:68 msgid "Mobjects added during an updater are added to ``Scene.moving_mobjects`` (:pr:`838`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:69 msgid "Pass background color to JS renderer (:pr:`876`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:70 msgid "Small fixes to docstrings. Tiny cleanups. Remove ``digest_mobject_attrs``. (:pr:`834`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:71 msgid "Added closed shape detection in :class:`~.DashedVMobject` in order to achieve an even dash pattern (:pr:`884`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:72 msgid "Fix Spelling in docstrings and variables across the library (:pr:`890`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:75 msgid "Other changes" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:77 msgid "Change library name to manim (:pr:`811`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:78 msgid "Docker: use local files when building an image (:pr:`803`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:79 msgid "Let ffmpeg render partial movie files directly instead of temp files (:pr:`817`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:80 msgid "``manimce`` to ``manim`` & capitalizing Manim in readme (:pr:`794`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:81 msgid "Added flowchart for different docstring categories (:pr:`828`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:82 msgid "Improve example in module docstring of :mod:`~.animation.creation` + explicitly document buff parameter in :meth:`~.Mobject.arrange` (:pr:`825`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:83 msgid "Disable CI pipeline for Python 3.6 (:pr:`823`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:84 msgid "Update URLs in docs (:pr:`832`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:85 msgid "Move upcoming changelog to GitHub-wiki (:pr:`822`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:86 msgid "Change badges in readme (:pr:`854`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:87 msgid "Exclude generated gRPC files from source control (:pr:`868`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:88 msgid "Added linguist-generated attribute to ``.gitattributes`` (:pr:`877`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:89 msgid "Cleanup: removed inheritance from ``object`` for some classes, refactor some imports (:pr:`795`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:90 msgid "Change several ``str.format()`` to ``f``-strings (:pr:`867`)" msgstr "" #: ../../source/changelog/0.2.0-changelog.rst:91 msgid "Update javascript renderer (:pr:`830`)" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.3.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.3.0-changelog.rst:3 msgid "v0.3.0" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:5 msgid "February 1, 2021" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:7 msgid "The changes since Manim Community release v0.2.0 are listed below." msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:11 msgid "New Features" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:13 msgid ":pr:`945`: :meth:`~.Graph.change_layout` method for :class:`~.Graph` mobject" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:14 msgid ":pr:`943`: IPython %%manim magic" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:15 msgid ":pr:`970`: Added ``--version`` command line flag" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:16 msgid ":pr:`948`: Allow passing a code string to :class:`~.Code`" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:17 msgid ":pr:`917`: Allow overriding new-style method animations" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:18 msgid ":pr:`756`: Allow setting frame_height and frame_width via config file" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:19 msgid ":pr:`939`: Added custom font files support" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:20 msgid ":pr:`892`: Added ManimCommunity colors" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:21 msgid ":pr:`922`: Tree layout for Graph mobject" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:22 msgid ":pr:`935`: Added code of conduct" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:23 msgid ":pr:`916`: Multi-column layout for partite graphs" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:24 msgid ":pr:`742`: Units: Pixels, Munits, Percent in :mod:`~.utils.unit`" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:25 msgid ":pr:`893`: Convenience method :meth:`~.Graph.from_networkx` for creating a graph from a networkx graph" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:28 msgid "Bugfixes and Enhancements" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:30 msgid ":pr:`988`: Fix Windows CI pipeline by adding missing LaTeX package" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:31 msgid ":pr:`961`: Added typings and docs for vectorized mobjects and bezier related functions" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:32 msgid ":pr:`977`: JupyterLab docker image and documentation for manim and IPython" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:33 msgid ":pr:`985`: Fix variable name for webgl renderer" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:34 msgid ":pr:`954`: Fix edges lagging behind vertices in animations of graphs" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:35 msgid ":pr:`980`: Allow usage of custom Pygments styles in Code" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:36 msgid ":pr:`952`: Allow passing tween information to the WebGL frontend" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:37 msgid ":pr:`978`: Fix ``possible_paths`` not printing in ``code_mobject``" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:38 msgid ":pr:`976`: Update ``ManimPango``" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:39 msgid ":pr:`967`: Automatically import plugins" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:40 msgid ":pr:`971`: Make ManimCommunity look consistent" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:41 msgid ":pr:`957`: Raise ``NotImplementedError`` when trying to chain overridden method animations" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:42 msgid ":pr:`947`: Several fixes and improvements for :class:`~.PointCloundDot`" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:43 msgid ":pr:`923`: Documentation: move installation instructions for developers to page for developers" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:44 msgid ":pr:`964`: Added unit test for :class:`~.NumberLine`'s unit vector" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:45 msgid ":pr:`960`: Magnitude of :class:`~.NumberLine`'s unit vector should be ``unit_size``, not 1" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:46 msgid ":pr:`958`: Fix code formatting in ``utils/debug.py``" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:47 msgid ":pr:`953`: Update license year" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:48 msgid ":pr:`944`: Interpolate stroke opacity in :class:`~.FadeIn` and update ``stroke_opacity`` and ``fill_opacity`` in :meth:`~.VMobject.set_stroke` and :meth:`~.VMobject.set_fill`" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:49 msgid ":pr:`865`: Rename ``get_submobject_index_labels`` to ``index_labels``" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:50 msgid ":pr:`941`: Added keyword arguments ``x_min``, ``x_max``, ``y_min``, ``y_max`` to :class:`~.ThreeDAxes`" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:51 msgid ":pr:`886`: Let the render progress bar show details about the rendered animation again" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:52 msgid ":pr:`936`: Fix :class:`~.BulletedList` TeX environment problem and add a typing to ``get_module``" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:53 msgid ":pr:`938`: Remove dependency on progressbar" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:54 msgid ":pr:`937`: Change 'brew cask install' to 'brew install --cask' for CI pipeline" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:55 msgid ":pr:`933`: Make matrix work with lists again" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:56 msgid ":pr:`932`: Correctly parse ``log_dir`` option" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:57 msgid ":pr:`920`: Raise error if markup in :class:`~.MarkupText` is invalid" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:58 msgid ":pr:`929`: Raise an error if a :class:`~.Matrix` object is created with < 2-dimensional input" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:59 msgid ":pr:`907`: Make Scene.add_sound work again (when running with ``--disable_caching``)" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:60 msgid ":pr:`906`: Allow new-style method animation to be used in animation groups" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:61 msgid ":pr:`908`: Removed deprecated command line arguments from documentation" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:62 msgid ":pr:`903`: Tiny grammar improvements" msgstr "" #: ../../source/changelog/0.3.0-changelog.rst:63 msgid ":pr:`904`: Added blank line between imports and class example" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.4.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.4.0-changelog.rst:3 msgid "v0.4.0" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:5 msgid "March 3, 2021" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:7 msgid "The changes since Manim Community release v0.3.0 are listed below." msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:10 msgid "Breaking Changes" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:12 msgid ":pr:`915`: Manim's SVG engine has been reworked and is able to handle a wider variations of SVG files. In particular: fill and stroke properties are now retained from the original files. Breaking change: ``VMobjectFromSVGPathstring`` is deprecated and has been renamed to ``SVGPathMobject``." msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:16 msgid "New Features" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:18 msgid ":pr:`1026`: Add 3D Mobjects: :class:`~.Cone`, :class:`~.Cylinder`, :class:`~.Line3D`, :class:`~.Arrow3D` and :class:`~.Torus`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:19 msgid ":pr:`1047`: Add documentation and examples for :class:`~.Matrix`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:20 msgid ":pr:`1044`: ``register_font`` is available for macOS" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:21 msgid ":pr:`995`: Add generic :func:`~.Mobject.set` method and compatibility layer between properties and ``get_*``/``set_*`` methods" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:24 msgid "Bugfixes and Enhancements" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:26 msgid ":pr:`981`: Fixed hot reload functionality for the WebGL renderer on Windows" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:27 msgid ":pr:`1053`: Repair links to source code in stable version of documentation" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:28 msgid ":pr:`1067`: Add ManimPango to ReadTheDocs requirements" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:29 msgid ":pr:`1058`: Replace ```` syntax by Pango's ```` for coloring parts of :class:`~.MarkupText` and allow using colors for underline, overline and strikethrough in MarkupText" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:30 msgid ":pr:`1063`: Fix documentation related to ``.animate``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:31 msgid ":pr:`1065`: Remove duplicate word 'vector'" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:32 msgid ":pr:`1060`: Update Linux installation instructions to mention the installation of Pango" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:33 msgid ":pr:`1050`: Ensure that the user-supplied stroke color and width gets applied to :class:`~.Cross`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:34 msgid ":pr:`1059`: More descriptive error when accessing an unhandled mobject attribute" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:35 msgid ":pr:`1048`: Use absolute path in ``make_and_open_docs.py``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:36 msgid ":pr:`1000`: Remove ``MovingCameraScene.setup`` and ``MovingCameraScene.camera_frame``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:37 msgid ":pr:`1051`: Corrections for setting stroke related attributes on :class:`~.VMobject`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:38 msgid ":pr:`1043`: Make :class:`~.CubicBezier` explicitly accept four points" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:39 msgid ":pr:`1046`: Use any version of ``importlib-metadata``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:40 msgid ":pr:`1030`: Parse ``.log`` file and try to print LaTeX errors if compilation fails" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:41 msgid ":pr:`1015`: Documentation: Add more explicit instructions related to ``tlmgr``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:42 msgid ":pr:`1028`: Documentation: Update installation guide on mac with Apple Silicon" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:43 msgid ":pr:`1032`: Remove ``Square.side_length`` property" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:44 msgid ":pr:`1031`: Fix link to wikipedia vector graphics page" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:45 msgid ":pr:`1021`: Documentation: Added example to :class:`~.CubicBezier`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:46 msgid ":pr:`1017`: Added ``progress_bar`` to ``digest_args`` to fix the ``--progress_bar`` CLI flag" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:47 msgid ":pr:`1018`: Remove redundancy in :class:`~.FunctionGraph` arguments" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:48 msgid ":pr:`1024`: Migrate ``width`` / ``height`` / ``depth`` to properties" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:49 msgid ":pr:`1022`: Fix ``-p`` flag when passing ``-s``" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:50 msgid ":pr:`1008`: CI pipeline: fix release asset upload" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:51 msgid ":pr:`983`: Make sure last frame for animations with updaters is correct" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:52 msgid ":pr:`984`: Add manim version to CLI output, append version name for generated ``.gif`` and ``.png`` files, add version to metadata of rendered videos, change dark blue terminal text to default green" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:53 msgid ":pr:`993`: Fix setting Mobject color to a gradient by passing a list of colors in :meth:`~.VMobject.set_color`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:54 msgid ":pr:`1003`: Fix animation :class:`~.GrowArrow`" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:55 msgid ":pr:`1010`: Disable STDIN interaction for ffmpeg concat." msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:56 msgid ":pr:`969`: Fix the ``--tex_template`` CLI flag" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:57 msgid ":pr:`989`: Fix the ``manim cfg export`` subcommand" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:58 msgid ":pr:`1005`: Fix the feature where ``-`` is used as the filename" msgstr "" #: ../../source/changelog/0.4.0-changelog.rst:59 msgid ":pr:`998`: Allow using hexadecimal color codes with 3 characters" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.5.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.5.0-changelog.rst:3 msgid "v0.5.0" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:5 msgid "April 02, 2021" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:10 msgid "A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:14 msgid "Abel Aebker +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:15 #: ../../source/changelog/0.5.0-changelog.rst:47 msgid "Abhijith Muthyala" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:16 msgid "AntonBallmaier +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:17 msgid "Aron" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:18 #: ../../source/changelog/0.5.0-changelog.rst:48 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:19 msgid "Bogdan Stăncescu +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:20 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:21 #: ../../source/changelog/0.5.0-changelog.rst:50 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:22 msgid "GameDungeon +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:23 #: ../../source/changelog/0.5.0-changelog.rst:51 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:24 #: ../../source/changelog/0.5.0-changelog.rst:52 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:25 #: ../../source/changelog/0.5.0-changelog.rst:53 msgid "Kapil Sachdeva" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:26 #: ../../source/changelog/0.5.0-changelog.rst:54 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:27 msgid "Lionel Ray +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:28 #: ../../source/changelog/0.5.0-changelog.rst:57 msgid "Mark Miller" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:29 msgid "Mohammad Al-Fetyani +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:30 #: ../../source/changelog/0.5.0-changelog.rst:59 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:31 msgid "Niklas Dewally +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:32 msgid "Oliver +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:33 msgid "Roopesh +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:34 msgid "Seb Pearce +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:35 msgid "aebkea +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:36 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:37 msgid "hydrobeam +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:38 msgid "kolibril13" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:39 msgid "sparshg" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:40 msgid "tfglynn +" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:43 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:46 msgid "Abel Aebker" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:49 msgid "Bogdan Stăncescu" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:55 msgid "Leo Torres" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:56 msgid "Lionel Ray" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:58 msgid "Mohammad Al-Fetyani" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:60 msgid "Oliver" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:61 msgid "Ricky Chon" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:62 msgid "vector67" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:65 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:67 msgid "A total of 64 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:70 msgid "Highlights" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:73 msgid ":pr:`1075`: Add OpenGL Renderer" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:73 msgid "Adds an OpenGLRenderer, OpenGLCamera, OpenGL-enabled Mobjects, and a ``--use_opengl_renderer`` flag. When this flag is passed, you can pass the ``-p`` flag to preview animations, the ``-w`` flag to generate video, and the ``-q`` flag to specify render quality. If you don't pass either the ``-p`` or the ``-w`` flag, nothing will happen. Scenes rendered with the OpenGL renderer must *only* use OpenGL-enabled Mobjects." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:76 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:80 msgid ":pr:`1124`: Deprecated :class:`ShowCreation` in favor of :class:`Create`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:79 msgid "Deprecated :class:`ShowCreation` in favor of :class:`Create` across the library with the exception of the `show_creation` boolean variable `vector_space_scene.py`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:80 msgid "Added a deprecation warning in the original :class:`ShowCreation` class." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:83 msgid ":pr:`1110`: Deprecated SmallDot + OpenGLSmallDot" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:83 msgid "`SmallDot` isn't necessary and a deprecation warning will be raised. This will be removed in a future release." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:86 msgid "New features" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:91 msgid ":pr:`1037`: Added new fade and transform animations (:class:`~.TransformMatchingShapes`, :class:`~.TransformMatchingTex`, :class:`~.FadeTransform`) from 3b1b/manim" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:89 msgid "Added new Fade animation: :class:`~FadeOutToPoint` Added :class:`~FadeTransform` and :class:`~FadeTransformPieces` for transforming mobjects and submobjects with a fade Added :class:`~TransformMatchingShapes` and :class:`~TransformMatchingTex` for transforming mobjects and tex that have matching parts" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:93 msgid ":pr:`1097`: Added 3D Mobject :class:`~.Dot3D`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:96 msgid ":pr:`1074`: Added jupyter media_width option to the config" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:100 msgid ":pr:`1107`: Added :class:`~.Unwrite` animation class to complement :class:`~.Write`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:100 msgid "Added :class:`Unwrite` which inherits from :class:`~.Write`. It automatically reverses the animation of :class:`~.Write` by passing the reversed rate function, but it also takes an additional boolean parameter `reverse` which, if `False`, renders the animation from left to right (assuming text oriented in the usual way), but if `True`, it renders right to left." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:103 msgid ":pr:`1085`: Added :class:`~.Angle` and :class:`~.RightAngle` for intersecting lines" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:103 msgid ":class:`~.Angle` and :class:`~.RightAngle` both take two lines as input. If they intersect, or share a common vertex, an angle is drawn between them. Users can customize the look of the angle and also use a dotted right angle." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:106 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:108 msgid ":pr:`1144`: Improved quality of GIFs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:114 msgid ":pr:`1157`: Refresh triangulation on call to :meth:`~.OpenGLVMobject.apply_points_function`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:112 msgid "Rotate called apply_points_function, which was previous not subclassed by OpenGLMobject - now it is. Then, the vertex normals can be updated too." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:114 msgid "Additionally, the old_points matrix would change after rotating, making the old points / new points test irrelevant. This is addressed with a .copy call." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:116 msgid ":pr:`1151`: Added parametric function support to :class:`OpenGLSurface`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:119 msgid ":pr:`1139`: In-Code `config[\"preview\"]` Support" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:123 msgid ":pr:`1123`: Added caching, skipping, and user-specified background colors to the OpenGL renderer" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:123 msgid "OpenGL play logic has been improved to support caching and skipping with `-n` argument ( it is now similar to Cairo play logic). A random bug was fixed in OpenGLSurface and OpenGL background color can now be changed via `background_color` argument." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:128 msgid ":pr:`1118`: Allow passing animation arguments with .animate syntax" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:126 msgid "Users will now be able to do things like `obj.animate(run_time=2).method(arg)` if they want to specify animation arguments for an individual `.animate` call, and can still not specify any arguments like `obj.animate.method(arg)`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:128 msgid "Passing animation arguments is only allowed directly after `.animate` is accessed, if passed elsewhere then a `ValueError` is raised." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:132 msgid ":pr:`718`: Rotating the numbers in y axis" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:131 msgid "In Axes, the y axis will be rotated 90deg but the numbers are also rotated and shouldn't be. Fixes this issue." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:135 msgid ":pr:`1070`: Raise FileNotFoundError when unable to locate the .cfg file specified via ``--config_file``" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:135 msgid "Raising the error will stop script execution and let the user know that there are problems with the `--config_file` location instead of reverting back to the default configuration." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:138 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:140 msgid ":pr:`1224`: Fixed :class:`~.ShowIncreasingSubsets`, :class:`~.ShowSubmobjectsOneByOne`, and :class:`~.AddTextLetterByLetter`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:143 msgid ":pr:`1201`: Prevent crash on :meth:`~.Scene.embed` for empty scenes" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:146 msgid ":pr:`1192`: Fixed issue when an animation is cached, manim can't merge the partial movie files." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:150 msgid ":pr:`1193`: Fixed using :class:`~.Animation` without a child :class:`~.Mobject` in :class:`~.AnimationGroup`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:150 msgid "`AnimationGroup` may now take `Animation` objects which do not have a child `Mobject`, such as `Wait`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:152 msgid ":pr:`1170`: Fixed minor SVG parsing bugs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:155 msgid ":pr:`1159`: Added support for multiple transforms in the same SVG element" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:159 msgid ":pr:`1156`: Fixed :class:`~.DrawBorderThenFill` to support OpenGL and improved type hints for some functions" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:159 msgid "Fixed a bug in :class:`~.DrawBorderThenFill` that prevented :class:`~.Write` animations from working with :class:`~.OpenGLVMobjects` and slightly improved type hints for some animation functions to include :class:`~.OpenGLVMobject`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:162 msgid ":pr:`1134`: Fixed the `-a` flag." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:162 msgid "The ``-a`` / ``--write-all`` flag was broken. When used, it would cause Manim to crash just after beginning to render the second scene." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:165 msgid ":pr:`1115`: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:165 msgid "Fixed undefined variables and converted :class:`Mobject` to :class:`OpenGLMobject`. Also, fixed assert statement in :class:`ApplyMethod`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:171 msgid ":pr:`1092`: Refactored coordinate_systems.py, fixed bugs, added :class:`~.NumberPlane` test" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:168 msgid "The default behavior of :meth:`~.Mobject.rotate` is to rotate about the center of :class:`~.Mobject`. :class:`~.NumberLine` is symmetric about the point at the number 0 only when ``|x_min|`` == ``|x_max|``. Ideally, the rotation should coincide with the point at number 0 on the line." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:171 msgid "Added a regression test and additionally fixed some bugs introduced in :pr:`718`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:174 msgid ":pr:`1078`: Removed stray print statements from `__main__.py`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:174 msgid "Uses rich's print traceback instead and fixes an issue in printing the version twice when `manim --version` is called." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:177 msgid ":pr:`1086`: Fixed broken line spacing in :class:`~.Text`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:177 msgid "The `line_spacing` kwarg was missing when creating :class:`Text` Mobjects; this adds it." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:180 msgid ":pr:`1083`: Corrected the shape of :class:`~.Torus`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:180 msgid ":class:`Torus` draws a surface with an elliptical cross-section when `minor_radius` is different from 1. This PR ensures the cross-section is always a circle." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:183 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:185 msgid ":pr:`1217`: Copyedited the document on testing in our documentation" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:188 msgid ":pr:`1206`: Added Docstrings to :class:`~.Mobject`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:191 msgid ":pr:`1218`: Removed BezierSpline from the example gallery" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:194 msgid ":pr:`1219`: Updated Dockerfile (include dependencies for building documentation), moved documentation to main README" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:198 msgid ":pr:`1209`: Added :ref_methods: to the manim directive" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:198 msgid "This allows class methods to be linked in the documentation. Checkout the `example references `_ below the code to see how this is used!" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:200 msgid ":pr:`1204`: Added rotation example to example gallery" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:203 msgid ":pr:`1137`: Added GitHub Wiki pages on adding testing/documentation to Sphinx Docs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:206 msgid ":pr:`1114`: Added examples for :class:`~.Ellipse`, :class:`~.Polygon`, :class:`~.RegularPolygon`, :class:`~.Triangle` and :class:`~.RoundedRectangle`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:209 msgid ":pr:`1195`: Removed SmallDot from example" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:212 msgid ":pr:`1130`: Added pre-commit to run black and flake8, updated contributing documentation accordingly" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:216 msgid ":pr:`1138`: Moved previous version changelogs to separate files; Added a Script to generate future changelogs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:216 msgid "This script quickly generates a changelog for whoever is making the release." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:218 msgid ":pr:`1190`: Added note in contributing guide to read the latest version of the documentation" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:221 msgid ":pr:`1188`: Added sounds example to docs" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:224 msgid ":pr:`1165`: Added documentation for installing Manim on Colab" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:227 msgid ":pr:`1128`: Added examples for :class:`~.DashedLine`, :class:`~.TangentLine`, :class:`~.Elbow`, :class:`~.Arrow`, :class:`~.Vector`, :class:`~.DoubleArrow`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:230 msgid ":pr:`1177`: Replace links to the latest version of the documentation to the stable version" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:233 msgid ":pr:`1077`: Added details to :func:`~.Mobject.get_critical_point`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:236 msgid ":pr:`1154`: Fixed some typing hints. (ints to floats)" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:239 msgid ":pr:`1036`: Added :class:`~.SurroundingRectangle` to the example gallery" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:242 msgid ":pr:`1103`: Added documentation and examples for Square, Dot, Circle and Rectangle" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:245 msgid ":pr:`1101`: Added documentation to :class:`~.Mobject`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:249 msgid ":pr:`1088`: Added new svg files to documentation and imports" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:249 msgid "In particular, SVGPathMobject, VMobjectFromPathstring, and the style_utils functions to manim's namespace." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:252 msgid ":pr:`1076`: Improve documentation for GraphScene" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:252 msgid "Updated `coords_to_point` and `point_to_coords` under `manim/scene/graph_scene.py` as the dosctring of each function confusingly described the opposite of what it is supposed to do." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:255 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:257 msgid ":pr:`1160`: Enable CI testing for OpenGL" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:261 msgid ":pr:`1100`: Rewrote test cases to use sys.executable in the command instead of \"python\"" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:261 msgid "Tests would fail due to `capture()` not spawning a subshell in the correct environment, so when python was called, the test would be unable to find necessary packages." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:263 msgid ":pr:`1079`: Removed the hardcoded value, `manim`, in `test_version.py`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:267 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:269 msgid ":pr:`1213`: Updated TinyTex dependencies" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:272 msgid ":pr:`1187`: Add CodeCov to Github Workflow" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:275 msgid ":pr:`1166`: CI: Use poetry's cache dir rather than pip" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:281 msgid ":pr:`1071`: Enable pytest-cov based code coverage" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:279 msgid "Include pytest-cov as a python module as part of developer dependencies" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:280 msgid "In updating poetry to include pytest-cov, manimpango moved from version 0.2.3 to 0.2.4, and libpango1.0-dev needed to be installed in Ubuntu." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:281 msgid "Add to the CI workflow (`ci.yml`) to create and upload test coverage." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:283 msgid ":pr:`1073`: Removed \"one line summary\" from PULL_REQUEST_TEMPLATE.md" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:287 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:289 msgid ":pr:`1167`: Merge :class:`~.OpenGLMobject` and :class:`~.Mobject`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:292 msgid ":pr:`1164`: Fixed single PEP8 style in `cairo_renderer.py`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:295 msgid ":pr:`1140`: Flake8 Compat & Code Cleanup" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:305 msgid ":pr:`1019`: Refactored :meth:`~.Scene.play`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:299 msgid "Removed the _**three**_ decorators of :meth:`~.Scene.play`, in particular: caching logic and file writer logic are now included within :meth:`~.Scene.play` (it wasn't possible before, because `scene.wait` and `scene.play` were two different things)." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:300 msgid "Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame)." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:301 msgid "Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:302 msgid "Now when calling play without animation, it raises `ValueError` instead of just a warning." msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:303 msgid "Fixed :pr:`874` by modifying `renderer.update_skipping_status`" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:304 msgid "`renderer` starts the animation with `scene.begin_animations` (`scene.compile_animation_data` used to do this)" msgstr "" #: ../../source/changelog/0.5.0-changelog.rst:305 msgid "The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later." msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.6.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.6.0-changelog.rst:3 msgid "v0.6.0" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:5 msgid "May 02, 2021" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:10 msgid "A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:14 #: ../../source/changelog/0.6.0-changelog.rst:47 msgid "Abel Aebker" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:15 #: ../../source/changelog/0.6.0-changelog.rst:48 msgid "Abhijith Muthyala" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:16 msgid "Adam Ryczkowski +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:17 msgid "Alex Lembcke +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:18 #: ../../source/changelog/0.6.0-changelog.rst:51 msgid "Anton Ballmaier" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:19 #: ../../source/changelog/0.6.0-changelog.rst:52 msgid "Aron" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:20 #: ../../source/changelog/0.6.0-changelog.rst:53 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:21 #: ../../source/changelog/0.6.0-changelog.rst:54 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:22 msgid "Deniz Hasler +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:23 #: ../../source/changelog/0.6.0-changelog.rst:56 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:24 msgid "Elisha Hollander +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:25 msgid "Erik Tastepe +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:26 #: ../../source/changelog/0.6.0-changelog.rst:60 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:27 #: ../../source/changelog/0.6.0-changelog.rst:61 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:28 #: ../../source/changelog/0.6.0-changelog.rst:63 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:29 #: ../../source/changelog/0.6.0-changelog.rst:64 msgid "Mark Miller" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:30 #: ../../source/changelog/0.6.0-changelog.rst:65 msgid "Mohammad Al-Fetyani" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:31 #: ../../source/changelog/0.6.0-changelog.rst:66 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:32 msgid "Newell Jensen +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:33 msgid "Nidhal Baccouri +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:34 msgid "Nikhil Garuda +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:35 msgid "Peilonrayz +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:36 #: ../../source/changelog/0.6.0-changelog.rst:71 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:37 msgid "Ricky Chon +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:38 #: ../../source/changelog/0.6.0-changelog.rst:73 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:39 msgid "kamilczerwinski22 +" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:40 #: ../../source/changelog/0.6.0-changelog.rst:74 msgid "sparshg" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:43 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:46 msgid "Aathish Sivasubrahmanian" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:49 msgid "Adam Ryczkowski" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:50 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:55 msgid "Deniz Hasler" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:57 msgid "Elisha Hollander" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:58 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:59 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:62 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:67 msgid "Nidhal Baccouri" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:68 msgid "Nikhil Garuda" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:69 msgid "Oliver" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:70 msgid "Philipp Imhof" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:72 msgid "Ricky Chon" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:77 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:79 msgid "A total of 112 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:82 msgid "Breaking changes" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:85 msgid ":pr:`1347`: Restructure vector_field module and add documentation" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:85 msgid ":class`~.VectorField` is renamed to :class:`~.ArrowVectorField` and a new class :class:`~.VectorField` is added as a superclass for :class:`~.ArrowVectorField` and :class:`~.StreamLines`. :class:`~.AnimatedStreamLines` is removed. It's functionality is moved to :class:`~.StreamLines`. Added a lot of new options when working with vector fields. :class:`~.ShowPassingFlashWithThinningStrokeWidth` was moved to the indication module." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:91 msgid ":pr:`1161`: Upgrades to CoordinateSystem and graphing." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:88 msgid "Breaking changes were introduced to :class:`~.Axes`, :class:`~.ThreeDAxes`, :class:`~.NumberPlane` and :class:`~.NumberLine` All the above now use lists to construct their ranges as opposed to explicitly defining these values. `x_range` has replaced `x_min`, `x_max` and defining the step is much easier with `x_step` --> ``x_range`` : ``[x_min, x_max, x_step]``. There were also many upgrades to these classes which improve their functionality and appearance." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:91 msgid "``NumberLineOld`` was introduced to continue support for :class:`~.GraphScene`, although we are moving away from GraphScene and intend to deprecate it in a future release." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:107 msgid ":pr:`1013`: Refactored the Command Line Interface to use Click instead of Argparse" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:94 msgid "This change breaks the CLI API to organize the structure of Manim Community's commands, options, and arguments." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:96 msgid "To be more in line with POSIX compliant CLI conventions, options for commands are given *BEFORE* their arguments. In Argparse: ``manim basic.py -p -ql`` With Click: ``manim -p -ql basic.py``" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:100 msgid "Although this is primarily a refactor and most of the common options are still there, some options have been added/removed. Use the ``manim`` command's ``--help`` option, or simply run the command without providing options/arguments to view the help page with the full list of subcommands/options/arguments." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:102 msgid "Added a ``--fps``/``--frame_rate`` option which allows for custom fps that don't have to be integer (i.e. 29.97, 23.98, etc.). Users no longer have to specify the FPS from within a config file. Additionally, the ``--webgl_renderer_fps`` option has been removed. Use ``--fps`` or ``--frame_rate`` instead." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:103 msgid "Added a ``--renderer`` option which you can use to select your choice of renderer (e.g. ``--renderer=opengl``). There are currently *THREE* renderers to choose from!" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:104 msgid "Removed the ``--background_color`` option. Reassigned the ``--background_color`` option's shorthand ``-c`` to ``--config_file``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:105 msgid "Removed the ``--leave_progress_bars`` option. Use ``--progress_bars=leave`` instead." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:106 msgid "Removed the deprecated render quality flags, in particular: ``-l``, ``-m``, ``-h``, ``-k``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:107 msgid "Removed the ``--sound`` option. It lost support long ago with the removal of SoX." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:110 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:116 msgid ":pr:`1431`: Fix CLI bugs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:113 msgid "Fixed conflict with ``-f`` which was previously assigned to both ``--show_in_file_browser`` and ``--format`` by removing ``-f`` from ``--format``. A warning is issued that ``-f`` will soon move to ``--format``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:114 msgid "Added back in flags to render the files as gif/last frame. Deprecated them in favor of ``--format``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:115 msgid "Fixed the broken ``--output_file``/``-o`` option." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:116 msgid "Fixed an issue where the ``-qh`` quality option was interpreted as ``-q`` ``-h``, prompting the help page." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:118 msgid ":pr:`1354`: Refactored a few functions in space_ops.py, deprecated :func:`~.angle_between`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:122 msgid ":pr:`1370`: Remove TexMobject and TextMobject" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:122 msgid "TexMobject and TextMobject have been deprecated for a while, they are now fully removed. Use Tex or MathTex instead." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:124 msgid ":pr:`1349`: Removed the deprecated ``SmallDot`` mobject" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:127 msgid ":pr:`1259`: Removed deprecated CairoText class" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:130 msgid "New features" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:132 msgid ":pr:`1386`: Implement utility methods for adding/removing vertices and edges of graphs; allow custom mobjects as vertices" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:136 msgid ":pr:`1385`: Added :meth:`~.Axes.get_line_graph` for plotting a line graph" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:136 msgid "Added :meth:`~.Axes.get_line_graph` that returns a line graph from lists of points along x, y and z (optional) axes." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:139 msgid ":pr:`1381`: Hot reloading for the OpenGL renderer" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:139 msgid "Rerun scene when the input file is modified" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:148 msgid ":pr:`1383`: Overhaul of the :mod:`~.animation.indication` module interfaces" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:142 msgid "Added class `Circumscribe` combining functionality of `CircleIndicate`, `AnimationOnSurroundingRectangle`, `ShowPassingFlashAround`, `ShowCreationThenDestructionAround`, `ShowCreationThenFadeAround`, which have all been deprecated." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:143 msgid "Changes to `Flash`: `flash_radius` parameter now defines inner radius of the animation. Added new parameter `time_width`." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:144 msgid "`ShowCreationThenDestruction` has been deprecated in favor of `ShowPassingFlash`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:145 msgid "Changes to `ApplyWave`: New implementation giving more flexibility with new parameters `wave_func`, `time_width` and`ripples`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:146 msgid "Renamed `WiggleOutThenIn` to `Wiggle` (`WiggleOutThenIn` has been deprecated)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:147 msgid "Added documentation and examples to all the above" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:148 msgid "Other minor enhancements and bug-fixes" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:150 msgid ":pr:`1348`: Added :class:`~.Polyhedron`, and platonic solids :class:`~.Tetrahedron`, :class:`~.Octahedron`, :class:`~.Icosahedron` and :class:`~.Dodecahedron`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:154 msgid ":pr:`1285`: Add :meth:`~.Scene.interactive_embed` for OpenGL rendering" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:154 msgid ":meth:`~.Scene.interactive_embed` allows interaction with Scene via mouse and keyboard as well as dynamic commands via an iPython terminal." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:157 msgid ":pr:`1261`: Render image automatically if no animation is played in a scene" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:157 msgid "If no animations in scene and asked to preview/render a video, preview/render an image instead of raising a confusing error." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:160 msgid ":pr:`1200`: Add text and SVG mobjects to OpenGL" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:160 msgid "Added OpenGL-compatible text and SVG mobjects" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:163 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:166 msgid ":pr:`1398`: Fix and enhance `Mobject.arrange_in_grid`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:166 msgid "`arrange_in_grid` now actually arranges submobjects in a grid. Added new parameters `buff`, `cell_alignment`, `row_alignments`, `col_alignments`, `row_heights`, `col_widths`, `flow_order`." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:168 msgid ":pr:`1407`: Fix bug and rename :meth:`vector_coordinate_label` to :meth:`~.Vector.coordinate_label` and move it to :class:`geometry.py`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:171 msgid ":pr:`1380`: Allow image objects as background images" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:175 msgid ":pr:`1391`: Add `path_arc` support to `.animate` syntax" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:175 msgid "The parameter `path_arc` of :class:`~.Transform` now works with the `.animate` syntax" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:178 msgid ":pr:`1364`: Added :meth:`~.Mobject.match_points`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:178 msgid "Added :func:`~.Mobject.match_points`, which transforms the points, positions and submobjects of a Mobject to match that of the other while keeping style unchanged." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:180 msgid ":pr:`1363`: Change of TeX compiler and output file format" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:184 msgid ":pr:`1359`: Make FILE a required argument" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:184 msgid "Make `FILE` a required argument, `manim/cli/render/commands.py`:L30" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:186 msgid ":pr:`1304`: Improve Tex string splitting at double braces: only split for double brace groups" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:190 msgid ":pr:`1340`: Add OpenGL support to the new transform animations" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:190 msgid "Made `FadeTransform`, `FadeTransformPieces`, `TransformMatchingShapes` and `TransformMatchingTex` compatible with OpenGL rendering." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:193 msgid ":pr:`1343`: Make TexTemplate() simple, but keep Tex()'s default template" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:193 msgid "TexTemplate() now returns a simple tex template." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:195 msgid ":pr:`1321`: Add OpenGL support to :class:`~.AnimationGroup`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:200 msgid ":pr:`1302`: Raise appropriate errors in :meth:`~.VMobject.point_from_proportion`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:199 msgid "Raise an error if the ``alpha`` argument is not between 0 and 1." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:200 msgid "Raise an error if the :class:`~.VMobject` has no points." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:202 msgid ":pr:`1315`: Fix performance issues with :meth:`~.VMobject.get_arc_length`, stemming from :pr:`1274`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:205 msgid ":pr:`1320`: Add `jpeg` extension to the default image extensions" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:209 msgid ":pr:`1234`: Added new method :meth:`~.Mobject.get_midpoint`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:209 msgid "Implemented :meth:`~.Mobject.get_midpoint` to return the point that is the middle of the stroke line of an mobject." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:211 msgid ":pr:`1237`: Notify user if they are using an outdated version of Manim" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:214 msgid ":pr:`1308`: Improved :class:`~.ManimBanner` animations" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:217 msgid ":pr:`1275`: Add SVG element support to :class:`~.SVGMobject`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:220 msgid ":pr:`1238`: Add parameter ``about_point`` for :meth:`~.Mobject.rotate`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:223 msgid ":pr:`1260`: Change Brace from Tex to SVG (#1258)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:226 msgid ":pr:`1122`: Support for specifying the interpolation algorithms for individual ImageMobjects" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:229 msgid ":pr:`1283`: Set default value of keyword ``random_seed`` in :class:`~.Scene` to ``None`` (was 0 and fixed before)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:236 msgid ":pr:`1220`: Added sanity checks to :meth:`~.Mobject.add_to_back` for Mobjects" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:233 msgid "Add Mobject `add_to_back` sanity checks: - Raises ValueError when Mobject tries to add itself - Raises TypeError when a non-Mobject is added - Filters out incoming duplicate submobjects if at least one instance of that submobject exists in the list" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:239 msgid ":pr:`1249`: Set corners of :class:`~.Rectangle` in counterclockwise direction" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:239 msgid "This improves the look of transformations between rectangles and other simple mobjects." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:241 msgid ":pr:`1248`: Add Copy function to TexTemplate" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:245 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:247 msgid ":pr:`1368`: Added a check to ensure checking for the latest version was successful" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:251 msgid ":pr:`1413`: Prevent duplication of the same mobject when adding to submobjects via :meth:`~.Mobject.add_to_back`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:251 msgid "Fixes #1412" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:253 msgid ":pr:`1395`: SVG transforms now handle exponent notation (6.02e23)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:256 msgid ":pr:`1355`: Rewrite `put_start_and_end_on` to work in 3D" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:259 msgid ":pr:`1346`: Fixed errors introduced by stray print in :class:`~.MathTex`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:262 msgid ":pr:`1305`: Automatically remove long tick marks not within the range of the :class:`~NumberLine`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:265 msgid ":pr:`1296`: Fix random pipeline TeX failures" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:270 msgid ":pr:`1274`: Fix :meth:`~.VMobject.point_from_proportion` to account for the length of curves." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:269 msgid "Add :meth:`~.VMobject.get_nth_curve_function_with_length` and associated functions." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:270 msgid "Change :meth:`~.VMobject.point_from_proportion` to use these functions to account for curve length." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:273 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:277 msgid ":pr:`1430`: Un-deprecated GraphScene (will be deprecated later), fixed an old-style call to NumberPlane" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:276 msgid "More work is required in order to fully replace `GraphScene` via `Axes`, thus `GraphScene` is not deprecated yet." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:277 msgid "Fixed one example in which the old `NumberPlane` syntax was used." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:279 msgid ":pr:`1425`: Added a \"How to Cite Manim\" section to the Readme" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:283 msgid ":pr:`1387`: Added Guide to Contribute Examples from GitHub Wiki to Documentation" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:283 msgid "Added a Guide" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:285 msgid ":pr:`1424`: Fixed all current docbuild warnings" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:288 msgid ":pr:`1389`: Adding Admonitions Tutorial to docs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:291 msgid ":pr:`1341`: Reduce complexity of ThreeDSurfacePlot example" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:294 msgid ":pr:`1362`: Quick reference to modules" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:298 msgid ":pr:`1376`: Add flake8 and isort in docs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:298 msgid "added 'flake8' and 'isort' usages to docs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:301 msgid ":pr:`1360`: Grammatical error corrections in documentation" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:301 msgid "changed a few sentences in docs/source" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:303 msgid ":pr:`1351`: Some more typehints" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:306 msgid ":pr:`1358`: Fixed link to installation instructions for developers" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:309 msgid ":pr:`1338`: Added documentation guidelines for type hints" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:312 msgid ":pr:`1342`: Multiple ValueTracker example for docs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:315 msgid ":pr:`1210`: Added tutorial chapter on coordinates of an mobject" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:318 msgid ":pr:`1335`: Added import statements to examples in documentation" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:321 msgid ":pr:`1245`: Added filled angle Example" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:324 msgid ":pr:`1328`: Docs: Update Brace example" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:327 msgid ":pr:`1326`: Improve documentation of :class:`~.ManimMagic` (in particular: fix documented order of CLI flags)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:330 msgid ":pr:`1323`: Blacken Docs Strings" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:333 msgid ":pr:`1300`: Added typehints for :class:`~.ValueTracker`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:336 msgid ":pr:`1301`: Added further docstrings and typehints to :class:`~.Mobject`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:339 msgid ":pr:`1298`: Add double backquotes for rst code samples (value_tracker.py)" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:343 msgid ":pr:`1297`: Change docs to use viewcode extension instead of linkcode" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:343 msgid "Switched ``sphinx.ext.linkcode`` to ``sphinx.ext.viewcode`` and removed ``linkcode_resolve`` in ``conf.py``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:345 msgid ":pr:`1246`: Added docstrings for :class:`~.ValueTracker`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:348 msgid ":pr:`1251`: Switch documentation from guzzle-sphinx-theme to furo" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:351 msgid ":pr:`1232`: Further docstrings and examples for :class:`~.Mobject`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:354 msgid ":pr:`1291`: Grammar improvements in README.md" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:357 msgid ":pr:`1269`: Add documentation about :meth:`~.set_color_by_tex`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:360 msgid ":pr:`1284`: Updated readme by providing the correct link to the example_scenes" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:363 msgid ":pr:`1029`: Added example jupyter notebook into the examples folders" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:367 msgid ":pr:`1279`: Added sphinx requirements to pyproject.toml" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:367 msgid "New contributors who wanted to build the sphinx documentation had an extra step that could be removed by making use of ``poetry install``. This removes the developer's need for ``pip install -r requirements.txt``." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:369 msgid ":pr:`1268`: Added documentation explaining the differences between manim versions" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:372 msgid ":pr:`1247`: Added warning for the usage of `animate`" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:375 msgid ":pr:`1242`: Added an example for the manim colormap" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:378 msgid ":pr:`1239`: Add TinyTex installation instructions" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:381 msgid ":pr:`1231`: Improve changelog generation script" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:385 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:387 msgid ":pr:`1299`: Red pixels (different value) now appear over green pixels (same value) in GraphicalUnitTest" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:391 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:394 msgid ":pr:`1436`: Cache poetry venv with `pyproject.toml` hash in key" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:394 msgid "Cache poetry venv with `pyproject.toml` hash in key" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:397 msgid ":pr:`1435`: CI: Update poetry cache when new version is released" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:397 msgid "Fix `test_version` failure in CI when using cached poetry venv" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:399 msgid ":pr:`1427`: Add URL's to pyproject.toml" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:402 msgid ":pr:`1421`: Updated changelog generator's labels and removed pre-commit bot from changelog" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:405 msgid ":pr:`1339`: CI: Fix macOS installation error from creating file in read-only file system" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:409 msgid ":pr:`1257`: CI: Caching ffmpeg, tinytex dependencies and poetry venv" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:409 msgid "CI: Caching ffmpeg, tinytex dependencies and poetry venv" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:411 msgid ":pr:`1294`: Added mixed-line-ending to .pre-commit-config.yaml" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:414 msgid ":pr:`1278`: Fixed flake8 errors and removed linter/formatter workflows" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:417 msgid ":pr:`1270`: Added isort to pre_commit file" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:422 msgid ":pr:`1263`: CI: Turn off experimental installer for poetry to fix installation errors" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:421 msgid "Turn off experimental installer for poetry to prevent manim installation errors for packages." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:422 msgid "Downgrade py39 to py38 for flake checks as `pip` does not enjoy py39, along with `poetry`." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:425 msgid ":pr:`1255`: CI: Fix macOS pipeline failure" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:425 msgid "Update `ci.yml` to update and upgrade brew if necessary before installing dependencies, and remove the unsupported `dvisvgm.86_64-darwin` package." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:427 msgid ":pr:`1254`: Removed the comment warning that GitHub doesn't allow uploading video in the issue templates." msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:430 msgid ":pr:`1216`: Use actions/checkout for cloning repository; black-checks" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:433 msgid ":pr:`1235`: Fixed version of decorator at <5.0.0" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:437 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:439 msgid ":pr:`1411`: Change `Union[float, int]` to just `float` according to PEP 484" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:442 msgid ":pr:`1241`: Type Annotations: Fixing errors showing up in static type checking tool mypy" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:446 msgid ":pr:`1319`: Fix mean/meant typo" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:446 msgid "Fix typo in docs" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:448 msgid ":pr:`1313`: Singular typo fix on the Quickstart page in documentation" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:452 msgid ":pr:`1292`: Remove unnecessary imports from files" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:452 msgid "Imports reduced in a bunch of files" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:454 msgid ":pr:`1295`: Fix grammar and typos in the CODE OF CONDUCT" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:458 msgid ":pr:`1293`: Minor fixes - reduce lines" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:458 msgid "Remove unnecessary lines" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:460 msgid ":pr:`1281`: Remove all Carriage Return characters in our files" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:463 msgid ":pr:`1178`: Format Imports using Isort" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:466 msgid ":pr:`1233`: Fix deprecation warning for ``--use_opengl_renderer`` and ``--use_webgl_renderer``" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:469 msgid ":pr:`1282`: Fix typing hints in vectorized_mobject.py based on mypy" msgstr "" #: ../../source/changelog/0.6.0-changelog.rst:473 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.7.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.7.0-changelog.rst:3 msgid "v0.7.0" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:5 msgid "June 01, 2021" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:10 msgid "A total of 45 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:14 msgid "André +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:15 #: ../../source/changelog/0.7.0-changelog.rst:53 msgid "Anton Ballmaier" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:16 #: ../../source/changelog/0.7.0-changelog.rst:55 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:17 msgid "Clar Fon" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:18 #: ../../source/changelog/0.7.0-changelog.rst:56 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:19 #: ../../source/changelog/0.7.0-changelog.rst:57 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:20 #: ../../source/changelog/0.7.0-changelog.rst:59 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:21 msgid "Iced-Tea3 +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:22 #: ../../source/changelog/0.7.0-changelog.rst:61 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:23 #: ../../source/changelog/0.7.0-changelog.rst:62 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:24 msgid "Jerónimo Squartini +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:25 #: ../../source/changelog/0.7.0-changelog.rst:64 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:26 #: ../../source/changelog/0.7.0-changelog.rst:65 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:27 msgid "Max Stoumen +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:28 #: ../../source/changelog/0.7.0-changelog.rst:67 msgid "Mohammad Al-Fetyani" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:29 #: ../../source/changelog/0.7.0-changelog.rst:68 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:30 msgid "NeoPlato" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:31 msgid "Newell Jensen" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:32 #: ../../source/changelog/0.7.0-changelog.rst:69 msgid "Nikhil Garuda" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:33 msgid "Nikhil Sharma +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:34 msgid "PaulCMurdoch +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:35 #: ../../source/changelog/0.7.0-changelog.rst:71 msgid "Philipp Imhof" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:36 #: ../../source/changelog/0.7.0-changelog.rst:72 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:37 msgid "Robert West +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:38 msgid "Ryan McCauley +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:39 msgid "Skaft +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:40 msgid "SwiddisZwei +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:41 msgid "e4coder +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:42 #: ../../source/changelog/0.7.0-changelog.rst:78 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:43 msgid "malte-v +" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:44 #: ../../source/changelog/0.7.0-changelog.rst:79 msgid "ralphieraccoon" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:45 #: ../../source/changelog/0.7.0-changelog.rst:80 msgid "sparshg" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:48 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:51 msgid "Aathish Sivasubrahmanian" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:52 msgid "Abhijith Muthyala" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:54 msgid "Aron" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:58 msgid "GameDungeon" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:60 msgid "Iced-Tea3" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:63 msgid "Jerónimo Squartini" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:66 msgid "Mark Miller" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:70 msgid "Oliver" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:73 msgid "Ricky Chon" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:74 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:75 msgid "Skaft" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:76 msgid "SwiddisZwei" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:77 msgid "e4coder" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:83 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:85 msgid "A total of 87 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:88 msgid "Breaking changes" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:92 msgid ":pr:`1521`: Improve :class:`~.Animation` docs" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:91 msgid "Improve documentation of the :class:`~.Animation` class." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:92 msgid "Unify the signature of ``get_all_mobjects``. Now it always returns a sequence of :class:`Mobjects <.Mobject>`. This breaks using ``FadeTransform.get_all_mobjects`` as ``Group``." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:95 msgid ":pr:`1470`: Drop support for Python 3.6" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:95 msgid "Manim won't work on Python 3.6 anymore." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:98 msgid "Highlights" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:100 msgid ":pr:`1447`: Added :class:`~.PolarPlane` for polar coordinates." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:109 msgid ":pr:`1490`: Added :class:`~.Polygram`, rework the polygon inheritance tree, and add :class:`~.Star`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:104 msgid "Add :class:`~.Polygram`, a generalized :class:`~.Polygon` that allows for disconnected sets of edges." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:105 msgid "Make :class:`~.Polygon` inherit from :class:`~.Polygram`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:106 msgid "Add :func:`~.regular_vertices`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:107 msgid "Add :class:`~.RegularPolygram`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:108 msgid "Make :class:`~.RegularPolygon` inherit from :class:`~.RegularPolygram`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:109 msgid "Add :class:`~.Star`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:112 msgid ":pr:`1462`: OpenGL: Added :class:`~.Shader`, :class:`~.Mesh`, and :class:`~.FullScreenQuad`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:112 msgid "Add Shader and Mesh objects" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:117 msgid ":pr:`1418`: Added project management commands" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:115 msgid "``manim init`` - quickly sets up default files for a manim project." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:116 msgid "``manim new project`` - lets the user set project settings. It also creates the project inside a new folder of name " msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:117 msgid "``manim new scene`` - used to quickly insert new scenes into files. If ``file name`` is not provided ``main.py`` is used as default." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:120 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:123 msgid ":pr:`1598`: Update examples to use :class:`~.Axes` and deprecate :class:`~.GraphScene`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:123 msgid ":class:`~.GraphScene` has been deprecated and its functionality has been shifted to :class:`~.Axes`. See the updated example gallery for sample usage." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:126 msgid ":pr:`1454`: Fading module enhancements" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:126 msgid "Moved functionality of all Fading classes to :class:`~.FadeIn` and :class:`~.FadeOut`. All other fading classes have been deprecated." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:128 msgid ":pr:`1375`: Deleted the deprecated ``ShowCreation`` in favor of :class:`~.Create`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:132 msgid "New features" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:134 msgid ":pr:`1566`: Added the ability to add gridlines to a :class:`~.Rectangle`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:137 msgid ":pr:`1548`: Added :class:`~.ArcBrace`, a subclass of :class:`~.Brace`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:141 msgid ":pr:`1559`: Update VGroup to support item assignment (#1530)" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:141 msgid "Support indexed item-assignment for VGroup" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:143 msgid ":pr:`1518`: Allow fading multiple Mobjects in one Animation" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:146 msgid ":pr:`1422`: Added :func:`~.override_animation` decorator" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:154 msgid ":pr:`1504`: Color module enhancements" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:150 msgid "Replaced ``BLUE_E`` with what was previously ``DARK_BLUE`` and removed ``DARK_BLUE``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:151 msgid "Added alias ``LIGHTER_GRAY`` for ``GRAY_A``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:152 msgid "Added ``PURE_RED``, ``PURE_BLUE`` and renamed ``GREEN_SCREEN`` to ``PURE_GREEN``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:153 msgid "All gray colors are now also available using British spelling (including ``GREY_BROWN``)" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:154 msgid "Replaced color example in the docs. It can now be used as a quick reference for all color names." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:156 msgid ":pr:`1272`: Implement metaclass approach in geometry module to make mobjects compatible with cairo and opengl rendering" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:160 msgid ":pr:`1404`: Added two deprecation decorators" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:160 msgid "Added two function decorators ``deprecated`` and ``deprecated_params`` as a consistent way of deprecating code." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:163 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:165 msgid ":pr:`1572`: OpenGL compatibility via metaclass: :class:`~.TracedPath`, :class:`~.ParametricFunction`, :class:`~.Brace`, :class:`~.VGroup`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:168 msgid ":pr:`1472`: Porting methods from :class:`~.GraphScene` to :class:`~.CoordinateSystem`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:171 msgid ":pr:`1589`: OpenGL compatibility via metaclass: :class:`~.ValueTracker`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:175 msgid ":pr:`1564`: Add extra notes for TeX compilation errors" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:175 msgid "Add hint to use custom ``TexTemplate`` on TeX compilation errors" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:177 msgid ":pr:`1584`: Added a check for ``0`` in :meth:`~.round_corners`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:181 msgid ":pr:`1586`: Add OpenGLMobject support to all ``isinstance`` occurrences" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:181 msgid "This PR increases the support for OpenGL in the remaining animation classes and in other places where appropriate." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:183 msgid ":pr:`1577`: Added new metaclass ConvertToOpenGL (replacing MetaVMobject), restore IntelliSense" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:187 msgid ":pr:`1562`: Improved VectorField's Nudge Accuracy Per Step" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:187 msgid "Implemented the Runge-Kutta algorithm in VectorField's nudge function. This increases the accuracy as an object moves along a vector field. This also increases efficiency as the nudge function requires less loops to achieve accuracy than the previous implementation." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:189 msgid ":pr:`1480`: Add logging info to tex errors" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:194 msgid ":pr:`1567`: Compatibility Fixes with ManimPango v0.3.0" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:193 msgid "ManimPango v0.3.0+ is required for Manim now." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:194 msgid "Show errors from Pango when Markup isn't correct" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:196 msgid ":pr:`1512`: OpenGL compatibility via metaclass: graph" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:199 msgid ":pr:`1511`: OpenGL compatibility via metaclass: svg_mobject, text_mobject, tex_mobject" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:202 msgid ":pr:`1502`: Added ``center`` parameter to :class:`~.Sphere` and ``point`` parameter to :class:`~.Dot3D`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:206 msgid ":pr:`1486`: Update of ``rate_functions``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:206 msgid "Changed the picture for the non standard rate functions." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:208 msgid ":pr:`1495`: Ported value_tracker to OpenGL" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:212 msgid ":pr:`1382`: Expand documentation, testing, and functionality of ValueTrackers; remove ExponentialValueTracker" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:212 msgid "Added more documentation and inline operators to ValueTracker and ComplexValueTracker. Brought coverage for value_tracker.py to 100%. Removed ExponentialValueTracker." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:214 msgid ":pr:`1475`: Add SVG elliptical arc support" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:218 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:220 msgid ":pr:`1574`: Fixed error when processing SVG with omitted elliptical arc command" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:226 msgid ":pr:`1596`: Fix indexing for non-whitespace tex arg separator" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:224 msgid "Fixes #1568" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:226 msgid "Fix issue when setting the arg_separator of a Tex object as a non-whitespace character(s). The method `break_up_by_substrings(self)` was not accounting for the separator when setting the index." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:228 msgid ":pr:`1588`: Fixed multiple animations being saved in the same file" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:231 msgid ":pr:`1571`: Fix tests after introducing parallelization" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:234 msgid ":pr:`1545`: Fix outdated parameters for :class:`LinearTransformationScene` and add an example + typing." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:239 msgid ":pr:`1513`: Fixed rotation of gradients while rotating a VMobject" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:238 msgid "Fixed the direction of gradient which remained the same while rotating VMobjects" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:239 msgid "Added ``rotate_sheen_direction()`` method in VMobject" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:241 msgid ":pr:`1570`: Output errors to stderr" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:244 msgid ":pr:`1560`: Declare ``*.npz`` ``*.wav`` ``*.png`` as binary in ``.gitattributes``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:248 msgid ":pr:`1211`: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:248 msgid "Refactored internal scene-caching mechanism and fixed bug when an inconsistent hash was produced when copying a mobject." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:250 msgid ":pr:`1527`: Improved handling of substring isolation within sqrt, and fixed a bug with transform_mismatch for the matching shape transforms" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:253 msgid ":pr:`1526`: Fix fading" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:256 msgid ":pr:`1523`: Fix multiple FadeIn / Out only working on VMobjects" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:260 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:262 msgid ":pr:`1599`: Added example for :class:`~.Annulus`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:265 msgid ":pr:`1415`: New example for gallery and some docs refinements" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:271 msgid ":pr:`1509`: Copyedited Documentation" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:269 msgid "Added a link to Manim Community GitHub page in ``for_dev.rst``. Fixed :meth:`~.Mobject.get_start` and added ``roll`` link in ``building_blocks-rst`` Added language to code blocks in ``configuration.rst``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:274 msgid ":pr:`1384`: Added typings to space_ops.py" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:274 msgid "Added Typehints to most of the functions" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:276 msgid ":pr:`1500`: Example for :meth:`~.apply_complex_function`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:279 msgid ":pr:`1551`: Fixed the typo for Admonitions" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:282 msgid ":pr:`1550`: Restructuring of Contribution Section" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:285 msgid ":pr:`1541`: Fixing broken links and other minor doc things" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:288 msgid ":pr:`1516`: Update docs to use ``t_range`` instead of ``t_min`` and ``t_max`` in :class:`~.ParametricFunction`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:291 msgid ":pr:`1508`: Update troubleshooting docs" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:294 msgid ":pr:`1485`: Added :class:`~.Title` example for the docs" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:297 msgid ":pr:`1439`: Cleaning ``Sequence`` typehints" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:300 msgid ":pr:`1440`: Added Scoop installation docs (Windows)" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:303 msgid ":pr:`1452`: Refine typehints at :class:`~.Angle`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:306 msgid ":pr:`1458`: Refine docs of :class:`~.Text` ( add ``disable_ligatures=True`` for t2c)" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:309 msgid ":pr:`1449`: Added :class:`~.PointCloudDot` example" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:312 msgid ":pr:`1473`: Added easy example for :meth:`~.arrange_in_grid`" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:315 msgid ":pr:`1402`: Added typestring parser checker" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:318 msgid ":pr:`1451`: Reduce complexity of AngleExample" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:322 msgid ":pr:`1441`: Add inheritance diagrams to reference page" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:322 msgid "Added inheritance diagrams to the reference page as a quick navigation method." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:324 msgid ":pr:`1457`: Fixing broken doc links" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:327 msgid ":pr:`1445`: Remove $ from tutorial commands" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:331 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:333 msgid ":pr:`1556`: Try pytest-xdist for parallelization in tests" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:337 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:340 msgid ":pr:`1505`: Add docs reference to PR template" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:340 msgid "Added documentation link to the Pull Request Template." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:342 msgid ":pr:`1499`: Updated Discord links in the docs to point towards a standardized redirect" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:345 msgid ":pr:`1461`: Build the docs - Logging" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:348 msgid ":pr:`1481`: pyproject.toml: poetry_core -> poetry-core" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:351 msgid ":pr:`1477`: Update RDT sphinx package to version 3.5.3" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:354 msgid ":pr:`1460`: Create CONTRIBUTING.md" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:358 msgid ":pr:`1453`: manim_directive: fix image links in docs - Windows" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:358 msgid "Use POSIX path on Windows to link images so documentation can build locally." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:361 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:363 msgid ":pr:`1465`: Added typings and description to some functions in :mod:`~.coordinate_systems`." msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:367 msgid ":pr:`1552`: Removed unwanted parameters in geometry" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:367 msgid "Removed ``anchors_span_full_range``, ``close_new_points``, ``anchors_span_full_range``, ``preserve_tip_size_when_scaling``, ``mark_paths_closed`` and ``close_new_points``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:369 msgid ":pr:`1597`: Removed hilite_me and insert_line_numbers_in_html from global name space" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:372 msgid ":pr:`1535`: Update dependencies and fix tests" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:375 msgid ":pr:`1544`: Adding spell checker as a pre-commit hook" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:378 msgid ":pr:`1542`: Swapping a pango markup link in docs" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:381 msgid ":pr:`1531`: Don't use deprecated methods in deprecation.py" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:384 msgid ":pr:`1492`: Remove stray print statements introduced in #1404" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:387 msgid ":pr:`1471`: Fix Some Warnings from lgtm" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:391 msgid "Changes that needed to be reverted again" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:393 msgid ":pr:`1606`: Bring back ``DARK_BLUE``" msgstr "" #: ../../source/changelog/0.7.0-changelog.rst:397 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.8.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.8.0-changelog.rst:3 msgid "v0.8.0" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:5 msgid "July 02, 2021" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:10 msgid "A total of 37 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:14 #: ../../source/changelog/0.8.0-changelog.rst:51 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:15 msgid "Bill Shillito +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:16 msgid "Darigov Research +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:17 #: ../../source/changelog/0.8.0-changelog.rst:53 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:18 #: ../../source/changelog/0.8.0-changelog.rst:54 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:19 msgid "Iced-Tea3" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:20 #: ../../source/changelog/0.8.0-changelog.rst:55 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:21 #: ../../source/changelog/0.8.0-changelog.rst:56 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:22 #: ../../source/changelog/0.8.0-changelog.rst:57 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:23 #: ../../source/changelog/0.8.0-changelog.rst:58 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:24 msgid "MathInvariance +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:25 msgid "Max Stoumen" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:26 msgid "Mehmet Ali Özer +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:27 msgid "Michael Pilosov +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:28 #: ../../source/changelog/0.8.0-changelog.rst:61 msgid "Mohammad Al-Fetyani" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:29 #: ../../source/changelog/0.8.0-changelog.rst:62 msgid "Naveen M K" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:30 #: ../../source/changelog/0.8.0-changelog.rst:63 msgid "Nikhil Garuda" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:31 #: ../../source/changelog/0.8.0-changelog.rst:64 msgid "Oliver" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:32 msgid "PaulCMurdoch" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:33 #: ../../source/changelog/0.8.0-changelog.rst:65 msgid "Philipp Imhof" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:34 msgid "PipedQuintes +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:35 #: ../../source/changelog/0.8.0-changelog.rst:66 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:36 #: ../../source/changelog/0.8.0-changelog.rst:67 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:37 msgid "Ujjayanta +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:38 msgid "Vagrid +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:39 msgid "andrehisatsuga +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:40 #: ../../source/changelog/0.8.0-changelog.rst:70 msgid "friedkeenan" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:41 msgid "peaceheis +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:42 msgid "yit6 +" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:45 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:48 msgid "Abhijith Muthyala" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:49 msgid "Anton Ballmaier" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:50 msgid "Aron" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:52 msgid "Clar Fon" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:59 msgid "Mark Miller" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:60 msgid "MathInvariance" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:68 msgid "Ujjayanta" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:69 msgid "Vagrid" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:73 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:75 msgid "A total of 76 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:78 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:80 msgid ":pr:`1616`: Remove all functions and classes that were deprecated until ``v0.6.0``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:84 msgid "New features" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:87 msgid ":pr:`1716`: Rewrite stroke and fill shaders" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:87 msgid "Rewrite vectorized mobject shaders to be compatible with transformation matrices." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:90 msgid ":pr:`1695`: Add option to justify text with :class:`~.MarkupText`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:90 msgid "A new parameter ``justify`` is added to :class:`~.MarkupText`. It can be used to justify a paragraph of text." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:94 msgid ":pr:`1660`: Added support for ``.webm`` and transparency of videos in Jupyter notebooks" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:93 msgid "Added support for generating ``webm`` videos via the command line flag ``--format=webm``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:94 msgid "Added transparency support for Jupyter notebooks" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:96 msgid ":pr:`1553`: Add dearpygui integration" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:100 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:102 msgid ":pr:`1728`: Improved positioning and size of the OpenGL window; added some configuration options" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:105 msgid ":pr:`1733`: Let OpenGLMobject.copy return a deep copy by default" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:108 msgid ":pr:`1735`: Metaclass compatibility for `coordinate_system.py`, `Code` and `ParametricSurface`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:111 msgid ":pr:`1585`: OpenGL compatibility via metaclass for :class:`~.Matrix`, :class:`~.DecimalNumber`, :class:`~.Variable`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:114 msgid ":pr:`1713`: Exit the command line interface gracefully if no scene was chosen" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:119 msgid ":pr:`1652`: Refactored :class:`~.Mobject` and :class:`~.Scene` to no longer inherit from the abstract base class ``Container``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:118 msgid "Moved tests in ``test_container.py`` for :class:`Container` that test :class:`~.Scene` and :class:`~.Mobject` to their own files." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:119 msgid "Corrected various instances of incorrectly passed keyword arguments, or unused keyword arguments." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:121 msgid ":pr:`1693`: Made the default arrowhead size for :class:`~.Arrow3D` smaller" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:127 msgid ":pr:`1678`: Allow some rate functions to assume values outside of [0, 1]; introduce clamping decorators" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:125 msgid "Fixed animations so that certain rate functions (``running_start``, ``wiggle``, ``ease_in_back``, ``ease_out_back``, ``ease_in_out_back``, ``ease_in_elastic``, ``ease_out_elastic``, and ``ease_out_elastic``) can go outside the range from 0 to 1." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:126 msgid "Fixed lag ratios so that they're spaced out evenly within the time interval and the rate functions are applied to each animation individually, rather than having the rate function determine when the animation starts." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:127 msgid "Fixed faulty code for ``ease_in_out_expo``, ``ease_in_bounce``, ``ease_out_bounce``, and ``ease_in_out_bounce``." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:129 msgid ":pr:`1649`: Made video file names in Jupyter notebook more readable" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:133 msgid ":pr:`1667`: Determine the default number of decimal places for :class:`~.NumberLine` labels automatically from the step size" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:133 msgid "As an example: If the step size is set to 0.5, labels will now show at least one decimal place." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:135 msgid ":pr:`1608`: Color file paths in terminal; remove curly braces surrounding the file path in \"Partial movie file written in...\" messages" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:138 msgid ":pr:`1632`: OpenGL compatibility via metaclass: :class:`~.Group`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:142 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:144 msgid ":pr:`1740`: Fix pillow to <8.3.0" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:147 msgid ":pr:`1729`: Fix bug when using :class:`~.Text` with the OpenGL renderer" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:150 msgid ":pr:`1675`: Fixed ignored fill and stroke colors for :class:`~.SVGMobject`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:153 msgid ":pr:`1664`: Fixed accidental displacement in :class:`~.Axes` caused by ``include_numbers`` / ``numbers_to_include``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:156 msgid ":pr:`1670`: Fixed missing ``numpy`` import in OpenGL shader example" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:159 msgid ":pr:`1636`: Fixed bugs and added examples to methods and classes in :mod:`manim.mobject.matrix`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:162 msgid ":pr:`1614`: Fix tick issues and improve tick placement for :class:`~.NumberLine`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:165 msgid ":pr:`1593`: Un-flip output of ``get_frame()`` when using the OpenGL renderer" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:168 msgid ":pr:`1619`: Fix output of automatically detected LaTeX errors" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:176 msgid ":pr:`1595`: Fixed a few CLI and rendering bugs" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:172 msgid "Corrected issue where gifs were being logged with an incorrect extension" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:173 msgid "Fixed issue where videos were output when format was set to png" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:174 msgid "Added logging for png output" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:175 msgid "Added precedence handling when the ``write_to_movie`` flag would conflict with ``--format``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:176 msgid "Fixed issue that caused png image output to be ignored when caching was enabled" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:178 msgid ":pr:`1635`: Added missing numpy import for :mod:`manim.mobject.probability`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:182 msgid ":pr:`1634`: Fixed OpenGL examples for MacOS" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:182 msgid "Renamed deprecated ``gl_FragColor`` to ``fragColor``." msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:185 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:187 msgid ":pr:`1732`: Remove reference to ``--plugins`` flag" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:190 msgid ":pr:`1734`: Fix inheritance graph background color" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:193 msgid ":pr:`1698`: Added an example for :class:`~.PMobject`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:196 msgid ":pr:`1690`: Added an example for :class:`~.CoordinateSystem`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:199 msgid ":pr:`1510`: Add a tutorial for using :class:`~.Text` and :class:`~.Tex`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:202 msgid ":pr:`1685`: Added an example and parameter description for :class:`~.AnnularSector`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:205 msgid ":pr:`1687`: Updated imports in ``geometry.py`` and added example to :class:`~.Arrow`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:208 msgid ":pr:`1681`: Added an example for :class:`~.NumberLine`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:211 msgid ":pr:`1697`: Added an example for :class:`~.PGroup`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:214 msgid ":pr:`1594`: Several improvements to the documentation design and layout" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:217 msgid ":pr:`1696`: Added an example for :class:`~.DashedVMobject`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:220 msgid ":pr:`1637`: Added an example for :class:`~.FunctionGraph`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:223 msgid ":pr:`1626`: Added an example for :class:`~.Prism`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:226 msgid ":pr:`1712`: Added a second example for :class:`~.DoubleArrow`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:229 msgid ":pr:`1710`: Update copyright year in documentation to 2020-2021" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:232 msgid ":pr:`1708`: Fixed link to interactive example notebook" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:235 msgid ":pr:`1657`: Added an example for :class:`~.ParametricSurface`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:238 msgid ":pr:`1642`: Added examples and docstrings for :class:`~.BarChart`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:241 msgid ":pr:`1700`: Added an example for :meth:`~.Mobject.scale`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:244 msgid ":pr:`1689`: Added an example for :class:`~.SurroundingRectangle`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:247 msgid ":pr:`1627`: Added an example for :class:`~.Sphere`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:250 msgid ":pr:`1569`: Added example to demonstrate differences between :class:`~.Transform` and :class:`~.ReplacementTransform`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:253 msgid ":pr:`1647`: Added an example for :class:`~.Sector`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:256 msgid ":pr:`1673`: Updated documentation examples for :class:`~.Text` and :class:`~.MarkupText`: set ``weight=BOLD`` instead of ``style``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:259 msgid ":pr:`1650`: Added an example for :class:`~.ArcBetweenPoints`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:262 msgid ":pr:`1628`: Added an example for :class:`~.NumberPlane`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:265 msgid ":pr:`1646`: Added an example for :class:`~.Underline`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:268 msgid ":pr:`1659`: Added more details to the Google Colab installation instructions" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:271 msgid ":pr:`1658`: Updated python requirement in the documentation" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:274 msgid ":pr:`1639`: Added an example for :class:`~.SampleSpace`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:277 msgid ":pr:`1640`: Added an example for :class:`~.Point`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:280 msgid ":pr:`1643`: Fixed ``RightArcAngleExample`` for :class:`~.Angle` in documentation" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:283 msgid ":pr:`1617`: Visually improved an example in our tutorial" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:286 msgid ":pr:`1641`: Added an example for :class:`~.ComplexPlane`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:289 msgid ":pr:`1644`: Added an example for :class:`~.BackgroundRectangle`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:292 msgid ":pr:`1633`: Added an example for :class:`~.Integer`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:295 msgid ":pr:`1630`: Added an example for :class:`~.Arc`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:298 msgid ":pr:`1631`: Added an example for :class:`~.BulletedList`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:301 msgid ":pr:`1620`: Fixed reference to command line interface help command" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:305 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:307 msgid ":pr:`1623`: CI: branch rename: master -> main" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:310 msgid ":pr:`1621`: Revert default template and add new templates" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:313 msgid ":pr:`1573`: PR template for the manim hackathon" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:317 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:319 msgid ":pr:`1720`: Renamed incorrect references of ``master`` to ``main``" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:322 msgid ":pr:`1692`: Removed redundant warning in CLI parsing" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:325 msgid ":pr:`1651`: Small code cleanup for :class:`~.Polygram`" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:328 msgid ":pr:`1610`: Changed one image extension to lowercase letters" msgstr "" #: ../../source/changelog/0.8.0-changelog.rst:332 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog/0.9.0-changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/changelog/0.9.0-changelog.rst:3 msgid "v0.9.0" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:0 msgid "Date" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:5 msgid "August 02, 2021" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:8 msgid "Contributors" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:10 msgid "A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:14 #: ../../source/changelog/0.9.0-changelog.rst:47 msgid "Alex Lembcke" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:15 #: ../../source/changelog/0.9.0-changelog.rst:48 msgid "Benjamin Hackl" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:16 #: ../../source/changelog/0.9.0-changelog.rst:49 msgid "Darylgolden" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:17 #: ../../source/changelog/0.9.0-changelog.rst:50 msgid "Devin Neal" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:18 msgid "Harivinay +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:19 #: ../../source/changelog/0.9.0-changelog.rst:52 msgid "Hugues Devimeux" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:20 msgid "Jared Hughes +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:21 #: ../../source/changelog/0.9.0-changelog.rst:54 msgid "Jason Villanueva" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:22 msgid "Kadatatlu Kishore +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:23 #: ../../source/changelog/0.9.0-changelog.rst:55 msgid "KingWampy" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:24 msgid "LED Me Explain +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:25 #: ../../source/changelog/0.9.0-changelog.rst:56 msgid "Laith Bahodi" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:26 #: ../../source/changelog/0.9.0-changelog.rst:58 msgid "Mohammad Al-Fetyani" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:27 msgid "Noam Zaks" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:28 #: ../../source/changelog/0.9.0-changelog.rst:59 msgid "Oliver" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:29 msgid "PaulCMurdoch" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:30 msgid "Raghav Prabhakar +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:31 msgid "Ryan McCauley" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:32 msgid "Suhail Sherif +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:33 msgid "Taektiek +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:34 msgid "Udeshya Dhungana +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:35 msgid "UraniumCronorum +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:36 msgid "Vinh H. Pham (Vincent) +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:37 msgid "ccn +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:38 msgid "icedcoffeeee +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:39 msgid "sahilmakhijani +" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:40 #: ../../source/changelog/0.9.0-changelog.rst:64 msgid "sparshg" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:43 msgid "The patches included in this release have been reviewed by the following contributors." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:46 msgid "Abhijith Muthyala" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:51 msgid "Harivinay" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:53 msgid "Jan-Hendrik Müller" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:57 msgid "Lino" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:60 msgid "Raghav Goel" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:61 msgid "Suhail Sherif" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:62 msgid "icedcoffeeee" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:63 msgid "sahilmakhijani" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:67 msgid "Pull requests merged" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:69 msgid "A total of 55 pull requests were merged for this release." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:72 msgid "Highlights" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:75 msgid ":pr:`1677`: Added a new :class:`~.Table` mobject" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:75 msgid "This brings easy-to-use and customizable tables to Manim. Several examples for this new mobject can be found at :mod:`the module documentation page <.mobject.table>` and its subpages." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:78 msgid "Deprecated classes and functions" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:82 msgid ":pr:`1848`: Deprecated parameters for :class:`~.DashedLine` and :class:`~.DashedVMobject`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:81 msgid "``dash_spacing`` is an unused parameter" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:82 msgid "``positive_space_ratio`` has been replaced with the shorter name ``dashed_ratio``" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:92 msgid ":pr:`1773`: Remove all classes and functions that were deprecated until ``v0.7.0`` and ``v0.8.0``" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:85 msgid "The classes ``FadeInFrom``, ``FadeOutAndShift``, ``FadeOutToPoint``, ``FadeInFromPoint``, ``FadeInFromLarge``, ``VFadeIn``, ``VFadeOut``, ``VFadeInThenOut`` have been removed, use :class:`~.FadeIn` or :class:`~.FadeOut` with appropriate keyword arguments instead." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:88 msgid "The classes ``CircleIndicate``, ``ShowCreationThenDestruction``, ``AnimationOnSurroundingRectangle``, ``ShowPassingFlashAround``, ``ShowCreationThenDestructionAround``, ``ShowCreationThenFadeAround``, ``WiggleOutThenIn``, ``TurnInsideOut`` have been removed. Use :class:`~.Circumscribe`, :class:`~.ShowPassingFlash`, or :class:`~.Wiggle` instead." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:90 msgid "The classes ``OpenGLTexMobject`` and ``OpenGLTextMobject`` have been removed, use :class:`~.MathTex` and :class:`~.Tex` instead. Also, ``VMobjectFromSVGPathstring`` has been removed, use :class:`~.SVGPathMobject` instead." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:92 msgid "Finally, the utility functions ``get_norm`` and ``cross`` have been removed (use the corresponding Numpy methods instead), and the function ``angle_between`` has been replaced with ``angle_between_vectors``." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:96 msgid ":pr:`1731`: Deprecated :class:`~.ParametricSurface` parameters" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:95 msgid "``u_min`` and ``u_max`` have been replaced by ``u_range``." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:96 msgid "``v_min`` and ``v_max`` have been replaced by ``v_range``." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:99 msgid "New features" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:103 msgid ":pr:`1780`: Allow non-numerical values to be added to :class:`~.NumberLine` and :class:`~.Axes`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:102 msgid "Added :meth:`.NumberLine.add_labels` method to :class:`~.NumberLine` which accepts a dictionary of positions/values." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:103 msgid ":meth:`.CoordinateSystem.add_coordinates` now accepts a dictionary too." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:105 msgid ":pr:`1719`: Added a :class:`~.Broadcast` animation" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:109 msgid ":pr:`1765`: Added a static method :meth:`.Circle.from_three_points` for defining a circle from three points" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:109 msgid "Added a new :func:`~.perpendicular_bisector` function in ``space_ops.py``" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:112 msgid ":pr:`1686`: Added :meth:`.ParametricSurface.set_fill_by_value`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:112 msgid "This method enables a color gradient to be applied to a :class:`~.ParametricSurface`, including the ability to define at which points the colors should be centered." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:115 msgid "Enhancements" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:117 msgid ":pr:`1833`: Added OpenGL compatibility for :class:`~.VDict`, :meth:`~.Axes.get_line_graph` and :class:`~.FocusOn`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:121 msgid ":pr:`1760`: Added ``window_size`` flag to manually adjust the size of the OpenGL window" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:121 msgid "Accepts a tuple in the form: ``x,y``." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:124 msgid ":pr:`1823`: Reworked :class:`~.DashedVMobject`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:124 msgid "Rewritten the logic to generate dashes" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:129 msgid ":pr:`1808`: OpenGL renderer updates" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:127 msgid "Adds model matrices to all OpenGLVMobjects" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:128 msgid "Improved performance on vectorized mobject shaders" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:129 msgid "Added updaters that are part of the scene rather than a mobject" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:132 msgid ":pr:`1787`: Made :class:`~.DecimalNumber` apply color to the ellipsis" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:132 msgid "Made color apply to the dots when `show_ellipsis` is set to true in `DecimalNumber`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:134 msgid ":pr:`1775`: Let :class:`~.Create` work on :class:`~.OpenGLSurface`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:137 msgid ":pr:`1757`: Added warning when there is a large number of items to hash." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:140 msgid ":pr:`1774`: Add the ``reverse`` parameter to :class:`~.Write`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:144 msgid "Fixed bugs" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:146 msgid ":pr:`1722`: Fixed ``remover=True`` for :class:`~.AnimationGroup`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:151 msgid ":pr:`1727`: Fixed some hot reload issues and compatibility with IDEs" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:150 msgid "Fixed interactive embed issue where it would fail when running on non-tty terminals" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:151 msgid "Fixed issue where file observer would error after the second run as the first observer was not closed" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:153 msgid ":pr:`1844`: Fixed the oversized :class:`~.Code` window with the OpenGL renderer" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:159 msgid ":pr:`1821`: Fixed issues concerning ``frame_center`` in :class:`~.ThreeDScene`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:157 msgid "Changing ``frame_center`` in a :class:`~.ThreeDScene` now actually changes the camera position." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:158 msgid "An animation with only ``frame_center`` animated will now be rendered properly." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:159 msgid "A black dot is not created at the origin once ``frame_center`` is animated." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:161 msgid ":pr:`1826`: Fixed scaling issue with :meth:`.BarChart.change_bar_values`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:164 msgid ":pr:`1839`: Allow passing arguments to ``.animate`` with the OpenGL renderer" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:167 msgid ":pr:`1791`: :meth:`~.Mobject.set_z_index` now sets all submobjects' ``z_index`` value" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:170 msgid ":pr:`1792`: Fixed bug that caused dry runs to fail when using the PNG format" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:173 msgid ":pr:`1790`: Fixed an import from ``manimlib``" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:176 msgid ":pr:`1782`: Fixed :class:`~.Tex` not working properly with the OpenGL renderer" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:179 msgid ":pr:`1783`: Fixed :meth:`~.OpenGLMobject.shuffle` function and added :meth:`~.invert` to OpenGL" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:182 msgid ":pr:`1786`: Fixed :class:`~.DecimalNumber` not working properly when the number of digits changes" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:185 msgid ":pr:`1763`: Fixed not being able to set some CLI flags in the configuration file" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:189 msgid ":pr:`1776`: :meth:`.CoordinateSystem.get_riemann_rectangles` now uses the graph's range instead of the axes range" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:189 msgid "If no range specified, `get_riemann_rectangles` generates the rectangles only where the area is correctly bounded" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:191 msgid ":pr:`1770`: Rewrote :meth:`.OpenGLMobject.put_start_and_end_on` to work correctly in 3D" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:194 msgid ":pr:`1736`: Fixed :class:`~.LinearTransformationScene` crashing on multiple animations" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:198 msgid "Documentation-related changes" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:200 msgid ":pr:`1852`: Fixed docs for :meth:`.Coordinate_system.add_coordinates` and moved :class: `~.Code` example" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:206 msgid ":pr:`1807`: Updated installation instructions" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:204 msgid "Added a warning about the incompatibility of different versions of Manim in the README" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:205 msgid "Modified the admonition warning in the documentation" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:206 msgid "Removed duplicated information from the README (``pip install manim`` is already covered in the docs)" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:208 msgid ":pr:`1739`: Added a section on creating a custom animation to the \"Manim's building blocks\" tutorial" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:211 msgid ":pr:`1835`: Updated documentation with information about reworked graphical unit test system" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:214 msgid ":pr:`1845`: Improve ``ThreeDSurfacePlot`` example in example gallery" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:217 msgid ":pr:`1842`: Removed instructions on installing Poetry from Developer Installation documentation, reference Poetry's documentation instead" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:220 msgid ":pr:`1829`: Switch the order of Scoop and Chocolatey in the docs for the Windows Installation" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:223 msgid ":pr:`1827`: Added ``robots.txt`` to prevent old versions of documentation from showing in search results" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:226 msgid ":pr:`1819`: Removed mention of ``-h`` CLI flag from documentation" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:229 msgid ":pr:`1813`: Removed unused variables from tutorial" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:232 msgid ":pr:`1815`: Added codespell to the list of used linters in the contribution guidelines" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:235 msgid ":pr:`1778`: Improve sidebar structure of the documentation's reference manual" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:238 msgid ":pr:`1749`: Added documentation and example for :meth:`.VMobject.set_fill`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:241 msgid ":pr:`1743`: Edited the developer installation instructions to include information on cloning the repository" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:244 msgid ":pr:`1706`: Rework example for :class:`~.Variable`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:248 msgid "Changes concerning the testing system" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:250 msgid ":pr:`1836`: Converted all the graphical tests to the new syntax" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:254 msgid ":pr:`1802`: Refactored graphical unit testing system, and implemented multi frames tests" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:254 msgid "This PR introduces a new ``@frames_comparison`` decorator which allows writing simple ``construct``-like functions as tests. Control data for new tests can be easily generated by calling ``pytest --set_test``." msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:257 msgid "Changes to our development infrastructure" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:259 msgid ":pr:`1830`: Be more concise about the documentation URL in the PR template" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:263 msgid "Code quality improvements and similar refactors" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:265 msgid ":pr:`1851`: Renamed ``Tabular`` to :class:`~.Table`" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:268 msgid ":pr:`1817`: Remove pillow version requirement" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:271 msgid ":pr:`1806`: Fixed spelling mistake" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:274 msgid ":pr:`1745`: Updated the BibTeX template in the README to Manim v0.9.0" msgstr "" #: ../../source/changelog/0.9.0-changelog.rst:278 msgid "New releases" msgstr "" ================================================ FILE: docs/i18n/gettext/changelog.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" ================================================ FILE: docs/i18n/gettext/conduct.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/conduct.md:3 msgid "Code of Conduct" msgstr "" #: ../../source/conduct.md:7 msgid "TL;DR Be excellent to each other; we're a community after all. If you run into issues with others in our community, please [contact](https://www.manim.community/discord/) a Manim Community Dev, or Moderator." msgstr "" #: ../../source/conduct.md:9 msgid "Purpose" msgstr "" #: ../../source/conduct.md:11 msgid "The Manim Community includes members of varying skills, languages, personalities, cultural backgrounds, and experiences from around the globe. Through these differences, we continue to grow and collectively improve upon an open-source animation engine. When working in a community, it is important to remember that you are interacting with humans on the other end of your screen. This code of conduct will guide your interactions and keep Manim a positive environment for our developers, users, and fundamentally our growing community." msgstr "" #: ../../source/conduct.md:15 msgid "Our Community" msgstr "" #: ../../source/conduct.md:17 msgid "Members of Manim Community are respectful, open, and considerate. Behaviors that reinforce these values contribute to our positive environment, and include:" msgstr "" #: ../../source/conduct.md:19 msgid "**Being respectful.** Respectful of others, their positions, experiences, viewpoints, skills, commitments, time, and efforts." msgstr "" #: ../../source/conduct.md:21 msgid "**Being open.** Open to collaboration, whether it's on problems, Pull Requests, issues, or otherwise." msgstr "" #: ../../source/conduct.md:23 msgid "**Being considerate.** Considerate of their peers -- other Manim users and developers." msgstr "" #: ../../source/conduct.md:25 msgid "**Focusing on what is best for the community.** We're respectful of the processes set forth in the community, and we work within them." msgstr "" #: ../../source/conduct.md:27 msgid "**Showing empathy towards other community members.** We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views." msgstr "" #: ../../source/conduct.md:29 msgid "**Gracefully accepting constructive criticism.** When we disagree, we are courteous in raising our issues." msgstr "" #: ../../source/conduct.md:31 msgid "**Using welcoming and inclusive language.** We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference." msgstr "" #: ../../source/conduct.md:35 msgid "Our Standards" msgstr "" #: ../../source/conduct.md:37 msgid "Every member of our community has the right to have their identity respected. Manim Community is dedicated to providing a positive environment for everyone, regardless of age, gender identity and expression, sexual orientation, disability, physical appearance, body size, ethnicity, nationality, race, religion (or lack thereof), education, or socioeconomic status." msgstr "" #: ../../source/conduct.md:41 msgid "Inappropriate Behavior" msgstr "" #: ../../source/conduct.md:43 msgid "Examples of unacceptable behavior by participants include:" msgstr "" #: ../../source/conduct.md:45 msgid "Harassment of any participants in any form" msgstr "" #: ../../source/conduct.md:46 msgid "Deliberate intimidation, stalking, or following" msgstr "" #: ../../source/conduct.md:47 msgid "Logging or taking screenshots of online activity for harassment purposes" msgstr "" #: ../../source/conduct.md:48 msgid "Publishing others' private information, such as a physical or electronic address, without explicit permission" msgstr "" #: ../../source/conduct.md:49 msgid "Violent threats or language directed against another person" msgstr "" #: ../../source/conduct.md:50 msgid "Incitement of violence or harassment towards any individual, including encouraging a person to commit suicide or to engage in self-harm" msgstr "" #: ../../source/conduct.md:51 msgid "Creating additional online accounts in order to harass another person or circumvent a ban" msgstr "" #: ../../source/conduct.md:52 msgid "Sexual language and imagery in online communities or any conference venue, including talks" msgstr "" #: ../../source/conduct.md:53 msgid "Insults, put-downs, or jokes that are based upon stereotypes, that are exclusionary, or that hold others up for ridicule" msgstr "" #: ../../source/conduct.md:54 msgid "Excessive swearing" msgstr "" #: ../../source/conduct.md:55 msgid "Unwelcome sexual attention or advances" msgstr "" #: ../../source/conduct.md:56 msgid "Unwelcome physical contact, including simulated physical contact (eg, textual descriptions like \"hug\" or \"backrub\") without consent or after a request to stop" msgstr "" #: ../../source/conduct.md:57 msgid "Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others" msgstr "" #: ../../source/conduct.md:58 msgid "Sustained disruption of online community discussions, in-person presentations, or other in-person events" msgstr "" #: ../../source/conduct.md:59 msgid "Continued one-on-one communication after requests to cease" msgstr "" #: ../../source/conduct.md:60 msgid "Other conduct that is inappropriate for a professional audience including people of many different backgrounds Community members asked to stop any inappropriate behavior are expected to comply immediately." msgstr "" #: ../../source/conduct.md:65 msgid "Manim Community Online Spaces" msgstr "" #: ../../source/conduct.md:67 msgid "This Code of Conduct applies to the following online spaces:" msgstr "" #: ../../source/conduct.md:69 msgid "The [ManimCommunity GitHub Organization](https://github.com/ManimCommunity) and all of its repositories" msgstr "" #: ../../source/conduct.md:71 msgid "The Manim [Discord](https://www.manim.community/discord/)" msgstr "" #: ../../source/conduct.md:73 msgid "The Manim [Reddit](https://www.reddit.com/r/manim/)" msgstr "" #: ../../source/conduct.md:75 msgid "The Manim [Twitter](https://twitter.com/manim\\_community/)" msgstr "" #: ../../source/conduct.md:77 msgid "This Code of Conduct applies to every member in official Manim Community online spaces, including:" msgstr "" #: ../../source/conduct.md:79 msgid "Moderators" msgstr "" #: ../../source/conduct.md:81 msgid "Maintainers" msgstr "" #: ../../source/conduct.md:83 msgid "Developers" msgstr "" #: ../../source/conduct.md:85 msgid "Reviewers" msgstr "" #: ../../source/conduct.md:87 msgid "Contributors" msgstr "" #: ../../source/conduct.md:89 msgid "Users" msgstr "" #: ../../source/conduct.md:91 msgid "All community members" msgstr "" #: ../../source/conduct.md:95 msgid "Consequences" msgstr "" #: ../../source/conduct.md:97 msgid "If a member's behavior violates this code of conduct, the Manim Community Code of Conduct team may take any action they deem appropriate, including, but not limited to: warning the offender, temporary bans, deletion of offending messages, and expulsion from the community and its online spaces. The full list of consequences for inappropriate behavior is listed below in the Enforcement Procedures." msgstr "" #: ../../source/conduct.md:101 msgid "Thank you for helping make this a welcoming, friendly community for everyone." msgstr "" #: ../../source/conduct.md:105 msgid "Contact Information" msgstr "" #: ../../source/conduct.md:107 msgid "If you believe someone is violating the code of conduct, or have any other concerns, please contact a Manim Community Dev, or Moderator immediately. They can be reached on Manim's Community [Discord](https://www.manim.community/discord/)." msgstr "" #: ../../source/conduct.md:117 msgid "Enforcement Procedures" msgstr "" #: ../../source/conduct.md:119 msgid "This document summarizes the procedures the Manim Community Code of Conduct team uses to enforce the Code of Conduct." msgstr "" #: ../../source/conduct.md:123 msgid "Summary of processes" msgstr "" #: ../../source/conduct.md:125 msgid "When the team receives a report of a possible Code of Conduct violation, it will:" msgstr "" #: ../../source/conduct.md:127 msgid "Acknowledge the receipt of the report." msgstr "" #: ../../source/conduct.md:128 msgid "Evaluate conflicts of interest." msgstr "" #: ../../source/conduct.md:129 msgid "Call a meeting of code of conduct team members without a conflict of interest." msgstr "" #: ../../source/conduct.md:130 msgid "Evaluate the reported incident." msgstr "" #: ../../source/conduct.md:131 msgid "Propose a behavioral modification plan." msgstr "" #: ../../source/conduct.md:132 msgid "Propose consequences for the reported behavior." msgstr "" #: ../../source/conduct.md:133 msgid "Vote on behavioral modification plan and consequences for the reported person." msgstr "" #: ../../source/conduct.md:134 msgid "Contact Manim Community moderators to approve the behavioral modification plan and consequences." msgstr "" #: ../../source/conduct.md:135 msgid "Follow up with the reported person." msgstr "" #: ../../source/conduct.md:136 msgid "Decide further responses." msgstr "" #: ../../source/conduct.md:137 msgid "Follow up with the reporter." msgstr "" #: ../../source/conduct.md:140 msgid "Acknowledge the report" msgstr "" #: ../../source/conduct.md:142 msgid "Reporters should receive an acknowledgment of the receipt of their report within 48 hours." msgstr "" #: ../../source/conduct.md:146 msgid "Conflict of interest policy" msgstr "" #: ../../source/conduct.md:148 msgid "Examples of conflicts of interest include:" msgstr "" #: ../../source/conduct.md:150 msgid "You have a romantic or platonic relationship with either the reporter or the reported person. It's fine to participate if they are an acquaintance." msgstr "" #: ../../source/conduct.md:151 msgid "The reporter or reported person is someone you work closely with. This could be someone on your team or someone who works on the same project as you." msgstr "" #: ../../source/conduct.md:152 msgid "The reporter or reported person is a maintainer who regularly reviews your contributions" msgstr "" #: ../../source/conduct.md:153 msgid "The reporter or reported person is your metamour." msgstr "" #: ../../source/conduct.md:154 msgid "The reporter or reported person is your family member Committee members do not need to state why they have a conflict of interest, only that one exists. Other team members should not ask why the person has a conflict of interest." msgstr "" #: ../../source/conduct.md:157 msgid "Anyone who has a conflict of interest will remove themselves from the discussion of the incident, and recluse themselves from voting on a response to the report." msgstr "" #: ../../source/conduct.md:161 msgid "Evaluating a report" msgstr "" #: ../../source/conduct.md:163 msgid "Jurisdiction" msgstr "" #: ../../source/conduct.md:165 msgid "*Is this a Code of Conduct violation?* Is this behavior on our list of inappropriate behavior? Is it borderline inappropriate behavior? Does it violate our community norms?" msgstr "" #: ../../source/conduct.md:166 msgid "*Did this occur in a space that is within our Code of Conduct's scope?* If the incident occurred outside the community, but a community member's mental health or physical safety may be negatively impacted if no action is taken, the incident may be in scope. Private conversations in community spaces are also in scope." msgstr "" #: ../../source/conduct.md:167 msgid "Impact" msgstr "" #: ../../source/conduct.md:169 msgid "*Did this incident occur in a private conversation or a public space?* Incidents that all community members can see will have a more negative impact." msgstr "" #: ../../source/conduct.md:170 msgid "*Does this behavior negatively impact a marginalized group in our community?* Is the reporter a person from a marginalized group in our community? How is the reporter being negatively impacted by the reported person's behavior? Are members of the marginalized group likely to disengage with the community if no action was taken on this report?" msgstr "" #: ../../source/conduct.md:171 msgid "*Does this incident involve a community leader?* Community members often look up to community leaders to set the standard of acceptable behavior" msgstr "" #: ../../source/conduct.md:172 msgid "Risk" msgstr "" #: ../../source/conduct.md:174 msgid "*Does this incident include sexual harassment?*" msgstr "" #: ../../source/conduct.md:175 msgid "*Does this pose a safety risk?* Does the behavior put a person's physical safety at risk? Will this incident severely negatively impact someone's mental health?" msgstr "" #: ../../source/conduct.md:176 msgid "*Is there a risk of this behavior being repeated?* Does the reported person understand why their behavior was inappropriate? Is there an established pattern of behavior from past reports?" msgstr "" #: ../../source/conduct.md:179 msgid "Reports which involve higher risk or higher impact may face more severe consequences than reports which involve lower risk or lower impact." msgstr "" #: ../../source/conduct.md:183 msgid "Propose consequences" msgstr "" #: ../../source/conduct.md:185 msgid "What follows are examples of possible consequences of an incident report. This list of consequences is not exhaustive, and the Manim Community Code of Conduct team reserves the right to take any action it deems necessary." msgstr "" #: ../../source/conduct.md:187 msgid "Possible private responses to an incident include:" msgstr "" #: ../../source/conduct.md:189 msgid "Nothing, if the behavior was determined to not be a Code of Conduct violation" msgstr "" #: ../../source/conduct.md:190 msgid "A warning" msgstr "" #: ../../source/conduct.md:191 msgid "A final warning" msgstr "" #: ../../source/conduct.md:192 msgid "Temporarily removing the reported person from the community's online space(s)" msgstr "" #: ../../source/conduct.md:193 msgid "Permanently removing the reported person from the community's online space(s)" msgstr "" #: ../../source/conduct.md:194 msgid "Publishing an account of the incident" msgstr "" #: ../../source/conduct.md:197 msgid "Team vote" msgstr "" #: ../../source/conduct.md:199 msgid "Some team members may have a conflict of interest and may be excluded from discussions of a particular incident report. Excluding those members, decisions on the behavioral modification plans and consequences will be determined by a two-thirds majority vote of the Manim Community Code of Conduct team." msgstr "" #: ../../source/conduct.md:203 msgid "Moderators approval" msgstr "" #: ../../source/conduct.md:205 msgid "Once the team has approved the behavioral modification plans and consequences, they will communicate the recommended response to the Manim Community moderators. The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report." msgstr "" #: ../../source/conduct.md:207 msgid "Moderators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week." msgstr "" #: ../../source/conduct.md:209 msgid "In cases where the moderators disagree on the suggested resolution for a report, the Manim Community Code of Conduct team may choose to notify the Manim Community Moderators." msgstr "" #: ../../source/conduct.md:213 msgid "Follow up with the reported person" msgstr "" #: ../../source/conduct.md:215 msgid "The Manim Community Code of Conduct team will work with Manim Community moderators to draft a response to the reported person. The response should contain:" msgstr "" #: ../../source/conduct.md:217 msgid "A description of the person's behavior in neutral language" msgstr "" #: ../../source/conduct.md:218 msgid "The negative impact of that behavior" msgstr "" #: ../../source/conduct.md:219 msgid "A concrete behavioral modification plan" msgstr "" #: ../../source/conduct.md:220 msgid "Any consequences of their behavior The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report. The reported person should be discouraged from contacting the reporter to discuss the report. If they wish to apologize to the reporter, the team can accept the apology on behalf of the reporter." msgstr "" #: ../../source/conduct.md:225 msgid "Decide further responses" msgstr "" #: ../../source/conduct.md:227 msgid "If the reported person provides additional context, the Manim Community Code of Conduct team may need to re-evaluate the behavioral modification plan and consequences." msgstr "" #: ../../source/conduct.md:229 msgid "Follow up with the reporter" msgstr "" #: ../../source/conduct.md:231 msgid "A person who makes a report should receive a follow-up response stating what action was taken in response to the report. If the team decided no response was needed, they should provide an explanation why it was not a Code of Conduct violation. Reports that are not made in good faith (such as \"reverse sexism\" or \"reverse racism\") may receive no response." msgstr "" #: ../../source/conduct.md:233 msgid "The follow-up should be sent no later than one week after the receipt of the report. If deliberation or follow-up with the reported person takes longer than one week, the team should send a status update to the reporter." msgstr "" #: ../../source/conduct.md:237 msgid "Changes to Code of Conduct" msgstr "" #: ../../source/conduct.md:239 msgid "When discussing a change to the Manim Community code of conduct or enforcement procedures, the Manim Community Code of Conduct team will follow this decision-making process:" msgstr "" #: ../../source/conduct.md:241 msgid "**Brainstorm options.** Team members should discuss any relevant context and brainstorm a set of possible options. It is important to provide constructive feedback without getting side-tracked from the main question." msgstr "" #: ../../source/conduct.md:242 msgid "**Vote.** Proposed changes to the code of conduct will be decided by a two-thirds majority of all voting members of the Code of Conduct team. Team members are listed in the charter. Currently active voting members are listed in the following section." msgstr "" #: ../../source/conduct.md:243 msgid "**Board Vote.** Once a working draft is in place for the Code of Conduct and procedures, the Code of Conduct team shall provide the Manim Community Moderators with a draft of the changes. The Manim Community Moderators will vote on the changes at a board meeting." msgstr "" #: ../../source/conduct.md:246 msgid "Current list of voting members" msgstr "" #: ../../source/conduct.md:248 msgid "All available Community Developers (i.e. those with \"write\" permissions, or above, on the Manim Community GitHub organization)." msgstr "" #: ../../source/conduct.md:252 msgid "License" msgstr "" #: ../../source/conduct.md:254 msgid "This Code of Conduct is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](https://creativecommons.org/licenses/by-sa/3.0/)." msgstr "" #: ../../source/conduct.md:258 msgid "Attributions" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/admonitions.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/admonitions.rst:3 msgid "Adding Admonitions" msgstr "" #: ../../source/contributing/admonitions.rst:6 msgid "Adding Blocks for Tip, Note, Important etc. (Admonitions)" msgstr "" #: ../../source/contributing/admonitions.rst:8 msgid "The following directives are called Admonitions. You can use them to point out additional or important information. Here are some examples:" msgstr "" #: ../../source/contributing/admonitions.rst:13 msgid "See also" msgstr "" #: ../../source/contributing/admonitions.rst:21 msgid "Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser`" msgstr "" #: ../../source/contributing/admonitions.rst:28 msgid "Note" msgstr "" #: ../../source/contributing/admonitions.rst:36 msgid "A note" msgstr "" #: ../../source/contributing/admonitions.rst:39 msgid "Tip" msgstr "" #: ../../source/contributing/admonitions.rst:47 msgid "A tip" msgstr "" #: ../../source/contributing/admonitions.rst:49 msgid "You may also use the admonition **hint**, but this is very similar and **tip** is more commonly used in the documentation." msgstr "" #: ../../source/contributing/admonitions.rst:53 msgid "Important" msgstr "" #: ../../source/contributing/admonitions.rst:61 msgid "Some important information which should be considered." msgstr "" #: ../../source/contributing/admonitions.rst:64 msgid "Warning" msgstr "" #: ../../source/contributing/admonitions.rst:72 msgid "Some text pointing out something that people should be warned about." msgstr "" #: ../../source/contributing/admonitions.rst:74 msgid "You may also use the admonitions **caution** or even **danger** if the severity of the warning must be stressed." msgstr "" #: ../../source/contributing/admonitions.rst:78 msgid "Attention" msgstr "" #: ../../source/contributing/admonitions.rst:86 msgid "A attention" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/development.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/development.rst:3 msgid "Manim Development Process" msgstr "" #: ../../source/contributing/development.rst:6 msgid "For first-time contributors" msgstr "" #: ../../source/contributing/development.rst:7 msgid "Install git:" msgstr "" #: ../../source/contributing/development.rst:9 msgid "For instructions see https://git-scm.com/." msgstr "" #: ../../source/contributing/development.rst:12 msgid "Fork the project. Go to https://github.com/ManimCommunity/manim and click the \"fork\" button to create a copy of the project for you to work on. You will need a GitHub account. This will allow you to make a \"Pull Request\" (PR) to the ManimCommunity repo later on." msgstr "" #: ../../source/contributing/development.rst:17 msgid "Clone your fork to your local computer:" msgstr "" #: ../../source/contributing/development.rst:23 msgid "GitHub will provide both a SSH (``git@github.com:/manim.git``) and HTTPS (``https://github.com//manim.git``) URL for cloning. You can use SSH if you have SSH keys setup." msgstr "" #: ../../source/contributing/development.rst:29 msgid "Do not clone the ManimCommunity repository. You must clone your own fork." msgstr "" #: ../../source/contributing/development.rst:32 msgid "Change the directory to enter the project folder:" msgstr "" #: ../../source/contributing/development.rst:38 msgid "Add the upstream repository, ManimCommunity:" msgstr "" #: ../../source/contributing/development.rst:44 msgid "Now, ``git remote -v`` should show two remote repositories named:" msgstr "" #: ../../source/contributing/development.rst:46 msgid "``origin``, your forked repository" msgstr "" #: ../../source/contributing/development.rst:47 msgid "``upstream`` the ManimCommunity repository" msgstr "" #: ../../source/contributing/development.rst:49 msgid "Install Manim:" msgstr "" #: ../../source/contributing/development.rst:51 msgid "Follow the steps in our :doc:`installation instructions <../installation>` to install **Manim's dependencies**, primarily ``ffmpeg`` and ``LaTeX``." msgstr "" #: ../../source/contributing/development.rst:55 msgid "We recommend using `Poetry `__ to manage your developer installation of Manim. Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on, and it will manage (install / update) them for you. In addition, Poetry provides a simple interface for managing virtual environments." msgstr "" #: ../../source/contributing/development.rst:62 msgid "If you choose to use Poetry as well, follow `Poetry's installation guidelines `__ to install it on your system, then run ``poetry install`` from your cloned repository. Poetry will then install Manim, as well as create and enter a virtual environment. You can always re-enter that environment by running ``poetry shell``." msgstr "" #: ../../source/contributing/development.rst:69 msgid "In case you want to install extra dependencies that are defined in the ``[tool.poetry.extras]`` section of ``pyproject.toml``, this can be done by passing the ``-E`` flag, for example ``poetry install -E jupyterlab -E gui``." msgstr "" #: ../../source/contributing/development.rst:73 msgid "In case you decided against Poetry, you can install Manim via pip by running ``python3 -m pip install .``. Note that due to our development infrastructure being based on Poetry, we currently do not support editable installs via ``pip``, so you will have to re-run this command every time you make changes to the source code." msgstr "" #: ../../source/contributing/development.rst:82 msgid "The following steps assume that you chose to install and work with Poetry." msgstr "" #: ../../source/contributing/development.rst:85 msgid "Install Pre-Commit:" msgstr "" #: ../../source/contributing/development.rst:91 msgid "This will ensure during development that each of your commits is properly formatted against our linter and formatters, ``black``, ``flake8``, ``isort`` and ``codespell``." msgstr "" #: ../../source/contributing/development.rst:95 msgid "You are now ready to work on manim!" msgstr "" #: ../../source/contributing/development.rst:98 msgid "Develop your contribution" msgstr "" #: ../../source/contributing/development.rst:100 msgid "Checkout your local repository's main branch and pull the latest changes from ManimCommunity, ``upstream``, into your local repository:" msgstr "" #: ../../source/contributing/development.rst:108 msgid "Create a branch for the changes you want to work on rather than working off of your local main branch:" msgstr "" #: ../../source/contributing/development.rst:115 msgid "This ensures you can easily update your local repository's main with the first step and switch branches to work on multiple features." msgstr "" #: ../../source/contributing/development.rst:118 msgid "Write some awesome code!" msgstr "" #: ../../source/contributing/development.rst:120 msgid "You're ready to make changes in your local repository's branch. You can add local files you've changed within the current directory with ``git add .``, or add specific files with" msgstr "" #: ../../source/contributing/development.rst:128 msgid "and commit these changes to your local history with ``git commit``. If you have installed pre-commit, your commit will succeed only if none of the hooks fail." msgstr "" #: ../../source/contributing/development.rst:134 msgid "When crafting commit messages, it is highly recommended that you adhere to `these guidelines `_." msgstr "" #: ../../source/contributing/development.rst:137 msgid "Add new or update existing tests." msgstr "" #: ../../source/contributing/development.rst:139 msgid "Depending on your changes, you may need to update or add new tests. For new features, it is required that you include tests with your PR. Details of our testing system are explained in the :doc:`testing guide `." msgstr "" #: ../../source/contributing/development.rst:144 msgid "Update docstrings and documentation:" msgstr "" #: ../../source/contributing/development.rst:146 msgid "Update the docstrings (the text in triple quotation marks) of any functions or classes you change and include them with any new functions you add. See the :doc:`documentation guide ` for more information about how we prefer our code to be documented. The content of the docstrings will be rendered in the :doc:`reference manual <../reference>`." msgstr "" #: ../../source/contributing/development.rst:154 msgid "Use the :mod:`manim directive for Sphinx ` to add examples to the documentation!" msgstr "" #: ../../source/contributing/development.rst:157 msgid "As far as development on your local machine goes, these are the main steps you should follow." msgstr "" #: ../../source/contributing/development.rst:161 msgid "Polishing Changes and Submitting a Pull Request" msgstr "" #: ../../source/contributing/development.rst:163 msgid "As soon as you are ready to share your local changes with the community so that they can be discussed, go through the following steps to open a pull request. A pull request signifies to the ManimCommunity organization, \"Here are some changes I wrote; I think it's worthwhile for you to maintain them.\"" msgstr "" #: ../../source/contributing/development.rst:171 msgid "You do not need to have everything (code/documentation/tests) complete to open a pull request (PR). If the PR is still under development, please mark it as a draft. Community developers will still be able to review the changes, discuss yet-to-be-implemented changes, and offer advice; however, the more complete your PR, the quicker it will be merged." msgstr "" #: ../../source/contributing/development.rst:177 msgid "Update your fork on GitHub to reflect your local changes:" msgstr "" #: ../../source/contributing/development.rst:183 msgid "Doing so creates a new branch on your remote fork, ``origin``, with the contents of your local repository on GitHub. In subsequent pushes, this local branch will track the branch ``origin`` and ``git push`` is enough." msgstr "" #: ../../source/contributing/development.rst:188 msgid "Make a pull request (PR) on GitHub." msgstr "" #: ../../source/contributing/development.rst:190 msgid "In order to make the ManimCommunity development team aware of your changes, you can make a PR to the ManimCommunity repository from your fork." msgstr "" #: ../../source/contributing/development.rst:195 msgid "Make sure to select ``ManimCommunity/manim`` instead of ``3b1b/manim`` as the base repository!" msgstr "" #: ../../source/contributing/development.rst:198 msgid "Choose the branch from your fork as the head repository - see the screenshot below." msgstr "" #: ../../source/contributing/development.rst:204 msgid "Please make sure you follow the template (this is the default text you are shown when first opening the 'New Pull Request' page)." msgstr "" #: ../../source/contributing/development.rst:208 msgid "Your changes are eligible to be merged if:" msgstr "" #: ../../source/contributing/development.rst:210 msgid "there are no merge conflicts" msgstr "" #: ../../source/contributing/development.rst:211 msgid "the tests in our pipeline pass" msgstr "" #: ../../source/contributing/development.rst:212 msgid "at least one (two for more complex changes) Community Developer approves the changes" msgstr "" #: ../../source/contributing/development.rst:214 msgid "You can check for merge conflicts between the current upstream/main and your branch by executing ``git pull upstream main`` locally. If this generates any merge conflicts, you need to resolve them and push an updated version of the branch to your fork of the repository." msgstr "" #: ../../source/contributing/development.rst:219 msgid "Our pipeline consists of a series of different tests that ensure that manim still works as intended and that the code you added sticks to our coding conventions." msgstr "" #: ../../source/contributing/development.rst:223 msgid "**Code style**: We use the code style imposed by `Black `_, `isort `_ and `flake8 `_. The GitHub pipeline makes sure that the (Python) files changed in your pull request also adhere to this code style. If this step of the pipeline fails, fix your code formatting automatically by running ``black `` and ``isort ``. To fix code style problems, run ``flake8 `` for a style report, and then fix the problems manually that were detected by ``flake8``." msgstr "" #: ../../source/contributing/development.rst:232 msgid "**Tests**: The pipeline runs manim's test suite on different operating systems (the latest versions of Ubuntu, MacOS, and Windows) for different versions of Python. The test suite consists of two different kinds of tests: integration tests and doctests. You can run them locally by executing ``poetry run pytest`` and ``poetry run pytest --doctest-modules manim``, respectively, from the root directory of your cloned fork." msgstr "" #: ../../source/contributing/development.rst:239 msgid "**Documentation**: We also build a version of the documentation corresponding to your pull request. Make sure not to introduce any Sphinx errors, and have a look at the built HTML files to see whether the formatting of the documentation you added looks as you intended. You can build the documentation locally by running ``make html`` from the ``docs`` directory. Since the inheritance diagrams require you to have `Graphviz `_ installed locally." msgstr "" #: ../../source/contributing/development.rst:246 msgid "Finally, if the pipeline passes and you are satisfied with your changes: wait for feedback and iterate over any requested changes. You will likely be asked to edit or modify your PR in one way or another during this process. This is not an indictment of your work, but rather a strong signal that the community wants to merge your changes! Once approved, your changes may be merged!" msgstr "" #: ../../source/contributing/development.rst:253 msgid "Further useful guidelines" msgstr "" #: ../../source/contributing/development.rst:255 msgid "When submitting a PR, please mention explicitly if it includes breaking changes." msgstr "" #: ../../source/contributing/development.rst:257 msgid "When submitting a PR, make sure that your proposed changes are as general as possible, and ready to be taken advantage of by all of manim's users. In particular, leave out any machine-specific configurations, or any personal information it may contain." msgstr "" #: ../../source/contributing/development.rst:262 msgid "If you are a maintainer, please label issues and PRs appropriately and frequently." msgstr "" #: ../../source/contributing/development.rst:265 msgid "When opening a new issue, if there are old issues that are related, add a link to them in your new issue (even if the old ones are closed)." msgstr "" #: ../../source/contributing/development.rst:268 msgid "When submitting a code review, it is highly recommended that you adhere to `these general guidelines `_." msgstr "" #: ../../source/contributing/development.rst:271 msgid "If you find stale or inactive issues that seem to be irrelevant, please post a comment saying 'This issue should be closed', and a community developer will take a look." msgstr "" #: ../../source/contributing/development.rst:275 msgid "Please do as much as possible to keep issues, PRs, and development in general as tidy as possible." msgstr "" #: ../../source/contributing/development.rst:279 msgid "You can find examples for the ``docs`` in several places: the :doc:`Example Gallery <../examples>`, :doc:`Tutorials <../tutorials/index>`, and :doc:`Reference Classes <../reference>`." msgstr "" #: ../../source/contributing/development.rst:283 msgid "In case you are contributing, please have a look at this flowchart:" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/docstrings.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/docstrings.rst:3 msgid "Adding Docstrings" msgstr "" #: ../../source/contributing/docstrings.rst:5 msgid "A docstring is a string literal that is used right after the definition of a module, function, class, or method. They are used to document our code. This page will give you a set of guidelines to write efficient and correct docstrings." msgstr "" #: ../../source/contributing/docstrings.rst:11 msgid "Formatting the Docstrings" msgstr "" #: ../../source/contributing/docstrings.rst:13 msgid "Please begin the description of the class/function in the same line as the 3 quotes:" msgstr "" #: ../../source/contributing/docstrings.rst:31 msgid "NumPy Format" msgstr "" #: ../../source/contributing/docstrings.rst:32 msgid "The Manim Community uses numpy format for the documentation." msgstr "" #: ../../source/contributing/docstrings.rst:34 msgid "Use the numpy format for sections and formatting - see https://numpydoc.readthedocs.io/en/latest/format.html." msgstr "" #: ../../source/contributing/docstrings.rst:37 msgid "This includes:" msgstr "" #: ../../source/contributing/docstrings.rst:39 msgid "The usage of ``Attributes`` to specify ALL ATTRIBUTES that a class can have and a brief (or long, if needed) description." msgstr "" #: ../../source/contributing/docstrings.rst:43 msgid "Also, ``__init__`` parameters should be specified as ``Parameters`` **on the class docstring**, *rather than under* ``__init__``. Note that this can be omitted if the parameters and the attributes are the same (i.e., dataclass) - priority should be given to the ``Attributes`` section, in this case, which must **always be present**, unless the class specifies no attributes at all. (See more on Parameters in number 2 of this list.)" msgstr "" #: ../../source/contributing/docstrings.rst:51 #: ../../source/contributing/docstrings.rst:151 msgid "Example:" msgstr "" #: ../../source/contributing/docstrings.rst:83 msgid "The usage of ``Parameters`` on functions to specify how every parameter works and what it does. This should be excluded if the function has no parameters. Note that you **should not** specify the default value of the parameter on the type. On the documentation render, this is already specified on the function's signature. If you need to indicate a further consequence of value omission or simply want to specify it on the docs, make sure to **specify it in the parameter's DESCRIPTION**." msgstr "" #: ../../source/contributing/docstrings.rst:92 #: ../../source/contributing/docstrings.rst:128 msgid "See an example on list item 4." msgstr "" #: ../../source/contributing/docstrings.rst:96 msgid "When documenting varargs (args and kwargs), make sure to document them by listing the possible types of each value specified, like this:" msgstr "" #: ../../source/contributing/docstrings.rst:109 msgid "Note that, if the kwargs expect specific values, those can be specified in a section such as ``Other Parameters``:" msgstr "" #: ../../source/contributing/docstrings.rst:120 msgid "The usage of ``Returns`` to indicate what is the type of this function's return value and what exactly it returns (i.e., a brief - or long, if needed - description of what this function returns). Can be omitted if the function does not explicitly return (i.e., always returns ``None`` because ``return`` is never specified, and it is very clear why this function does not return at all). In all other cases, it should be specified." msgstr "" #: ../../source/contributing/docstrings.rst:130 msgid "The usage of ``Examples`` in order to specify an example of usage of a function **is highly encouraged** and, in general, should be specified for *every function* unless its usage is **extremely obvious**, which can be debatable. Even if it is, it's always a good idea to add an example in order to give a better orientation to the documentation user. Use the following format for Python code:" msgstr "" #: ../../source/contributing/docstrings.rst:144 msgid "Also, if this is a video- or animation-related change, please try to add an example GIF or video if possible for demonstration purposes." msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/examples.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/examples.rst:3 msgid "Adding Examples" msgstr "" #: ../../source/contributing/examples.rst:5 msgid "This is a page for adding examples to the documentation. Here are some guidelines you should follow before you publish your examples." msgstr "" #: ../../source/contributing/examples.rst:9 msgid "Guidelines for examples" msgstr "" #: ../../source/contributing/examples.rst:11 msgid "Everybody is welcome to contribute examples to the documentation. Since straightforward examples are a great resource for quickly learning manim, here are some guidelines." msgstr "" #: ../../source/contributing/examples.rst:15 msgid "What makes a great example" msgstr "" #: ../../source/contributing/examples.rst:19 msgid "As soon as a new version of manim is released, the documentation will be a snapshot of that version. Examples contributed after the release will only be shown in the latest documentation." msgstr "" #: ../../source/contributing/examples.rst:22 msgid "Examples should be ready to copy and paste for use." msgstr "" #: ../../source/contributing/examples.rst:24 msgid "Examples should be brief yet still easy to understand." msgstr "" #: ../../source/contributing/examples.rst:26 msgid "Examples don't require the ``from manim import *`` statement, this will be added automatically when the docs are built." msgstr "" #: ../../source/contributing/examples.rst:28 msgid "There should be a balance of animated and non-animated examples." msgstr "" #: ../../source/contributing/examples.rst:30 msgid "As manim makes animations, we can include lots of animated examples; however, our RTD has a maximum 20 minutes to build. Animated examples should only be used when necessary, as last frame examples render faster." msgstr "" #: ../../source/contributing/examples.rst:32 msgid "Lots of examples (e.g. size of a plot-axis, setting opacities, making texts, etc.) will also work as images. It is a lot more convenient to see the end product immediately instead of waiting for an animation to reveal it." msgstr "" #: ../../source/contributing/examples.rst:34 msgid "Please ensure the examples run on the current main branch when you contribute an example." msgstr "" #: ../../source/contributing/examples.rst:36 msgid "If the functions used are confusing for people, make sure to add comments in the example to explain what they do." msgstr "" #: ../../source/contributing/examples.rst:39 msgid "How examples are structured" msgstr "" #: ../../source/contributing/examples.rst:41 msgid "Examples can be organized into chapters and subchapters." msgstr "" #: ../../source/contributing/examples.rst:43 msgid "When you create examples, the beginning example chapter should focus on only one functionality. When the functionality is simple, multiple ideas can be illustrated under a single example." msgstr "" #: ../../source/contributing/examples.rst:45 msgid "As soon as simple functionalities are explained, the chapter may include more complex examples which build on the simpler ideas." msgstr "" #: ../../source/contributing/examples.rst:48 msgid "Writing examples" msgstr "" #: ../../source/contributing/examples.rst:50 msgid "When you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in ``rst`` format and use the manim directive (see :mod:`manim.utils.docbuild.manim_directive` ), ``.. manim::``. Every example is in its own block, and looks like this:" msgstr "" #: ../../source/contributing/examples.rst:67 msgid "In the building process of the docs, all ``rst`` files are scanned, and the manim directive (``.. manim::``) blocks are identified as scenes that will be run by the current version of manim. Here is the syntax:" msgstr "" #: ../../source/contributing/examples.rst:72 msgid "``.. manim:: [SCENE_NAME]`` has no indentation and ``SCENE_NAME`` refers to the name of the class below." msgstr "" #: ../../source/contributing/examples.rst:74 msgid "The flags are followed in the next line (no blank line here!), with the indentation level of one tab." msgstr "" #: ../../source/contributing/examples.rst:76 msgid "All possible flags can be found at :mod:`manim.utils.docbuild.manim_directive`." msgstr "" #: ../../source/contributing/examples.rst:78 msgid "In the example above, the ``Formula1`` following ``.. manim::`` is the scene that the directive expects to render; thus, in the python code, the class has the same name: ``class Formula1(Scene)``." msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/internationalization.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/internationalization.rst:3 msgid "Internationalization" msgstr "" #: ../../source/contributing/internationalization.rst:5 msgid "Thank you for your interest in localizing Manim! Please read the instructions below to get started. You are also encouraged, though not required, to join our `Discord server `__." msgstr "" #: ../../source/contributing/internationalization.rst:11 msgid "Signing up" msgstr "" #: ../../source/contributing/internationalization.rst:13 msgid "You will first need to create an account for our project. Go to our `project homepage `__ and click the sign up button at the top right hand corner. Follow the instructions to create an account. After creating an account, you should return back to our homepage. Click the Manim project to contribute translations for the main library." msgstr "" #: ../../source/contributing/internationalization.rst:21 msgid "Contributing" msgstr "" #: ../../source/contributing/internationalization.rst:24 msgid "Keep in mind that Manim is still a work in progress. Tutorials and documentation are always subject to change. When a developer implements a new feature, they are not forced to respect any translations. This means that parts of the translation might become outdated over time." msgstr "" #: ../../source/contributing/internationalization.rst:29 msgid "That being said, improving the documentation and making it more accessible is still highly encouraged. And even if your work gets outdated and requires change, you or someone else can simply adjust the translation. Your efforts are not in vail!" msgstr "" #: ../../source/contributing/internationalization.rst:35 msgid "Voting" msgstr "" #: ../../source/contributing/internationalization.rst:37 msgid "To ensure that our translations are of good quality, we use crowdsourcing and voting to approve good translations and reject bad ones. The current threshold for a translation being accepted is 3 votes; this may change as we gauge the level of activity in the community and the quality of translations." msgstr "" #: ../../source/contributing/internationalization.rst:43 msgid "To vote on translations, first click on a language you would like to help with, then click the \"translate all\" button. You should then enter the translation editor. Next to the search bar, you will see a funnel-like icon - click it and select the \"Need to Be Voted\" option to see translations that need to be voted on. You can then select a string on the left sidebar, view the translations at the bottom and vote with the + and - icons for good and poor translations respectively." msgstr "" #: ../../source/contributing/internationalization.rst:52 msgid "Translations" msgstr "" #: ../../source/contributing/internationalization.rst:54 msgid "You can also help with contributing translations directly. Follow the steps above to enter the translation editor (instead of clicking \"Translate all\", you may also choose to translate strings from a specific file by clicking them). Crowdin's on-screen tutorial should guide you through the process." msgstr "" #: ../../source/contributing/internationalization.rst:61 msgid "Translation guidelines" msgstr "" #: ../../source/contributing/internationalization.rst:63 msgid "In general, follow the conventions for technical writing in your target language. You may want to refer to similar, high quality sources (eg. Python's documentation in your language) for guidance. Note that code blocks, code literals, names and pseudonyms should be left unchanged." msgstr "" #: ../../source/contributing/internationalization.rst:69 msgid "Proofreading" msgstr "" #: ../../source/contributing/internationalization.rst:71 msgid "For certain languages with a significant number of speakers within the Manim Community, an additional step of proofreading is used after crowdsourcing to further ensure the quality of our translations. Proofreaders are trusted community members who will look over and give the final approval on translations. If you would like to be a proofreader, please email translations@manim.community with the answers to the following questions:" msgstr "" #: ../../source/contributing/internationalization.rst:79 msgid "What is your Crowdin username?" msgstr "" #: ../../source/contributing/internationalization.rst:80 msgid "What is your Discord username (optional)?" msgstr "" #: ../../source/contributing/internationalization.rst:81 msgid "What is your GitHub username (optional)?" msgstr "" #: ../../source/contributing/internationalization.rst:82 msgid "List the languages you speak, and your level of fluency with them." msgstr "" #: ../../source/contributing/internationalization.rst:83 msgid "What language(s) are you applying to be a proofreader for?" msgstr "" #: ../../source/contributing/internationalization.rst:84 msgid "Do you have any previous experience with translations?" msgstr "" #: ../../source/contributing/internationalization.rst:85 msgid "If yes, give us more details." msgstr "" #: ../../source/contributing/internationalization.rst:86 msgid "How will you ensure the quality of translations, should you become a proofreader?" msgstr "" #: ../../source/contributing/internationalization.rst:89 msgid "Please note that you don't need to have prior translation experience to be a proofreader, just a commitment to maintaining a good quality of translations." msgstr "" #: ../../source/contributing/internationalization.rst:94 msgid "Errors" msgstr "" #: ../../source/contributing/internationalization.rst:97 msgid "Source errors" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/performance.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/performance.rst:3 msgid "Improving performance" msgstr "" #: ../../source/contributing/performance.rst:5 msgid "One of Manim's main flaws as an animation library is its slow performance. As of time of writing (January 2022), the library is still very unoptimized. As such, we highly encourage contributors to help out in optimizing the code." msgstr "" #: ../../source/contributing/performance.rst:10 msgid "Profiling" msgstr "" #: ../../source/contributing/performance.rst:12 msgid "Before the library can be optimized, we first need to identify the bottlenecks in performance via profiling. There are numerous Python profilers available for this purpose; some examples include cProfile and Scalene." msgstr "" #: ../../source/contributing/performance.rst:17 msgid "Running an animation as a script" msgstr "" #: ../../source/contributing/performance.rst:19 msgid "Most instructions for profilers assume you can run the python file directly as a script from the command line. While Manim animations are usually run from the command-line, we can run them as scripts by adding something like the following to the bottom of the file:" msgstr "" #: ../../source/contributing/performance.rst:30 msgid "Where ``SceneName`` is the name of the scene you want to run. You can then run the file directly, and can thus follow the instructions for most profilers." msgstr "" #: ../../source/contributing/performance.rst:34 msgid "An example: profiling with cProfile and SnakeViz" msgstr "" #: ../../source/contributing/performance.rst:36 msgid "Install SnakeViz:" msgstr "" #: ../../source/contributing/performance.rst:42 msgid "cProfile is included with in Python's standard library and does not need to be installed." msgstr "" #: ../../source/contributing/performance.rst:44 msgid "Suppose we want to profile ``SquareToCircle``. Then we add and save the following code to ``square_to_circle.py``:" msgstr "" #: ../../source/contributing/performance.rst:64 msgid "Now run the following in the terminal:" msgstr "" #: ../../source/contributing/performance.rst:70 msgid "This will create a file called ``square_to_circle.txt``." msgstr "" #: ../../source/contributing/performance.rst:72 msgid "Now, we can run SnakeViz on the profile file:" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/references.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/references.rst:3 msgid "Adding References" msgstr "" #: ../../source/contributing/references.rst:6 msgid "Reference to types in documentation" msgstr "" #: ../../source/contributing/references.rst:8 msgid "Always specify types with the correct **role** (see https://www.sphinx-doc.org/en/1.7/domains.html#python-roles) for the sake of proper rendering. E.g.: Use ``:class:`int``` to refer to an int type, and in general ``:class:``​`` to refer to a certain class (see ``Path specification`` below). See after for more specific instructions." msgstr "" #: ../../source/contributing/references.rst:16 msgid "Path specifications" msgstr "" #: ../../source/contributing/references.rst:18 msgid "If it's on stdlib: Use ```` directly. If it's a class, just the name is enough. If it's a method (``:meth:``) or attribute (``:attr:``), dotted names may be used (e.g. ``:meth:`str.to_lower`​``)." msgstr "" #: ../../source/contributing/references.rst:23 msgid "Example: ``:class:`int`​``, ``:class:`str`​``, ``:class:`float`​``, ``:class:`bool`​``" msgstr "" #: ../../source/contributing/references.rst:26 msgid "If it's on the same file as the docstring or, for methods and attributes, under the same class, then the name may also be specified directly." msgstr "" #: ../../source/contributing/references.rst:30 msgid "Example: ``:class:`MyClass`​`` referring to a class in the same file; ``:meth:`push`​`` referring to a method in the same class; ``:meth:`MyClass.push`​`` referring to a method in a different class in the same file; ``:attr:`color`​`` referring to an attribute in the same class; ``:attr:`MyClass.color`​`` referring to an attribute in a different class in the same file." msgstr "" #: ../../source/contributing/references.rst:37 msgid "If it's on a different file, then you may either use the full dotted name (e.g. ``~manim.animations.Animation``) or simply use the shortened way (``~.Animation``). Note that, if there is ambiguity, then the full dotted name must be used where the actual class can't be deduced. Also, note the ``~`` before the path - this is so that it displays just ``Animation`` instead of the full location in the rendering. It can be removed for disambiguation purposes only." msgstr "" #: ../../source/contributing/references.rst:45 msgid "Example: ``:class:`~.Animation`​``, ``:meth:`~.VMobject.set_color`​``, ``:attr:`~.VMobject.color`​``" msgstr "" #: ../../source/contributing/references.rst:48 msgid "If it's a class from a different module, specify the full dotted syntax." msgstr "" #: ../../source/contributing/references.rst:51 msgid "Example: ``:class:`numpy.ndarray`​`` for a numpy ndarray." msgstr "" #: ../../source/contributing/references.rst:54 msgid "Reference type specifications" msgstr "" #: ../../source/contributing/references.rst:56 msgid "**The following instructions refer to types of attributes, parameters, and return values.** When specifying a type mid-text, it does not necessarily have to be typeset. However, if it's a class name, a method, or an enum's attribute/variant, then it is recommended to be typeset at least on the first occurrence of the name so that the users can quickly jump to the related documentation." msgstr "" #: ../../source/contributing/references.rst:63 msgid "Class names should be wrapped in ``:class:`path_goes_here`​``. See examples in the subsection above." msgstr "" #: ../../source/contributing/references.rst:65 msgid "Method names should be wrapped in ``:meth:`path_goes_here`​``. See examples in the subsection above." msgstr "" #: ../../source/contributing/references.rst:67 msgid "Attribute names should be wrapped in ``:attr:`path_goes_here`​``. See examples in the subsection above." msgstr "" #: ../../source/contributing/references.rst:69 msgid "If ``None`` can also be specified, use ``Optional[type]``, where ``type`` must follow the guidelines in the current section." msgstr "" #: ../../source/contributing/references.rst:72 msgid "Example: ``Optional[:class:`str`]`` means you can either specify a ``str`` or ``None``." msgstr "" #: ../../source/contributing/references.rst:75 msgid "If more than one type is possible, use ``Union[type_1, type_2, (...), type_n]``, where all the ``type_n`` must follow the guidelines in the current section. Note that, if one of these types is ``None``, then the Union should be wrapped with ``Optional`` instead." msgstr "" #: ../../source/contributing/references.rst:81 msgid "Example: ``Union[:class:`str`, :class:`int`]`` for either ``str`` or ``int``. ``Optional[Union[:class:`int`, :class:`bool`]]`` for either ``int``, ``bool`` or ``None``." msgstr "" #: ../../source/contributing/references.rst:85 msgid "**Dictionaries:** Use ``Dict[key_type, value_type]``, where ``key_type`` and ``value_type`` must follow the guidelines in the current section." msgstr "" #: ../../source/contributing/references.rst:89 msgid "Example: ``Dict[:class:`str`, :class:`~.Mobject`]`` is a dictionary that maps strings to Mobjects. ``Dict[:class:`str`, Union[:class:`int`, :class:`MyClass`]]`` is a dictionary that maps a string to either an int or an instance of ``MyClass``." msgstr "" #: ../../source/contributing/references.rst:95 msgid "**If the parameter is a list:** Note that it is very rare to require the parameter to be exactly a ``list`` type. One could usually specify a ``tuple`` instead, for example. So, in order to cover all cases, consider:" msgstr "" #: ../../source/contributing/references.rst:100 msgid "If the parameter only needs to be an ``Iterable``, i.e., if the function only requires being able to iterate over this parameter's value (e.g. can be a ``list``, ``tuple``, ``str``, but also ``zip()``, ``iter()`` and so on), then specify ``Iterable[type_here]``, where ``type_here`` is the type of the iterable's yielded elements and should follow the format in the present section (``Type specifications``)." msgstr "" #: ../../source/contributing/references.rst:108 msgid "Example: ``Iterable[:class:`str`]`` for any iterable of strings; ``Iterable[:class:`~.Mobject`]`` for an iterable of Mobjects; etc." msgstr "" #: ../../source/contributing/references.rst:111 msgid "If you require being able to index the parameter (i.e. ``x[n]``) or retrieve its length (i.e. ``len(x)``), or even just pass it to a function that requires any of those, then specify ``Sequence``, which allows any list-like object to be specified (e.g. ``list``, ``tuple``...)" msgstr "" #: ../../source/contributing/references.rst:117 msgid "Example: ``Sequence[:class:`str`]`` for a sequence of strings; ``Sequence[Union[:class:`str`, :class:`int`]]`` for a sequence of integers or strings." msgstr "" #: ../../source/contributing/references.rst:121 msgid "If you EXPLICITLY REQUIRE it to be a ``list`` for some reason, then use ``List[type]``, where ``type`` is the type that any element in the list will have. It must follow the guidelines in the current section." msgstr "" #: ../../source/contributing/references.rst:126 msgid "**If the return type is a list or tuple:** Specify ``List[type]`` for a list, ``Tuple[type_a, type_b, (...), type_n]`` for a tuple (if the elements are all different) or ``Tuple[type, ...]`` (if all elements have the same type). Each ``type_n`` on those representations corresponds to elements in the returned list/tuple and must follow the guidelines in the current section." msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/testing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/testing.rst:3 msgid "Adding Tests" msgstr "" #: ../../source/contributing/testing.rst:4 msgid "If you are adding new features to manim, you should add appropriate tests for them. Tests prevent manim from breaking at each change by checking that no other feature has been broken and/or been unintentionally modified." msgstr "" #: ../../source/contributing/testing.rst:9 msgid "How Manim tests" msgstr "" #: ../../source/contributing/testing.rst:11 msgid "Manim uses pytest as its testing framework. To start the testing process, go to the root directory of the project and run pytest in your terminal. Any errors that occur during testing will be displayed in the terminal." msgstr "" #: ../../source/contributing/testing.rst:15 msgid "Some useful pytest flags:" msgstr "" #: ../../source/contributing/testing.rst:17 msgid "``-x`` will make pytest stop at the first failure it encounters" msgstr "" #: ../../source/contributing/testing.rst:19 msgid "``-s`` will make pytest display all the print messages (including those during scene generation, like DEBUG messages)" msgstr "" #: ../../source/contributing/testing.rst:21 msgid "``--skip_slow`` will skip the (arbitrarily) slow tests" msgstr "" #: ../../source/contributing/testing.rst:23 msgid "``--show_diff`` will show a visual comparison in case a unit test is failing." msgstr "" #: ../../source/contributing/testing.rst:27 msgid "How it Works" msgstr "" #: ../../source/contributing/testing.rst:29 msgid "At the moment there are three types of tests:" msgstr "" #: ../../source/contributing/testing.rst:31 msgid "Unit Tests:" msgstr "" #: ../../source/contributing/testing.rst:33 msgid "Tests for most of the basic functionalities of manim. For example, there a test for ``Mobject``, that checks if it can be added to a Scene, etc." msgstr "" #: ../../source/contributing/testing.rst:36 msgid "Graphical unit tests: Because ``manim`` is a graphics library, we test frames. To do so, we create test scenes that render a specific feature. When pytest runs, it compares the result of the test to the control data, either at 6 fps or just the last frame. If it matches, the tests pass. If the test and control data differ, the tests fail. You can use ``--show_diff`` flag with ``pytest`` to visually see the differences." msgstr "" #: ../../source/contributing/testing.rst:42 msgid "Videos format tests:" msgstr "" #: ../../source/contributing/testing.rst:44 msgid "As Manim is a video library, we have to test videos as well. Unfortunately, we cannot directly test video content as rendered videos can differ slightly depending on the system (for reasons related to ffmpeg). Therefore, we only compare video configuration values, exported in .json." msgstr "" #: ../../source/contributing/testing.rst:51 msgid "Architecture" msgstr "" #: ../../source/contributing/testing.rst:53 msgid "The ``manim/tests`` directory looks like this:" msgstr "" #: ../../source/contributing/testing.rst:122 msgid "The Main Directories" msgstr "" #: ../../source/contributing/testing.rst:124 msgid "``control_data/``:" msgstr "" #: ../../source/contributing/testing.rst:126 msgid "The directory containing control data. ``control_data/graphical_units_data/`` contains the expected and correct frame data for graphical tests, and ``control_data/videos_data/`` contains the .json files used to check videos." msgstr "" #: ../../source/contributing/testing.rst:129 msgid "``test_graphical_units/``:" msgstr "" #: ../../source/contributing/testing.rst:131 msgid "Contains graphical tests." msgstr "" #: ../../source/contributing/testing.rst:133 msgid "``test_scene_rendering/``:" msgstr "" #: ../../source/contributing/testing.rst:135 msgid "For tests that need to render a scene in some way, such as tests for CLI flags (end-to-end tests)." msgstr "" #: ../../source/contributing/testing.rst:138 msgid "``utils/``:" msgstr "" #: ../../source/contributing/testing.rst:140 msgid "Useful internal functions used by pytest." msgstr "" #: ../../source/contributing/testing.rst:142 msgid "fixtures are not contained here, they are in ``conftest.py``." msgstr "" #: ../../source/contributing/testing.rst:144 msgid "``helpers/``:" msgstr "" #: ../../source/contributing/testing.rst:146 msgid "Helper functions for developers to setup graphical/video tests." msgstr "" #: ../../source/contributing/testing.rst:149 msgid "Adding a New Test" msgstr "" #: ../../source/contributing/testing.rst:152 msgid "Unit Tests" msgstr "" #: ../../source/contributing/testing.rst:154 msgid "Pytest determines which functions are tests by searching for files whose names begin with \"test\\_\", and then within those files for functions beginning with \"test\" and classes beginning with \"Test\". These kinds of tests must be in ``tests/`` (e.g. ``tests/test_container.py``)." msgstr "" #: ../../source/contributing/testing.rst:160 msgid "Graphical Unit Test" msgstr "" #: ../../source/contributing/testing.rst:162 msgid "The test must be written in the correct file (i.e. the file that corresponds to the appropriate category the feature belongs to) and follow the structure of unit tests." msgstr "" #: ../../source/contributing/testing.rst:165 msgid "For example, to test the ``Circle`` VMobject which resides in ``manim/mobject/geometry.py``, add the CircleTest to ``test/test_geometry.py``." msgstr "" #: ../../source/contributing/testing.rst:169 msgid "The name of the module is indicated by the variable __module_test__, that **must** be declared in any graphical test file. The module name is used to store the graphical control data." msgstr "" #: ../../source/contributing/testing.rst:172 msgid "You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a parameter named ``scene`` that will be used like ``self`` in a standard ``construct`` method." msgstr "" #: ../../source/contributing/testing.rst:175 msgid "Here's an example in ``test_geometry.py``:" msgstr "" #: ../../source/contributing/testing.rst:190 msgid "The decorator can be used with or without parentheses. **By default, the test only tests the last frame. To enable multi-frame testing, you have to set ``last_frame=False`` in the parameters.**" msgstr "" #: ../../source/contributing/testing.rst:199 msgid "You can also specify, when needed, which base scene you need (ThreeDScene, for example) :" msgstr "" #: ../../source/contributing/testing.rst:208 msgid "Feel free to check the documentation of ``@frames_comparison`` for more." msgstr "" #: ../../source/contributing/testing.rst:210 msgid "Note that tests name must follow the syntax ``test_``, otherwise pytest will not recognize it as a test." msgstr "" #: ../../source/contributing/testing.rst:213 msgid "If you run pytest now, you will get a ``FileNotFound`` error. This is because you have not created control data for your test." msgstr "" #: ../../source/contributing/testing.rst:216 msgid "To create the control data for your test, you have to use the flag ``--set_test`` along with pytest. For the example above, it would be" msgstr "" #: ../../source/contributing/testing.rst:223 msgid "(``-s`` is here to see manim logs, so you can see what's going on)." msgstr "" #: ../../source/contributing/testing.rst:225 msgid "Please make sure to add the control data to git as soon as it is produced with ``git add ``." msgstr "" #: ../../source/contributing/testing.rst:229 msgid "Videos tests" msgstr "" #: ../../source/contributing/testing.rst:231 msgid "To test videos generated, we use the decorator ``tests.utils.videos_tester.video_comparison``:" msgstr "" #: ../../source/contributing/testing.rst:254 msgid "``assert exit*\\ code == 0, err`` is used in case of the command fails to run. The decorator takes two arguments: json name and the path to where the video should be generated, starting from the ``media/`` dir." msgstr "" #: ../../source/contributing/testing.rst:258 msgid "Note the fixtures here:" msgstr "" #: ../../source/contributing/testing.rst:260 msgid "tmp_path is a pytest fixture to get a tmp_path. Manim will output here, according to the flag ``--media_dir``." msgstr "" #: ../../source/contributing/testing.rst:262 msgid "``manim_cfg_file`` fixture that return a path pointing to ``test_scene_rendering/standard_config.cfg``. It's just to shorten the code, in the case multiple tests need to use this cfg file." msgstr "" #: ../../source/contributing/testing.rst:264 msgid "``simple_scenes_path`` same as above, except for ``test_scene_rendering/simple_scene.py``" msgstr "" #: ../../source/contributing/testing.rst:266 msgid "You have to generate a ``.json`` file first to be able to test your video. To do that, use ``helpers.save_control_data_from_video``." msgstr "" #: ../../source/contributing/testing.rst:269 msgid "For instance, a test that will check if the l flag works properly will first require rendering a video using the -l flag from a scene. Then we will test (in this case, SquareToCircle), that lives in ``test_scene_rendering/simple_scene.py``. Change directories to ``tests/``, create a file (e.g. ``create\\_data.py``) that you will remove as soon as you're done. Then run:" msgstr "" #: ../../source/contributing/testing.rst:280 msgid "Running this will save ``control_data/videos_data/SquareToCircleWithlFlag.json``, which will look like this:" msgstr "" ================================================ FILE: docs/i18n/gettext/contributing/typings.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing/typings.rst:3 msgid "Adding Typings" msgstr "" #: ../../source/contributing/typings.rst:6 msgid "Adding type hints to functions and parameters" msgstr "" #: ../../source/contributing/typings.rst:9 msgid "This section is still a work in progress." msgstr "" #: ../../source/contributing/typings.rst:11 msgid "If you've never used type hints before, this is a good place to get started: https://realpython.com/python-type-checking/#hello-types." msgstr "" #: ../../source/contributing/typings.rst:14 msgid "When adding type hints to manim, there are some guidelines that should be followed:" msgstr "" #: ../../source/contributing/typings.rst:16 msgid "Coordinates have the typehint ``Sequence[float]``, e.g." msgstr "" #: ../../source/contributing/typings.rst:23 msgid "``**kwargs`` has no typehint" msgstr "" #: ../../source/contributing/typings.rst:25 msgid "Mobjects have the typehint \"Mobject\", e.g." msgstr "" #: ../../source/contributing/typings.rst:33 msgid "Colors have the typehint ``Color``, e.g." msgstr "" #: ../../source/contributing/typings.rst:40 msgid "As ``float`` and ``Union[int, float]`` are the same, use only ``float``" msgstr "" #: ../../source/contributing/typings.rst:42 msgid "For numpy arrays use the typehint ``np.ndarray``" msgstr "" #: ../../source/contributing/typings.rst:44 msgid "Functions that does not return a value should get the type hint ``None``. (This annotations help catch the kinds of subtle bugs where you are trying to use a meaningless return value. )" msgstr "" #: ../../source/contributing/typings.rst:51 msgid "Parameters that are None by default should get the type hint ``Optional``" msgstr "" #: ../../source/contributing/typings.rst:65 msgid "The ``__init__()`` method always should have None as its return type." msgstr "" #: ../../source/contributing/typings.rst:67 msgid "Functions and lambda functions should get the typehint ``Callable``" msgstr "" #: ../../source/contributing/typings.rst:74 msgid "Assuming that typical path objects are either Paths or strs, one can use the typehint ``typing.Union[str, pathlib.Path]``" msgstr "" #: ../../source/contributing/typings.rst:77 msgid "As a helper for tool for typesets, you can use `typestring-parser `_ which can be accessed by first installing it via ``pip`` - ``pip install typestring-parser`` and then using ``from typestring_parser import parse``." msgstr "" #: ../../source/contributing/typings.rst:96 msgid "Missing Sections for typehints are:" msgstr "" #: ../../source/contributing/typings.rst:97 msgid "Tools for typehinting" msgstr "" #: ../../source/contributing/typings.rst:98 msgid "Link to MyPy" msgstr "" #: ../../source/contributing/typings.rst:99 msgid "Mypy and numpy import errors: https://realpython.com/python-type-checking/#running-mypy" msgstr "" #: ../../source/contributing/typings.rst:100 msgid "Where to find the alias" msgstr "" #: ../../source/contributing/typings.rst:101 msgid "When to use Object and when to use \"Object\"." msgstr "" #: ../../source/contributing/typings.rst:102 msgid "The use of a TypeVar on the type hints for copy()." msgstr "" ================================================ FILE: docs/i18n/gettext/contributing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/contributing.rst:3 msgid "Contributing" msgstr "" #: ../../source/contributing.rst:5 msgid "Manim is currently undergoing a major refactor. In general, contributions implementing new features will not be accepted in this period. Other contributions unrelated to cleaning up the codebase may also take a longer period of time to be reviewed. This guide may quickly become outdated quickly; we highly recommend joining our `Discord server `__ to discuss any potential contributions and keep up to date with the latest developments." msgstr "" #: ../../source/contributing.rst:12 msgid "Thank you for your interest in contributing to Manim! However you have decided to contribute or interact with the community, please always be civil and respect other members of the community. If you haven't read our :doc:`code of conduct`, do so here. Manim is Free and Open Source Software (FOSS) for mathematical animations. As such, **we welcome everyone** who is interested in mathematics, pedagogy, computer animations, open-source, software development, and beyond. Manim accepts many kinds of contributions, some are detailed below:" msgstr "" #: ../../source/contributing.rst:21 msgid "Code maintenance and development" msgstr "" #: ../../source/contributing.rst:22 msgid "DevOps" msgstr "" #: ../../source/contributing.rst:23 msgid "Documentation" msgstr "" #: ../../source/contributing.rst:24 msgid "Developing educational content & narrative documentation" msgstr "" #: ../../source/contributing.rst:25 msgid "Plugins to extend Manim functionality" msgstr "" #: ../../source/contributing.rst:26 msgid "Testing (graphical, unit & video)" msgstr "" #: ../../source/contributing.rst:27 msgid "Website design and development" msgstr "" #: ../../source/contributing.rst:28 msgid "Translating documentation and docstrings" msgstr "" #: ../../source/contributing.rst:30 msgid "To get an overview of what our community is currently working on, check out `our development project board `__." msgstr "" #: ../../source/contributing.rst:34 msgid "Please ensure that you are reading the latest version of this guide by ensuring that \"latest\" is selected in the version switcher." msgstr "" ================================================ FILE: docs/i18n/gettext/examples.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/examples.rst:3 msgid "Example Gallery" msgstr "" #: ../../source/examples.rst:5 msgid "This gallery contains a collection of best practice code snippets together with their corresponding video/image output, illustrating different functionalities all across the library. These are all under the MIT license, so feel free to copy & paste them to your projects. Enjoy this taste of Manim!" msgstr "" #: ../../source/examples.rst:13 msgid "This gallery is not the only place in our documentation where you can see explicit code and video examples: there are many more in our :doc:`reference manual ` -- see, for example, our documentation for the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`, and many more." msgstr "" #: ../../source/examples.rst:19 msgid "Check out our `interactive Jupyter environment `_ which allows running the examples online, without requiring a local installation." msgstr "" #: ../../source/examples.rst:23 msgid "Also, visit our `Twitter `_ for more *manimations*!" msgstr "" #: ../../source/examples.rst:29 msgid "Basic Concepts" msgstr "" #: ../../source/examples.rst:134 msgid "Animations" msgstr "" #: ../../source/examples.rst:216 msgid "You can use multiple ValueTrackers simultaneously." msgstr "" #: ../../source/examples.rst:310 msgid "Plotting with Manim" msgstr "" #: ../../source/examples.rst:496 msgid "Special Camera Settings" msgstr "" ================================================ FILE: docs/i18n/gettext/faq/general.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/general.md:1 msgid "FAQ: General Usage" msgstr "" #: ../../source/faq/general.md:3 msgid "Why does Manim say that \"there are no scenes inside that module\"?" msgstr "" #: ../../source/faq/general.md:5 msgid "There are two main reasons why this error appears: if you have edited the file containing your `Scene` class and forgot to save it, or if you have accidentally passed the name of a wrong file to `manim`, this is a likely outcome. Check that you have spelled everything correctly." msgstr "" #: ../../source/faq/general.md:10 msgid "Otherwise you are likely mixing up Manim versions. See {ref}`this FAQ answer ` for an explanation regarding why there are different versions. Under the assumption that you are trying to use the `manim` executable from the terminal to run a scene that has been written for the community version (i.e., there is `from manim import *`, or more specifically `from manim import Scene`)" msgstr "" #: ../../source/faq/general.md:18 msgid "No matter what code I put in my file, Manim only renders a black frame! Why?" msgstr "" #: ../../source/faq/general.md:20 msgid "If you are using the usual pattern to write a `Scene`, i.e.," msgstr "" #: ../../source/faq/general.md:27 msgid "then double check whether you have spelled `construct` correctly. If the method containing your code is not called `construct` (or if you are not calling a different, custom method from `construct`), Manim will not call your method and simply output a black frame." msgstr "" #: ../../source/faq/general.md:34 msgid "What are the default measurements for Manim's scene?" msgstr "" #: ../../source/faq/general.md:36 msgid "The scene measures 8 units in height and has a default ratio of 16:9, which means that it measures {math}`8 \\cdot 16 / 9 = 14 + 2/9` units in width. The origin is in the center of the scene, which means that, for example, the upper left corner of the scene has coordinates `[-7-1/9, 4, 0]`." msgstr "" #: ../../source/faq/general.md:43 msgid "How do I find out which keyword arguments I can pass when creating a `Mobject`?" msgstr "" #: ../../source/faq/general.md:45 msgid "Let us consider some specific example, like the {class}`.Circle` class. When looking at its documentation page, only two specific keyword arguments are listed (`radius`, and `color`). Besides these concrete arguments, there is also a catchall `**kwargs` argument which captures all other arguments that are passed to `Circle`, and passes them on to the base class of {class}`.Circle`, {class}`.Arc`." msgstr "" #: ../../source/faq/general.md:51 msgid "The same holds for {class}`.Arc`: some arguments are explicitly documented, and there is again a catchall `**kwargs` argument that passes unprocessed arguments to the next base class -- and so on." msgstr "" #: ../../source/faq/general.md:55 msgid "The most important keyword arguments relevant to styling your mobjects are the ones that are documented for the base classes {class}`.VMobject` and {class}`.Mobject`." msgstr "" #: ../../source/faq/general.md:61 msgid "Can Manim render a video with transparent background?" msgstr "" #: ../../source/faq/general.md:63 msgid "Yes: simply pass the CLI flag `-t` (or its long form `--transparent`). Note that the default video file format does not support transparency, which is why Manim will output a `.mov` instead of a `.mp4` when rendering with a transparent background. Other movie file formats that support transparency can be obtained by passing `--format=webm` or `--format=gif`." msgstr "" #: ../../source/faq/general.md:72 msgid "I have watched a video where a creator ran command X, but it does not work for me. Why?" msgstr "" #: ../../source/faq/general.md:74 msgid "The video you have been watching is likely outdated. If you want to follow along, you either need to use the same version used in the video, or modify the code (in many cases it is just a method having been renamed etc.) accordingly. Check the video description, in some cases creators point out whether changes need to be applied to the code shown in the video." msgstr "" #: ../../source/faq/general.md:82 msgid "When using `Tex` or `MathTex`, some letters are missing. How can I fix this?" msgstr "" #: ../../source/faq/general.md:84 msgid "It is possible that you have to (re)build some fonts used by LaTeX. For some distributions, you can do this manually by running" msgstr "" #: ../../source/faq/general.md:89 msgid "We recommend consulting the documentation of your LaTeX distribution for more information." msgstr "" #: ../../source/faq/general.md:94 msgid "I want to translate some code from `manimgl` to `manim`, what do I do with `CONFIG` dictionaries?" msgstr "" #: ../../source/faq/general.md:96 msgid "The community maintained version has dropped the use of `CONFIG` dictionaries very early, with {doc}`version v0.2.0 ` released in January 2021." msgstr "" #: ../../source/faq/general.md:100 msgid "Before that, Manim's classes basically processed `CONFIG` dictionaries by mimicking inheritance (to properly process `CONFIG` dictionaries set by parent classes) and then assigning all of the key-value-pairs in the dictionary as attributes of the corresponding object." msgstr "" #: ../../source/faq/general.md:105 msgid "In situations where there is not much inheritance going on, or for any custom setting, you should set these attributes yourself. For example, for an old-style `Scene` with custom attributes like" msgstr "" #: ../../source/faq/general.md:114 msgid "should be written as" msgstr "" #: ../../source/faq/general.md:122 msgid "In situations where values should be properly inherited, the arguments should be added to the initialization function of the class. An old-style mobject `Thing` could look like" msgstr "" #: ../../source/faq/general.md:135 msgid "where `stroke_color` and `fill_opacity` are arguments that concern the parent class of `Thing`, and `my_awesome_argument` is a custom argument that only concerns `Thing`. A version without `CONFIG` could look like this:" msgstr "" #: ../../source/faq/general.md:150 msgid "My installation does not support converting PDF to SVG, help?" msgstr "" #: ../../source/faq/general.md:152 msgid "This is an issue with `dvisvgm`, the tool shipped with LaTeX that transforms LaTeX output to a `.svg` file that Manim can parse." msgstr "" #: ../../source/faq/general.md:156 msgid "First, make sure your ``dvisvgm`` version is at least 2.4 by checking the output of" msgstr "" #: ../../source/faq/general.md:163 msgid "If you do not know how to update `dvisvgm`, please refer to your LaTeX distributions documentation (or the documentation of your operating system, if `dvisvgm` was installed as a system package)." msgstr "" #: ../../source/faq/general.md:167 msgid "Second, check whether your ``dvisvgm`` supports PostScript specials. This is needed to convert from PDF to SVG. Run:" msgstr "" #: ../../source/faq/general.md:174 msgid "If the output to this command does **not** contain `ps dvips PostScript specials`, this is a bad sign. In this case, run" msgstr "" #: ../../source/faq/general.md:181 msgid "If the output does **not** contain `--libgs=filename`, this means your `dvisvgm` does not currently support PostScript. You must get another binary." msgstr "" #: ../../source/faq/general.md:184 msgid "If, however, `--libgs=filename` appears in the help, that means that your `dvisvgm` needs the Ghostscript library to support PostScript. Search for `libgs.so` (on Linux, probably in `/usr/local/lib` or `/usr/lib`) or `gsdll32.dll` (on 32-bit Windows, probably in `C:\\windows\\system32`) or `gsdll64.dll` (on 64-bit Windows, also probably in `C:\\windows\\system32`) or `libgsl.dylib` (on MacOS, probably in `/usr/local/lib` or `/opt/local/lib`). Please look carefully, as the file might be located elsewhere, e.g. in the directory where Ghostscript is installed." msgstr "" #: ../../source/faq/general.md:193 msgid "When you have found the library, try (on MacOS or Linux)" msgstr "" #: ../../source/faq/general.md:200 msgid "or (on Windows)" msgstr "" #: ../../source/faq/general.md:207 msgid "You should now see `ps dvips PostScript specials` in the output. Refer to your operating system's documentation to find out how you can set or export the environment variable ``LIBGS`` automatically whenever you open a shell." msgstr "" #: ../../source/faq/general.md:211 msgid "As a last check, you can run" msgstr "" #: ../../source/faq/general.md:217 msgid "(while still having `LIBGS` set to the correct path, of course.) If `dvisvgm` can find your Ghostscript installation, it will be shown in the output together with the version number." msgstr "" #: ../../source/faq/general.md:221 msgid "If you do not have the necessary library on your system, please refer to your operating system's documentation to find out where you can get it and how you have to install it." msgstr "" #: ../../source/faq/general.md:225 msgid "If you are unable to solve your problem, check out the [dvisvgm FAQ](https://dvisvgm.de/FAQ/)." msgstr "" #: ../../source/faq/general.md:230 msgid "Where can I find more resources for learning Manim?" msgstr "" ================================================ FILE: docs/i18n/gettext/faq/help.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/help.md:1 msgid "FAQ: Getting Help" msgstr "" #: ../../source/faq/help.md:3 msgid "How do I animate X? Why do I get error Y? Can someone help me?" msgstr "" #: ../../source/faq/help.md:5 msgid "Before asking the community, please make sure that the issue you are having is not already discussed in our {doc}`FAQ section ` sufficiently well so that you can resolve the problem yourself. You can also try to use your favorite search engine, if you are lucky you might find a blog post, a question on [StackOverflow](https://stackoverflow.com/questions/tagged/manim), or a post in the [r/manim subreddit](https://reddit.com/r/manim)." msgstr "" #: ../../source/faq/help.md:12 msgid "If this is not the case, please take a moment to properly prepare your question: the better you manage to explain what exactly it is you are struggling with, the more efficient people will be able to help you. Regardless of the platform you choose in the next step, StackOverflow has a good guide on [asking good questions](https://stackoverflow.com/help/how-to-ask)." msgstr "" #: ../../source/faq/help.md:18 msgid "As soon as you have a good idea of what exactly you want to ask, pick one of the following communication channels:" msgstr "" #: ../../source/faq/help.md:21 msgid "The community is most active [in our Discord server](https://manim.community/discord/). Click the link to join, then pick one of the `#manim-help` channels in the sidebar, and post your question there. If you are comfortable with using Discord, try to search for your problem using the search function of our server; perhaps people have been talking about it before!" msgstr "" #: ../../source/faq/help.md:26 msgid "We are also monitoring questions on [StackOverflow](https://stackoverflow.com/questions/tagged/manim) that are tagged with `manim`." msgstr "" #: ../../source/faq/help.md:29 msgid "Many people are also active in our [r/manim subreddit](https://reddit.com/r/manim), feel free to post there if you are an avid Redditor -- but be aware that Discord or StackOverflow might be better choices." msgstr "" #: ../../source/faq/help.md:32 msgid "And finally, you can also start a new [discussion on GitHub](https://github.com/ManimCommunity/manim/discussions) if you dislike all other options." msgstr "" #: ../../source/faq/help.md:35 msgid "In all of these channels, please make sure to abide by Manim's {doc}`Code of Conduct ` -- in short, be *excellent* to one another: be friendly and patient, considerate, and respectful." msgstr "" #: ../../source/faq/help.md:41 msgid "What should I do if nobody answers my question?" msgstr "" #: ../../source/faq/help.md:43 msgid "Try and see whether your question can be improved: did you include all relevant information (in case of errors: the full stack trace, the code that you were rendering, and the command you used to run Manim?). In case you used a very long example, is it possible to construct a more minimal version that has the same (faulty) behavior?" msgstr "" #: ../../source/faq/help.md:49 msgid "If you posted in one of our help channels on Discord and your question got buried, you are allowed to ping the `@Manim Helper` role to bring it to the attention of the volunteers who are willing to take a look. Please refrain from pinging the role immediately when asking your question for the first time, this is considered impolite." msgstr "" #: ../../source/faq/help.md:54 msgid "You can also try to post your question to a different channel if you feel that you are not having any success with your initial choice -- but please do not spam your question in all of our communication channels (and in particular for Discord: please don't use multiple help channels at once)." msgstr "" #: ../../source/faq/help.md:59 msgid "In the end, it is as for most open-source projects: our community members are volunteers. If you do not receive a quick answer to your question, it may be because nobody knows the answer, or because your question is not clear enough, or it could be that everyone who can help you with your problem is busy doing other things." msgstr "" #: ../../source/faq/help.md:67 msgid "The library does not behave as documented, or something broke in a new release. What should I do?" msgstr "" #: ../../source/faq/help.md:69 msgid "Sounds like you have found a bug. One of the best ways of contributing to the development of Manim is by reporting it!" msgstr "" #: ../../source/faq/help.md:72 msgid "Check our list of known issues and feature requests [in our GitHub repository](https://github.com/ManimCommunity/manim/issues). If the problem you have found is not listed there yet (use the search function; also check whether there is a corresponding closed issue, it is possible that your problem has already been resolved and will be fixed with the next release), please consider the following steps to submit a new issue." msgstr "" #: ../../source/faq/help.md:80 msgid "If you are unsure whether or not you should file a new issue for some odd behavior that you found, feel free to ask the community developers, preferably in one of our `#manim-dev` channels in [our Discord](https://manim.community/discord/)." msgstr "" #: ../../source/faq/help.md:85 msgid "Make sure you are running the latest released version of Manim, your problem might otherwise already be fixed in a more recent version. Check the {doc}`/changelog` for a full list of changes between Manim releases." msgstr "" #: ../../source/faq/help.md:89 msgid "Choose the correct category for your report when [creating a new issue](https://github.com/ManimCommunity/manim/issues/new/choose). We have dedicated issue templates for *bug reports*, *feature requests*, and *installation issues*. If your report falls into one of these categories, read the issue template carefully! Instructions are given in the `` sections of the text field. If you want to suggest a new feature without concrete implementation details, see {ref}`the instructions given in this answer `." msgstr "" #: ../../source/faq/help.md:98 msgid "For bug reports: prepare a minimal example that can be used to illustrate the issue. Examples with hundreds of lines are very inefficient and tedious to debug. Your problem needs to be reproducible for others, so please make sure to prepare a suitable example." msgstr "" #: ../../source/faq/help.md:103 msgid "This is mentioned in the bug report template as well, but it is very important: if you report that some code raises an error, make sure to include the full terminal output, from the command you used to run the library up to and including the last line with the error message. Read carefully: if the message mentions that there is another relevant log file, include this other file as well!" msgstr "" #: ../../source/faq/help.md:112 msgid "I have an idea for a really cool feature that should be implemented, where should I share my idea?" msgstr "" ================================================ FILE: docs/i18n/gettext/faq/index.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/index.rst:4 #: ../../source/faq/index.rst:4 msgid "Table of Contents" msgstr "" ================================================ FILE: docs/i18n/gettext/faq/installation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/installation.md:1 msgid "FAQ: Installation" msgstr "" #: ../../source/faq/installation.md:4 msgid "Why are there different versions of Manim?" msgstr "" #: ../../source/faq/installation.md:6 msgid "Manim was originally created by Grant Sanderson as a personal project and for use in his YouTube channel, [3Blue1Brown](https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw). As his channel gained popularity, many grew to like the style of his animations and wanted to use manim for their own projects. However, as manim was only intended for personal use, it was very difficult for other users to install and use it." msgstr "" #: ../../source/faq/installation.md:13 msgid "In late 2019, Grant started working on faster OpenGL rendering in a new branch, known as the `shaders` branch. In mid-2020, a group of developers forked it into what is now the community edition; this is the version documented on this website. In early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository -- and this is what `manimgl` is. The old version, before merging the `shaders` branch is sometimes referred to as `ManimCairo` and is, at this point, only useful for one singular purpose: rendering Grant's old videos locally on your machine. It is still available in his GitHub repository in form of the `cairo-backend` branch." msgstr "" #: ../../source/faq/installation.md:22 msgid "To summarize:" msgstr "" #: ../../source/faq/installation.md:23 msgid "[**Manim**, or **ManimCE**](https://manim.community) refers to the community maintained version of the library. This is the version documented on this website; the package name on PyPI is [`manim`](https://pypi.org/project/manim/)." msgstr "" #: ../../source/faq/installation.md:26 msgid "[ManimGL](https://github.com/3b1b/manim) is the latest released version of the version of the library developed by Grant \"3b1b\" Sanderson. It has more experimental features and breaking changes between versions are not documented. Check out its documentation [here](https://3b1b.github.io/manim/index.html); on PyPI the package name is [`manimgl`](https://pypi.org/project/manimgl/)." msgstr "" #: ../../source/faq/installation.md:31 msgid "[ManimCairo](https://github.com/3b1b/manim/tree/cairo-backend) is the name that is sometimes used for the old, pre-OpenGL version of `manimgl`. The latest version of it is available [on PyPI as `manimlib`](https://pypi.org/project/manimgl/), but note that if you intend to use it to compile some old project of Grant, you will likely have to install the exact version from the time the project was created from source." msgstr "" #: ../../source/faq/installation.md:40 msgid "Which version should I use?" msgstr "" #: ../../source/faq/installation.md:42 msgid "We recommend the community maintained version especially for beginners. It has been developed to be more stable, better tested and documented (!), and quicker to respond to community contributions. It is also perfectly reasonable to start learning with the community maintained version and then switch to a different version later on." msgstr "" #: ../../source/faq/installation.md:47 msgid "If you do not care so much about documentation or stability, and would like to use the exact same version that Grant is using, then use ManimGL." msgstr "" #: ../../source/faq/installation.md:50 msgid "And as mentioned above, ManimCairo should only be used for (re)rendering old 3Blue1Brown projects (basically 2019 and before)." msgstr "" #: ../../source/faq/installation.md:55 msgid "What are the differences between Manim, ManimGL, ManimCairo? Can I tell for which version a scene was written for?" msgstr "" #: ../../source/faq/installation.md:57 msgid "You can! The thing that usually gives it away is the `import` statement at the top of the file; depending on how the code imports Manim you can tell for which version of the code it was written for:" msgstr "" #: ../../source/faq/installation.md:61 msgid "If the code imports from `manim` (i.e., `from manim import *`, `import manim as mn`, etc.), then the code you are reading is supposed to be run with the community maintained version." msgstr "" #: ../../source/faq/installation.md:63 msgid "If the import reads `import manimlib` (or `from manimlib import *`), you are likely reading a file to be rendered with ManimGL." msgstr "" #: ../../source/faq/installation.md:65 msgid "And if the import reads `from manimlib.imports import *`, or perhaps even `from big_ol_pile_of_manim_imports import *` you are reading a snippet that is supposed to be rendered with an early, or very early version of ManimCairo, respectively." msgstr "" #: ../../source/faq/installation.md:71 msgid "How do I know which version of Manim I have installed?" msgstr "" #: ../../source/faq/installation.md:73 msgid "Assuming you can run `manim` in your terminal and there is some output, check the first line of the text being produced. If you are using the community maintained version, the first line of any output will be `Manim Community `. If it does not say that, you are likely using ManimGL." msgstr "" #: ../../source/faq/installation.md:78 msgid "You can also check the list of packages you have installed: if typing `python` in your terminal spawns the interpreter that corresponds to the Python installation you use (might also be `py`, or `python3`, depending on your operating system), running `python -m pip list` will print a list of all installed packages. Check whether `manim` or `manimgl` appear in that list." msgstr "" #: ../../source/faq/installation.md:84 msgid "Similarly, you can use `python -m pip install ` and `python -m pip uninstall ` to install and uninstall packages from that list, respectively." msgstr "" #: ../../source/faq/installation.md:90 msgid "I am following the video guide X to install Manim, but some step fails. What do I do?" msgstr "" #: ../../source/faq/installation.md:92 msgid "It is only natural that there are many video guides on installing Manim out there, given that Manim is a library used for creating videos. Unfortunately however, (YouTube) videos can't be updated easily (without uploading a new one, that is) when some step in the installation process changes, and so there are many **severely outdated** resources out there." msgstr "" #: ../../source/faq/installation.md:98 msgid "This is why we strongly recommend following our {doc}`written installation guide ` to guide you through the process. In case you prefer using a video guide regardless, please check whether the creator whose guide you have been watching has made a more recent version available, and otherwise please contact them directly. Asking for help in the community will likely lead to being suggested to follow our written guide." msgstr "" #: ../../source/faq/installation.md:107 msgid "Why does ManimPango fail to install when running `pip install manim`?" msgstr "" #: ../../source/faq/installation.md:109 msgid "This most likely means that pip was not able to use our pre-built wheels of the `manimpango` dependency. Let us know (via [Discord](https://www.manim.community/discord/) or by opening a [new issue on GitHub](https://github.com/ManimCommunity/ManimPango/issues/new)) which architecture you would like to see supported, and we'll see what we can do about it." msgstr "" #: ../../source/faq/installation.md:116 msgid "To fix errors when installing `manimpango`, you need to make sure you have all the necessary build requirements. Check out the detailed instructions given in [the BUILDING section](https://github.com/ManimCommunity/ManimPango#BUILDING) of [ManimPango's README](https://github.com/ManimCommunity/ManimPango)." msgstr "" #: ../../source/faq/installation.md:123 msgid "I am using Windows and get the error `X is not recognized as an internal or external command, operable program or batch file`" msgstr "" #: ../../source/faq/installation.md:125 msgid "Regardless of whether `X` says `python` or `manim`, this means that the executable you are trying to run is not located in one of the directories your system is looking for them (specified by the `PATH` variable). Take a look at the instructions {doc}`in the installation guide for Windows `, or [this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121) to get help with editing the `PATH` variable manually." msgstr "" #: ../../source/faq/installation.md:132 msgid "If `python` is recognized but not `manim` or `pip`, you can try running commands by prepending `python -m`. That is, `manim` becomes `python -m manim`, and `pip` becomes `python -m pip`." msgstr "" #: ../../source/faq/installation.md:138 msgid "I have tried using Chocolatey (`choco install manimce`) to install Manim, but it failed!" msgstr "" #: ../../source/faq/installation.md:140 msgid "Make sure that you were running the command with administrator permissions, otherwise there can be problems. If this is not the issue, read Chocolatey's output carefully, it should mention a `.log` file containing information why the process failed." msgstr "" #: ../../source/faq/installation.md:145 msgid "You are welcome to take this file (and any other input you feel might be relevant) and submit it to Manim's community to ask for help with your problem. See the {doc}`FAQ on getting help ` for instructions." msgstr "" #: ../../source/faq/installation.md:151 msgid "On Windows, when typing `python` or `python3` the Windows store is opened, can I fix this?" msgstr "" #: ../../source/faq/installation.md:153 msgid "Yes: you can remove these aliases with these steps:" msgstr "" #: ../../source/faq/installation.md:155 msgid "Go to the Windows Setting." msgstr "" #: ../../source/faq/installation.md:156 msgid "Under *Apps and Features* you will find application execution aliases." msgstr "" #: ../../source/faq/installation.md:157 msgid "Within this menu, disable the alias(es) that are causing the issue (`python` and/or `python3`)." msgstr "" #: ../../source/faq/installation.md:162 msgid "I am using Anaconda and get an `ImportError` mentioning that some Symbol is not found." msgstr "" ================================================ FILE: docs/i18n/gettext/faq/internals.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/internals.md:1 msgid "Where can I learn more about Manim's internal structure?" msgstr "" #: ../../source/faq/internals.md:3 msgid "Efforts to document the internal structure of Manim is ongoing on our [wiki](https://github.com/ManimCommunity/manim/wiki/Developer-documentation-(WIP))." msgstr "" ================================================ FILE: docs/i18n/gettext/faq/opengl.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/faq/opengl.md:1 msgid "FAQ: OpenGL rendering" msgstr "" #: ../../source/faq/opengl.md:3 msgid "Are there any resources on how the OpenGL renderer in the community maintained version can be used?" msgstr "" #: ../../source/faq/opengl.md:5 msgid "Yes. Unfortunately, at this point, the official online documentation does not contain the relevant base classes like `OpenGLMobject` and `OpenGLVMobject` or specific OpenGL classes like `OpenGLSurface`, but documentation for some of them is available in form of docstrings [in the source code](https://github.com/ManimCommunity/manim/tree/main/manim/mobject/opengl)." msgstr "" #: ../../source/faq/opengl.md:11 msgid "Furthermore, [this user guide by *aquabeam*](https://www.aquabeam.me/manim/opengl_guide/) can be helpful to get started using the OpenGL renderer." msgstr "" #: ../../source/faq/opengl.md:16 msgid "I am trying to run an interactive scene with `--renderer=opengl` and `Scene.interactive_embed`, but an error (`sqlite3.ProgrammingError`) is raised. How can I fix this?" msgstr "" ================================================ FILE: docs/i18n/gettext/guides/configuration.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/guides/configuration.rst:2 msgid "Configuration" msgstr "" #: ../../source/guides/configuration.rst:4 msgid "Manim provides an extensive configuration system that allows it to adapt to many different use cases. There are many configuration options that can be configured at different times during the scene rendering process. Each option can be configured programmatically via `the ManimConfig class`_, at the time of command invocation via `command-line arguments`_, or at the time the library is first imported via `the config files`_." msgstr "" #: ../../source/guides/configuration.rst:11 msgid "The most common, simplest, and recommended way to configure Manim is via the command-line interface (CLI), which is described directly below." msgstr "" #: ../../source/guides/configuration.rst:15 msgid "Command-line arguments" msgstr "" #: ../../source/guides/configuration.rst:17 msgid "By far the most commonly used command in the CLI is the ``render`` command, which is used to render scene(s) to an output file. It is used with the following arguments:" msgstr "" #: ../../source/guides/configuration.rst:24 msgid "However, since Manim defaults to the :code:`render` command whenever no command is specified, the following form is far more common and can be used instead:" msgstr "" #: ../../source/guides/configuration.rst:31 msgid "An example of using the above form is:" msgstr "" #: ../../source/guides/configuration.rst:37 msgid "This asks Manim to search for a Scene class called :code:`SceneOne` inside the file ``file.py`` and render it with medium quality (specified by the ``-qm`` flag)." msgstr "" #: ../../source/guides/configuration.rst:40 msgid "Another frequently used flag is ``-p`` (\"preview\"), which makes manim open the rendered video after it's done rendering." msgstr "" #: ../../source/guides/configuration.rst:43 msgid "The ``-p`` flag does not change any properties of the global ``config`` dict. The ``-p`` flag is only a command-line convenience." msgstr "" #: ../../source/guides/configuration.rst:47 msgid "Advanced examples" msgstr "" #: ../../source/guides/configuration.rst:49 msgid "To render a scene in high quality, but only output the last frame of the scene instead of the whole video, you can execute" msgstr "" #: ../../source/guides/configuration.rst:56 msgid "The following example specifies the output file name (with the :code:`-o` flag), renders only the first ten animations (:code:`-n` flag) with a white background (:code:`-c` flag), and saves the animation as a ``.gif`` instead of as a ``.mp4`` file (``--format=gif`` flag). It uses the default quality and does not try to open the file after it is rendered." msgstr "" #: ../../source/guides/configuration.rst:67 msgid "A list of all CLI flags" msgstr "" #: ../../source/guides/configuration.rst:75 msgid "The ManimConfig class" msgstr "" #: ../../source/guides/configuration.rst:77 msgid "The most direct way of configuring Manim is through the global ``config`` object, which is an instance of :class:`.ManimConfig`. Each property of this class is a config option that can be accessed either with standard attribute syntax or with dict-like syntax:" msgstr "" #: ../../source/guides/configuration.rst:88 msgid "The former is preferred; the latter is provided for backwards compatibility." msgstr "" #: ../../source/guides/configuration.rst:91 msgid "Most classes, including :class:`.Camera`, :class:`.Mobject`, and :class:`.Animation`, read some of their default configuration from the global ``config``." msgstr "" #: ../../source/guides/configuration.rst:103 msgid ":class:`.ManimConfig` is designed to keep internal consistency. For example, setting ``frame_y_radius`` will affect ``frame_height``:" msgstr "" #: ../../source/guides/configuration.rst:114 msgid "The global ``config`` object is meant to be the single source of truth for all config options. All of the other ways of setting config options ultimately change the values of the global ``config`` object." msgstr "" #: ../../source/guides/configuration.rst:118 msgid "The following example illustrates the video resolution chosen for examples rendered in our documentation with a reference frame." msgstr "" #: ../../source/guides/configuration.rst:140 msgid "The config files" msgstr "" #: ../../source/guides/configuration.rst:142 msgid "As the last example shows, executing Manim from the command line may involve using many flags simultaneously. This may become a nuisance if you must execute the same script many times in a short time period, for example, when making small incremental tweaks to your scene script. For this reason, Manim can also be configured using a configuration file. A configuration file is a file ending with the suffix ``.cfg``." msgstr "" #: ../../source/guides/configuration.rst:149 msgid "To use a local configuration file when rendering your scene, you must create a file with the name ``manim.cfg`` in the same directory as your scene code." msgstr "" #: ../../source/guides/configuration.rst:152 msgid "The config file **must** be named ``manim.cfg``. Currently, Manim does not support config files with any other name." msgstr "" #: ../../source/guides/configuration.rst:155 msgid "The config file must start with the section header ``[CLI]``. The configuration options under this header have the same name as the CLI flags and serve the same purpose. Take, for example, the following config file." msgstr "" #: ../../source/guides/configuration.rst:167 msgid "Config files are parsed with the standard python library ``configparser``. In particular, they will ignore any line that starts with a pound symbol ``#``." msgstr "" #: ../../source/guides/configuration.rst:170 msgid "Now, executing the following command" msgstr "" #: ../../source/guides/configuration.rst:176 msgid "is equivalent to executing the following command, provided that ``manim.cfg`` is in the same directory as ," msgstr "" #: ../../source/guides/configuration.rst:183 msgid "The names of the configuration options admissible in config files are exactly the same as the **long names** of the corresponding command- line flags. For example, the ``-c`` and ``--background_color`` flags are interchangeable, but the config file only accepts :code:`background_color` as an admissible option." msgstr "" #: ../../source/guides/configuration.rst:189 msgid "Since config files are meant to replace CLI flags, all CLI flags can be set via a config file. Moreover, any config option can be set via a config file, whether or not it has an associated CLI flag. See the bottom of this document for a list of all CLI flags and config options." msgstr "" #: ../../source/guides/configuration.rst:194 msgid "Manim will look for a ``manim.cfg`` config file in the same directory as the file being rendered, and **not** in the directory of execution. For example," msgstr "" #: ../../source/guides/configuration.rst:201 msgid "will use the config file found in ``path/to/file.py``, if any. It will **not** use the config file found in the current working directory, even if it exists. In this way, the user may keep different config files for different scenes or projects, and execute them with the right configuration from anywhere in the system." msgstr "" #: ../../source/guides/configuration.rst:207 msgid "The file described here is called the **folder-wide** config file because it affects all scene scripts found in the same folder." msgstr "" #: ../../source/guides/configuration.rst:212 msgid "The user config file" msgstr "" #: ../../source/guides/configuration.rst:214 msgid "As explained in the previous section, a :code:`manim.cfg` config file only affects the scene scripts in its same folder. However, the user may also create a special config file that will apply to all scenes rendered by that user. This is referred to as the **user-wide** config file, and it will apply regardless of where Manim is executed from, and regardless of where the scene script is stored." msgstr "" #: ../../source/guides/configuration.rst:221 msgid "The user-wide config file lives in a special folder, depending on the operating system." msgstr "" #: ../../source/guides/configuration.rst:224 msgid "Windows: :code:`UserDirectory`/AppData/Roaming/Manim/manim.cfg" msgstr "" #: ../../source/guides/configuration.rst:225 msgid "MacOS: :code:`UserDirectory`/.config/manim/manim.cfg" msgstr "" #: ../../source/guides/configuration.rst:226 msgid "Linux: :code:`UserDirectory`/.config/manim/manim.cfg" msgstr "" #: ../../source/guides/configuration.rst:228 msgid "Here, :code:`UserDirectory` is the user's home folder." msgstr "" #: ../../source/guides/configuration.rst:231 msgid "A user may have many **folder-wide** config files, one per folder, but only one **user-wide** config file. Different users in the same computer may each have their own user-wide config file." msgstr "" #: ../../source/guides/configuration.rst:235 msgid "Do not store scene scripts in the same folder as the user-wide config file. In this case, the behavior is undefined." msgstr "" #: ../../source/guides/configuration.rst:238 msgid "Whenever you use Manim from anywhere in the system, Manim will look for a user-wide config file and read its configuration." msgstr "" #: ../../source/guides/configuration.rst:243 msgid "Cascading config files" msgstr "" #: ../../source/guides/configuration.rst:245 msgid "What happens if you execute Manim and it finds both a folder-wide config file and a user-wide config file? Manim will read both files, but if they are incompatible, **the folder-wide file takes precedence**." msgstr "" #: ../../source/guides/configuration.rst:249 msgid "For example, take the following user-wide config file" msgstr "" #: ../../source/guides/configuration.rst:259 msgid "and the following folder-wide file" msgstr "" #: ../../source/guides/configuration.rst:267 msgid "Then, executing :code:`manim SceneName` will be equivalent to not using any config files and executing" msgstr "" #: ../../source/guides/configuration.rst:274 msgid "Any command-line flags have precedence over any config file. For example, using the previous two config files and executing :code:`manim -c RED SceneName` is equivalent to not using any config files and executing" msgstr "" #: ../../source/guides/configuration.rst:283 msgid "There is also a **library-wide** config file that determines Manim's default behavior and applies to every user of the library. It has the least precedence, so any config options in the user-wide and any folder-wide files will override the library-wide file. This is referred to as the *cascading* config file system." msgstr "" #: ../../source/guides/configuration.rst:289 msgid "**The user should not try to modify the library-wide file**. Contributors should receive explicit confirmation from the core developer team before modifying it." msgstr "" #: ../../source/guides/configuration.rst:295 msgid "Order of operations" msgstr "" #: ../../source/guides/configuration.rst:304 msgid "With so many different ways of configuring Manim, it can be difficult to know when each config option is being set. In fact, this will depend on how Manim is being used." msgstr "" #: ../../source/guides/configuration.rst:308 msgid "If Manim is imported from a module, then the configuration system will follow these steps:" msgstr "" #: ../../source/guides/configuration.rst:311 msgid "The library-wide config file is loaded." msgstr "" #: ../../source/guides/configuration.rst:312 msgid "The user-wide and folder-wide files are loaded if they exist." msgstr "" #: ../../source/guides/configuration.rst:313 msgid "All files found in the previous two steps are parsed in a single :class:`ConfigParser` object, called ``parser``. This is where *cascading* happens." msgstr "" #: ../../source/guides/configuration.rst:316 msgid ":class:`logging.Logger` is instantiated to create Manim's global ``logger`` object. It is configured using the \"logger\" section of the parser, i.e. ``parser['logger']``." msgstr "" #: ../../source/guides/configuration.rst:319 msgid ":class:`ManimConfig` is instantiated to create the global ``config`` object." msgstr "" #: ../../source/guides/configuration.rst:320 msgid "The ``parser`` from step 3 is fed into the ``config`` from step 5 via :meth:`ManimConfig.digest_parser`." msgstr "" #: ../../source/guides/configuration.rst:322 msgid "Both ``logger`` and ``config`` are exposed to the user." msgstr "" #: ../../source/guides/configuration.rst:324 msgid "If Manim is being invoked from the command line, all of the previous steps happen, and are complemented by:" msgstr "" #: ../../source/guides/configuration.rst:327 msgid "The CLI flags are parsed and fed into ``config`` via :meth:`~ManimConfig.digest_args`." msgstr "" #: ../../source/guides/configuration.rst:329 msgid "If the ``--config_file`` flag was used, a new :class:`ConfigParser` object is created with the contents of the library-wide file, the user-wide file if it exists, and the file passed via ``--config_file``. In this case, the folder-wide file, if it exists, is ignored." msgstr "" #: ../../source/guides/configuration.rst:333 msgid "The new parser is fed into ``config``." msgstr "" #: ../../source/guides/configuration.rst:334 msgid "The rest of the CLI flags are processed." msgstr "" #: ../../source/guides/configuration.rst:336 msgid "To summarize, the order of precedence for configuration options, from lowest to highest precedence is:" msgstr "" #: ../../source/guides/configuration.rst:339 msgid "Library-wide config file," msgstr "" #: ../../source/guides/configuration.rst:340 msgid "user-wide config file, if it exists," msgstr "" #: ../../source/guides/configuration.rst:341 msgid "folder-wide config file, if it exists OR custom config file, if passed via ``--config_file``," msgstr "" #: ../../source/guides/configuration.rst:343 msgid "other CLI flags, and" msgstr "" #: ../../source/guides/configuration.rst:344 msgid "any programmatic changes made after the config system is set." msgstr "" #: ../../source/guides/configuration.rst:348 msgid "A list of all config options" msgstr "" #: ../../source/guides/configuration.rst:369 msgid "Accessing CLI command options" msgstr "" #: ../../source/guides/configuration.rst:371 msgid "Entering ``manim``, or ``manim --help``, will open the main help page." msgstr "" ================================================ FILE: docs/i18n/gettext/guides/deep_dive.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/guides/deep_dive.rst:2 msgid "A deep dive into Manim's internals" msgstr "" #: ../../source/guides/deep_dive.rst:4 msgid "**Author:** `Benjamin Hackl `__" msgstr "" #: ../../source/guides/deep_dive.rst:6 msgid "Disclaimer" msgstr "" #: ../../source/guides/deep_dive.rst:8 msgid "This guide reflects the state of the library as of version ``v0.16.0`` and primarily treats the Cairo renderer. The situation in the latest version of Manim might be different; in case of substantial deviations we will add a note below." msgstr "" #: ../../source/guides/deep_dive.rst:14 msgid "Introduction" msgstr "" #: ../../source/guides/deep_dive.rst:16 msgid "Manim can be a wonderful library, if it behaves the way you would like it to, and/or the way you expect it to. Unfortunately, this is not always the case (as you probably know if you have played with some manimations yourself already). To understand where things *go wrong*, digging through the library's source code is sometimes the only option -- but in order to do that, you need to know where to start digging." msgstr "" #: ../../source/guides/deep_dive.rst:23 msgid "This article is intended as some sort of life line through the render process. We aim to give an appropriate amount of detail describing what happens when Manim reads your scene code and produces the corresponding animation. Throughout this article, we will focus on the following toy example::" msgstr "" #: ../../source/guides/deep_dive.rst:43 msgid "Before we go into details or even look at the rendered output of this scene, let us first describe verbally what happens in this *manimation*. In the first three lines of the ``construct`` method, a :class:`.Square` and a :class:`.Circle` are initialized, then the square is added to the scene. The first frame of the rendered output should thus show an orange square." msgstr "" #: ../../source/guides/deep_dive.rst:49 msgid "Then the actual animations happen: the square first transforms into a circle, then a :class:`.Dot` is created (Where do you guess the dot is located when it is first added to the scene? Answering this already requires detailed knowledge about the render process.). The dot has an updater attached to it, and as the circle moves right, the dot moves with it. In the end, all mobjects are faded out." msgstr "" #: ../../source/guides/deep_dive.rst:56 msgid "Actually rendering the code yields the following video:" msgstr "" #: ../../source/guides/deep_dive.rst:75 msgid "For this example, the output (fortunately) coincides with our expectations." msgstr "" #: ../../source/guides/deep_dive.rst:78 msgid "Overview" msgstr "" #: ../../source/guides/deep_dive.rst:80 msgid "Because there is a lot of information in this article, here is a brief overview discussing the contents of the following chapters on a very high level." msgstr "" #: ../../source/guides/deep_dive.rst:83 msgid "`Preliminaries`_: In this chapter we unravel all the steps that take place to prepare a scene for rendering; right until the point where the user-overridden ``construct`` method is ran. This includes a brief discussion on using Manim's CLI versus other means of rendering (e.g., via Jupyter notebooks, or in your Python script by calling the :meth:`.Scene.render` method yourself)." msgstr "" #: ../../source/guides/deep_dive.rst:88 msgid "`Mobject Initialization`_: For the second chapter we dive into creating and handling Mobjects, the basic elements that should be displayed in our scene. We discuss the :class:`.Mobject` base class, how there are essentially three different types of Mobjects, and then discuss the most important of them, vectorized Mobjects. In particular, we describe the internal point data structure that governs how the mechanism responsible for drawing the vectorized Mobject to the screen sets the corresponding Bézier curves. We conclude the chapter with a tour into :meth:`.Scene.add`, the bookkeeping mechanism controlling which mobjects should be rendered." msgstr "" #: ../../source/guides/deep_dive.rst:97 msgid "`Animations and the Render Loop`_: And finally, in the last chapter we walk through the instantiation of :class:`.Animation` objects (the blueprints that hold information on how Mobjects should be modified when the render loop runs), followed by a investigation of the infamous :meth:`.Scene.play` call. We will see that there are three relevant parts in a :meth:`.Scene.play` call; a part in which the passed animations and keyword arguments are processed and prepared, followed by the actual \"render loop\" in which the library steps through a time line and renders frame by frame. The final part does some post-processing to save a short video segment (\"partial movie file\") and cleanup for the next call to :meth:`.Scene.play`. In the end, after all of :meth:`.Scene.construct` has been run, the library combines the partial movie files to one video." msgstr "" #: ../../source/guides/deep_dive.rst:110 msgid "And with that, let us get *in medias res*." msgstr "" #: ../../source/guides/deep_dive.rst:113 msgid "Preliminaries" msgstr "" #: ../../source/guides/deep_dive.rst:116 msgid "Importing the library" msgstr "" #: ../../source/guides/deep_dive.rst:118 msgid "Independent of how exactly you are telling your system to render the scene, i.e., whether you run ``manim -qm -p file_name.py ToyExample``, or whether you are rendering the scene directly from the Python script via a snippet like" msgstr "" #: ../../source/guides/deep_dive.rst:129 msgid "or whether you are rendering the code in a Jupyter notebook, you are still telling your python interpreter to import the library. The usual pattern used to do this is" msgstr "" #: ../../source/guides/deep_dive.rst:136 msgid "which (while being a debatable strategy in general) imports a lot of classes and functions shipped with the library and makes them available in your global name space. I explicitly avoided stating that it imports **all** classes and functions of the library, because it does not do that: Manim makes use of the practice described in `Section 6.4.1 of the Python tutorial `__, and all module members that should be exposed to the user upon running the ``*``-import are explicitly declared in the ``__all__`` variable of the module." msgstr "" #: ../../source/guides/deep_dive.rst:144 msgid "Manim also uses this strategy internally: taking a peek at the file that is run when the import is called, ``__init__.py`` (see `here `__), you will notice that most of the code in that module is concerned with importing members from various different submodules, again using ``*``-imports." msgstr "" #: ../../source/guides/deep_dive.rst:152 msgid "If you would ever contribute a new submodule to Manim, the main ``__init__.py`` is where it would have to be listed in order to make its members accessible to users after importing the library." msgstr "" #: ../../source/guides/deep_dive.rst:156 msgid "In that file, there is one particular import at the beginning of the file however, namely::" msgstr "" #: ../../source/guides/deep_dive.rst:161 msgid "This initializes Manim's global configuration system, which is used in various places throughout the library. After the library runs this line, the current configuration options are set. The code in there takes care of reading the options in your ``.cfg`` files (all users have at least the global one that is shipped with the library) as well as correctly handling command line arguments (if you used the CLI to render)." msgstr "" #: ../../source/guides/deep_dive.rst:167 msgid "You can read more about the config system in the :doc:`corresponding thematic guide `, and if you are interested in learning more about the internals of the configuration system and how it is initialized, follow the code flow starting in `the config module's init file `__." msgstr "" #: ../../source/guides/deep_dive.rst:173 msgid "Now that the library is imported, we can turn our attention to the next step: reading your scene code (which is not particularly exciting, Python just creates a new class ``ToyExample`` based on our code; Manim is virtually not involved in that step, with the exception that ``ToyExample`` inherits from ``Scene``)." msgstr "" #: ../../source/guides/deep_dive.rst:178 msgid "However, with the ``ToyExample`` class created and ready to go, there is a new excellent question to answer: how is the code in our ``construct`` method actually executed?" msgstr "" #: ../../source/guides/deep_dive.rst:183 msgid "Scene instantiation and rendering" msgstr "" #: ../../source/guides/deep_dive.rst:185 msgid "The answer to this question depends on how exactly you are running the code. To make things a bit clearer, let us first consider the case that you have created a file ``toy_example.py`` which looks like this::" msgstr "" #: ../../source/guides/deep_dive.rst:208 msgid "With such a file, the desired scene is rendered by simply running this Python script via ``python toy_example.py``. Then, as described above, the library is imported and Python has read and defined the ``ToyExample`` class (but, read carefully: *no instance of this class has been created yet*)." msgstr "" #: ../../source/guides/deep_dive.rst:213 msgid "At this point, the interpreter is about to enter the ``tempconfig`` context manager. Even if you have not seen Manim's ``tempconfig`` before, it's name already suggests what it does: it creates a copy of the current state of the configuration, applies the changes to the key-value pairs in the passed dictionary, and upon leaving the context the original version of the configuration is restored. TL;DR: it provides a fancy way of temporarily setting configuration options." msgstr "" #: ../../source/guides/deep_dive.rst:221 msgid "Inside the context manager, two things happen: an actual ``ToyExample``-scene object is instantiated, and the ``render`` method is called. Every way of using Manim ultimately does something along of these lines, the library always instantiates the scene object and then calls its ``render`` method. To illustrate that this really is the case, let us briefly look at the two most common ways of rendering scenes:" msgstr "" #: ../../source/guides/deep_dive.rst:228 msgid "**Command Line Interface.** When using the CLI and running the command ``manim -qm -p toy_example.py ToyExample`` in your terminal, the actual entry point is Manim's ``__main__.py`` file (located `here `__. Manim uses `Click `__ to implement the command line interface, and the corresponding code is located in Manim's ``cli`` module (https://github.com/ManimCommunity/manim/tree/main/manim/cli). The corresponding code creating the scene class and calling its render method is located `here `__." msgstr "" #: ../../source/guides/deep_dive.rst:238 msgid "**Jupyter notebooks.** In Jupyter notebooks, the communication with the library is handled by the ``%%manim`` magic command, which is implemented in the ``manim.utils.ipython_magic`` module. There is :meth:`some documentation <.ManimMagic.manim>` available for the magic command, and the code creating the scene class and calling its render method is located `here `__." msgstr "" #: ../../source/guides/deep_dive.rst:246 msgid "Now that we know that either way, a :class:`.Scene` object is created, let us investigate what Manim does when that happens. When instantiating our scene object" msgstr "" #: ../../source/guides/deep_dive.rst:253 msgid "the ``Scene.__init__`` method is called, given that we did not implement our own initialization method. Inspecting the corresponding code (see `here `__) reveals that ``Scene.__init__`` first sets several attributes of the scene objects that do not depend on any configuration options set in ``config``. Then the scene inspects the value of ``config.renderer``, and based on its value, either instantiates a ``CairoRenderer`` or an ``OpenGLRenderer`` object and assigns it to its ``renderer`` attribute." msgstr "" #: ../../source/guides/deep_dive.rst:261 msgid "The scene then asks its renderer to initialize the scene by calling" msgstr "" #: ../../source/guides/deep_dive.rst:267 msgid "Inspecting both the default Cairo renderer and the OpenGL renderer shows that the ``init_scene`` method effectively makes the renderer instantiate a :class:`.SceneFileWriter` object, which basically is Manim's interface to ``ffmpeg`` and actually writes the movie file. The Cairo renderer (see the implementation `here `__) does not require any further initialization. The OpenGL renderer does some additional setup to enable the realtime rendering preview window, which we do not go into detail further here." msgstr "" #: ../../source/guides/deep_dive.rst:276 msgid "Currently, there is a lot of interplay between a scene and its renderer. This is a flaw in Manim's current architecture, and we are working on reducing this interdependency to achieve a less convoluted code flow." msgstr "" #: ../../source/guides/deep_dive.rst:280 msgid "After the renderer has been instantiated and initialized its file writer, the scene populates further initial attributes (notable mention: the ``mobjects`` attribute which keeps track of the mobjects that have been added to the scene). It is then done with its instantiation and ready to be rendered." msgstr "" #: ../../source/guides/deep_dive.rst:285 msgid "The rest of this article is concerned with the last line in our toy example script::" msgstr "" #: ../../source/guides/deep_dive.rst:289 msgid "This is where the actual magic happens." msgstr "" #: ../../source/guides/deep_dive.rst:291 msgid "Inspecting the `implementation of the render method `__ reveals that there are several hooks that can be used for pre- or postprocessing a scene. Unsurprisingly, :meth:`.Scene.render` describes the full *render cycle* of a scene. During this life cycle, there are three custom methods whose base implementation is empty and that can be overwritten to suit your purposes. In the order they are called, these customizable methods are:" msgstr "" #: ../../source/guides/deep_dive.rst:298 msgid ":meth:`.Scene.setup`, which is intended for preparing and, well, *setting up* the scene for your animation (e.g., adding initial mobjects, assigning custom attributes to your scene class, etc.)," msgstr "" #: ../../source/guides/deep_dive.rst:301 msgid ":meth:`.Scene.construct`, which is the *script* for your screen play and contains programmatic descriptions of your animations, and" msgstr "" #: ../../source/guides/deep_dive.rst:303 msgid ":meth:`.Scene.tear_down`, which is intended for any operations you might want to run on the scene after the last frame has already been rendered (for example, this could run some code that generates a custom thumbnail for the video based on the state of the objects in the scene -- this hook is more relevant for situations where Manim is used within other Python scripts)." msgstr "" #: ../../source/guides/deep_dive.rst:310 msgid "After these three methods are run, the animations have been fully rendered, and Manim calls :meth:`.CairoRenderer.scene_finished` to gracefully complete the rendering process. This checks whether any animations have been played -- and if so, it tells the :class:`.SceneFileWriter` to close the pipe to ``ffmpeg``. If not, Manim assumes that a static image should be output which it then renders using the same strategy by calling the render loop (see below) once." msgstr "" #: ../../source/guides/deep_dive.rst:318 msgid "**Back in our toy example,** the call to :meth:`.Scene.render` first triggers :meth:`.Scene.setup` (which only consists of ``pass``), followed by a call of :meth:`.Scene.construct`. At this point, our *animation script* is run, starting with the initialization of ``orange_square``." msgstr "" #: ../../source/guides/deep_dive.rst:325 msgid "Mobject Initialization" msgstr "" #: ../../source/guides/deep_dive.rst:327 msgid "Mobjects are, in a nutshell, the Python objects that represent all the *things* we want to display in our scene. Before we follow our debugger into the depths of mobject initialization code, it makes sense to discuss Manim's different types of Mobjects and their basic data structure." msgstr "" #: ../../source/guides/deep_dive.rst:334 msgid "What even is a Mobject?" msgstr "" #: ../../source/guides/deep_dive.rst:336 msgid ":class:`.Mobject` stands for *mathematical object* or *Manim object* (depends on who you ask 😄). The Python class :class:`.Mobject` is the base class for all objects that should be displayed on screen. Looking at the `initialization method `__ of :class:`.Mobject`, you will find that not too much happens in there:" msgstr "" #: ../../source/guides/deep_dive.rst:343 msgid "some initial attribute values are assigned, like ``name`` (which makes the render logs mention the name of the mobject instead of its type), ``submobjects`` (initially an empty list), ``color``, and some others." msgstr "" #: ../../source/guides/deep_dive.rst:346 msgid "Then, two methods related to *points* are called: ``reset_points`` followed by ``generate_points``," msgstr "" #: ../../source/guides/deep_dive.rst:348 msgid "and finally, ``init_colors`` is called." msgstr "" #: ../../source/guides/deep_dive.rst:350 msgid "Digging deeper, you will find that :meth:`.Mobject.reset_points` simply sets the ``points`` attribute of the mobject to an empty NumPy vector, while the other two methods, :meth:`.Mobject.generate_points` and :meth:`.Mobject.init_colors` are just implemented as ``pass``." msgstr "" #: ../../source/guides/deep_dive.rst:355 msgid "This makes sense: :class:`.Mobject` is not supposed to be used as an *actual* object that is displayed on screen; in fact the camera (which we will discuss later in more detail; it is the class that is, for the Cairo renderer, responsible for \"taking a picture\" of the current scene) does not process \"pure\" :class:`Mobjects <.Mobject>` in any way, they *cannot* even appear in the rendered output." msgstr "" #: ../../source/guides/deep_dive.rst:362 msgid "This is where different types of mobjects come into play. Roughly speaking, the Cairo renderer setup knows three different types of mobjects that can be rendered:" msgstr "" #: ../../source/guides/deep_dive.rst:366 msgid ":class:`.ImageMobject`, which represent images that you can display in your scene," msgstr "" #: ../../source/guides/deep_dive.rst:368 msgid ":class:`.PMobject`, which are very special mobjects used to represent point clouds; we will not discuss them further in this guide," msgstr "" #: ../../source/guides/deep_dive.rst:370 msgid ":class:`.VMobject`, which are *vectorized mobjects*, that is, mobjects that consist of points that are connected via curves. These are pretty much everywhere, and we will discuss them in detail in the next section." msgstr "" #: ../../source/guides/deep_dive.rst:375 msgid "... and what are VMobjects?" msgstr "" #: ../../source/guides/deep_dive.rst:377 msgid "As just mentioned, :class:`VMobjects <.VMobject>` represent vectorized mobjects. To render a :class:`.VMobject`, the camera looks at the ``points`` attribute of a :class:`.VMobject` and divides it into sets of four points each. Each of these sets is then used to construct a cubic Bézier curve with the first and last entry describing the end points of the curve (\"anchors\"), and the second and third entry describing the control points in between (\"handles\")." msgstr "" #: ../../source/guides/deep_dive.rst:386 msgid "To learn more about Bézier curves, take a look at the excellent online textbook `A Primer on Bézier curves `__ by `Pomax `__ -- there is an playground representing cubic Bézier curves `in §1 `__, the red and yellow points are \"anchors\", and the green and blue points are \"handles\"." msgstr "" #: ../../source/guides/deep_dive.rst:393 msgid "In contrast to :class:`.Mobject`, :class:`.VMobject` can be displayed on screen (even though, technically, it is still considered a base class). To illustrate how points are processed, consider the following short example of a :class:`.VMobject` with 8 points (and thus made out of 8/4 = 2 cubic Bézier curves). The resulting :class:`.VMobject` is drawn in green. The handles are drawn as red dots with a line to their closest anchor." msgstr "" #: ../../source/guides/deep_dive.rst:433 msgid "Manually setting the points of your :class:`.VMobject` is usually discouraged; there are specialized methods that can take care of that for you -- but it might be relevant when implementing your own, custom :class:`.VMobject`." msgstr "" #: ../../source/guides/deep_dive.rst:441 msgid "Squares and Circles: back to our Toy Example" msgstr "" #: ../../source/guides/deep_dive.rst:443 msgid "With a basic understanding of different types of mobjects, and an idea of how vectorized mobjects are built we can now come back to our toy example and the execution of the :meth:`.Scene.construct` method. In the first two lines of our animation script, the ``orange_square`` and the ``blue_circle`` are initialized." msgstr "" #: ../../source/guides/deep_dive.rst:450 msgid "When creating the orange square by running" msgstr "" #: ../../source/guides/deep_dive.rst:456 msgid "the initialization method of :class:`.Square`, ``Square.__init__``, is called. `Looking at the implementation `__, we can see that the ``side_length`` attribute of the square is set, and then" msgstr "" #: ../../source/guides/deep_dive.rst:466 msgid "is called. This ``super`` call is the Python way of calling the initialization function of the parent class. As :class:`.Square` inherits from :class:`.Rectangle`, the next method called is ``Rectangle.__init__``. There, only the first three lines are really relevant for us::" msgstr "" #: ../../source/guides/deep_dive.rst:476 msgid "First, the initialization function of the parent class of :class:`.Rectangle` -- :class:`.Polygon` -- is called. The four positional arguments passed are the four corners of the polygon: ``UR`` is up right (and equal to ``UP + RIGHT``), ``UL`` is up left (and equal to ``UP + LEFT``), and so forth. Before we follow our debugger deeper, let us observe what happens with the constructed polygon: the remaining two lines stretch the polygon to fit the specified width and height such that a rectangle with the desired measurements is created." msgstr "" #: ../../source/guides/deep_dive.rst:486 msgid "The initialization function of :class:`.Polygon` is particularly simple, it only calls the initialization function of its parent class, :class:`.Polygram`. There, we have almost reached the end of the chain: :class:`.Polygram` inherits from :class:`.VMobject`, whose initialization function mainly sets the values of some attributes (quite similar to ``Mobject.__init__``, but more specific to the Bézier curves that make up the mobject)." msgstr "" #: ../../source/guides/deep_dive.rst:494 msgid "After calling the initialization function of :class:`.VMobject`, the constructor of :class:`.Polygram` also does something somewhat odd: it sets the points (which, you might remember above, should actually be set in a corresponding ``generate_points`` method of :class:`.Polygram`)." msgstr "" #: ../../source/guides/deep_dive.rst:501 msgid "In several instances, the implementation of mobjects does not really stick to all aspects of Manim's interface. This is unfortunate, and increasing consistency is something that we actively work on. Help is welcome!" msgstr "" #: ../../source/guides/deep_dive.rst:506 msgid "Without going too much into detail, :class:`.Polygram` sets its ``points`` attribute via :meth:`.VMobject.start_new_path`, :meth:`.VMobject.add_points_as_corners`, which take care of setting the quadruples of anchors and handles appropriately. After the points are set, Python continues to process the call stack until it reaches the method that was first called; the initialization method of :class:`.Square`. After this, the square is initialized and assigned to the ``orange_square`` variable." msgstr "" #: ../../source/guides/deep_dive.rst:516 msgid "The initialization of ``blue_circle`` is similar to the one of ``orange_square``, with the main difference being that the inheritance chain of :class:`.Circle` is different. Let us briefly follow the trace of the debugger:" msgstr "" #: ../../source/guides/deep_dive.rst:521 msgid "The implementation of :meth:`.Circle.__init__` immediately calls the initialization method of :class:`.Arc`, as a circle in Manim is simply an arc with an angle of :math:`\\tau = 2\\pi`. When initializing the arc, some basic attributes are set (like ``Arc.radius``, ``Arc.arc_center``, ``Arc.start_angle``, and ``Arc.angle``), and then the initialization method of its parent class, :class:`.TipableVMobject`, is called (which is a rather abstract base class for mobjects which a arrow tip can be attached to). Note that in contrast to :class:`.Polygram`, this class does **not** preemptively generate the points of the circle." msgstr "" #: ../../source/guides/deep_dive.rst:532 msgid "After that, things are less exciting: :class:`.TipableVMobject` again sets some attributes relevant for adding arrow tips, and afterwards passes to the initialization method of :class:`.VMobject`. From there, :class:`.Mobject` is initialized and :meth:`.Mobject.generate_points` is called, which actually runs the method implemented in :meth:`.Arc.generate_points`." msgstr "" #: ../../source/guides/deep_dive.rst:539 msgid "After both our ``orange_square`` and the ``blue_circle`` are initialized, the square is actually added to the scene. The :meth:`.Scene.add` method is actually doing a few interesting things, so it is worth to dig a bit deeper in the next section." msgstr "" #: ../../source/guides/deep_dive.rst:546 msgid "Adding Mobjects to the Scene" msgstr "" #: ../../source/guides/deep_dive.rst:548 msgid "The code in our ``construct`` method that is run next is" msgstr "" #: ../../source/guides/deep_dive.rst:554 msgid "From a high-level point of view, :meth:`.Scene.add` adds the ``orange_square`` to the list of mobjects that should be rendered, which is stored in the ``mobjects`` attribute of the scene. However, it does so in a very careful way to avoid the situation that a mobject is being added to the scene more than once. At a first glance, this sounds like a simple task -- the problem is that ``Scene.mobjects`` is not a \"flat\" list of mobjects, but a list of mobjects which might contain mobjects themselves, and so on." msgstr "" #: ../../source/guides/deep_dive.rst:563 msgid "Stepping through the code in :meth:`.Scene.add`, we see that first it is checked whether we are currently using the OpenGL renderer (which we are not) -- adding mobjects to the scene works slightly different (and actually easier!) for the OpenGL renderer. Then, the code branch for the Cairo renderer is entered and the list of so-called foreground mobjects (which are rendered on top of all other mobjects) is added to the list of passed mobjects. This is to ensure that the foreground mobjects will stay above of the other mobjects, even after adding the new ones. In our case, the list of foreground mobjects is actually empty, and nothing changes." msgstr "" #: ../../source/guides/deep_dive.rst:574 msgid "Next, :meth:`.Scene.restructure_mobjects` is called with the list of mobjects to be added as the ``to_remove`` argument, which might sound odd at first. Practically, this ensures that mobjects are not added twice, as mentioned above: if they were present in the scene ``Scene.mobjects`` list before (even if they were contained as a child of some other mobject), they are first removed from the list. The way :meth:`.Scene.restrucutre_mobjects` works is rather aggressive: It always operates on a given list of mobjects; in the ``add`` method two different lists occur: the default one, ``Scene.mobjects`` (no extra keyword argument is passed), and ``Scene.moving_mobjects`` (which we will discuss later in more detail). It iterates through all of the members of the list, and checks whether any of the mobjects passed in ``to_remove`` are contained as children (in any nesting level). If so, **their parent mobject is deconstructed** and their siblings are inserted directly one level higher. Consider the following example::" msgstr "" #: ../../source/guides/deep_dive.rst:604 msgid "Note that the group is disbanded and the circle moves into the root layer of mobjects in ``test_scene.mobjects``." msgstr "" #: ../../source/guides/deep_dive.rst:607 msgid "After the mobject list is \"restructured\", the mobject to be added are simply appended to ``Scene.mobjects``. In our toy example, the ``Scene.mobjects`` list is actually empty, so the ``restructure_mobjects`` method does not actually do anything. The ``orange_square`` is simply added to ``Scene.mobjects``, and as the aforementioned ``Scene.moving_mobjects`` list is, at this point, also still empty, nothing happens and :meth:`.Scene.add` returns." msgstr "" #: ../../source/guides/deep_dive.rst:615 msgid "We will hear more about the ``moving_mobject`` list when we discuss the render loop. Before we do that, let us look at the next line of code in our toy example, which includes the initialization of an animation class, ::" msgstr "" #: ../../source/guides/deep_dive.rst:623 msgid "Hence it is time to talk about :class:`.Animation`." msgstr "" #: ../../source/guides/deep_dive.rst:627 msgid "Animations and the Render Loop" msgstr "" #: ../../source/guides/deep_dive.rst:630 msgid "Initializing animations" msgstr "" #: ../../source/guides/deep_dive.rst:632 msgid "Before we follow the trace of the debugger, let us briefly discuss the general structure of the (abstract) base class :class:`.Animation`. An animation object holds all the information necessary for the renderer to generate the corresponding frames. Animations (in the sense of animation objects) in Manim are *always* tied to a specific mobject; even in the case of :class:`.AnimationGroup` (which you should actually think of as an animation on a group of mobjects rather than a group of animations). Moreover, except for in a particular special case, the run time of animations is also fixed and known beforehand." msgstr "" #: ../../source/guides/deep_dive.rst:642 msgid "The initialization of animations actually is not very exciting, :meth:`.Animation.__init__` merely sets some attributes derived from the passed keyword arguments and additionally ensures that the ``Animation.starting_mobject`` and ``Animation.mobject`` attributes are populated. Once the animation is played, the ``starting_mobject`` attribute holds an unmodified copy of the mobject the animation is attached to; during the initialization it is set to a placeholder mobject. The ``mobject`` attribute is set to the mobject the animation is attached to." msgstr "" #: ../../source/guides/deep_dive.rst:652 msgid "Animations have a few special methods which are called during the render loop:" msgstr "" #: ../../source/guides/deep_dive.rst:655 msgid ":meth:`.Animation.begin`, which is called (as hinted by its name) at the beginning of every animation, so before the first frame is rendered. In it, all the required setup for the animation happens." msgstr "" #: ../../source/guides/deep_dive.rst:658 msgid ":meth:`.Animation.finish` is the counterpart to the ``begin`` method which is called at the end of the life cycle of the animation (after the last frame has been rendered)." msgstr "" #: ../../source/guides/deep_dive.rst:661 msgid ":meth:`.Animation.interpolate` is the method that updates the mobject attached to the animation to the corresponding animation completion percentage. For example, if in the render loop, ``some_animation.interpolate(0.5)`` is called, the attached mobject will be updated to the state where 50% of the animation are completed." msgstr "" #: ../../source/guides/deep_dive.rst:667 msgid "We will discuss details about these and some further animation methods once we walk through the actual render loop. For now, we continue with our toy example and the code that is run when initializing the :class:`.ReplacementTransform` animation." msgstr "" #: ../../source/guides/deep_dive.rst:672 msgid "The initialization method of :class:`.ReplacementTransform` only consists of a call to the constructor of its parent class, :class:`.Transform`, with the additional keyword argument ``replace_mobject_with_target_in_scene`` set to ``True``. :class:`.Transform` then sets attributes that control how the points of the starting mobject are deformed into the points of the target mobject, and then passes on to the initialization method of :class:`.Animation`. Other basic properties of the animation (like its ``run_time``, the ``rate_func``, etc.) are processed there -- and then the animation object is fully initialized and ready to be played." msgstr "" #: ../../source/guides/deep_dive.rst:685 msgid "The ``play`` call: preparing to enter Manim's render loop" msgstr "" #: ../../source/guides/deep_dive.rst:687 msgid "We are finally there, the render loop is in our reach. Let us walk through the code that is run when :meth:`.Scene.play` is called." msgstr "" #: ../../source/guides/deep_dive.rst:692 msgid "Recall that this article is specifically about the Cairo renderer. Up to here, things were more or less the same for the OpenGL renderer as well; while some base mobjects might be different, the control flow and lifecycle of mobjects is still more or less the same. There are more substantial differences when it comes to the rendering loop." msgstr "" #: ../../source/guides/deep_dive.rst:698 msgid "As you will see when inspecting the method, :meth:`.Scene.play` almost immediately passes over to the ``play`` method of the renderer, in our case :class:`.CairoRenderer.play`. The one thing :meth:`.Scene.play` takes care of is the management of subcaptions that you might have passed to it (see the the documentation of :meth:`.Scene.play` and :meth:`.Scene.add_subcaption` for more information)." msgstr "" #: ../../source/guides/deep_dive.rst:707 msgid "As has been said before, the communication between scene and renderer is not in a very clean state at this point, so the following paragraphs might be confusing if you don't run a debugger and step through the code yourself a bit." msgstr "" #: ../../source/guides/deep_dive.rst:712 msgid "Inside :meth:`.CairoRenderer.play`, the renderer first checks whether it may skip rendering of the current play call. This might happen, for example, when ``-s`` is passed to the CLI (i.e., only the last frame should be rendered), or when the ``-n`` flag is passed and the current play call is outside of the specified render bounds. The \"skipping status\" is updated in form of the call to :meth:`.CairoRenderer.update_skipping_status`." msgstr "" #: ../../source/guides/deep_dive.rst:719 msgid "Next, the renderer asks the scene to process the animations in the play call so that renderer obtains all of the information it needs. To be more concrete, :meth:`.Scene.compile_animation_data` is called, which then takes care of several things:" msgstr "" #: ../../source/guides/deep_dive.rst:724 msgid "The method processes all animations and the keyword arguments passed to the initial :meth:`.Scene.play` call. In particular, this means that it makes sure all arguments passed to the play call are actually animations (or ``.animate`` syntax calls, which are also assembled to be actual :class:`.Animation`-objects at that point). It also propagates any animation-related keyword arguments (like ``run_time``, or ``rate_func``) passed to :class:`.Scene.play` to each individual animation. The processed animations are then stored in the ``animations`` attribute of the scene (which the renderer later reads...)." msgstr "" #: ../../source/guides/deep_dive.rst:733 msgid "It adds all mobjects to which the animations that are played are bound to to the scene (provided the animation is not an mobject-introducing animation -- for these, the addition to the scene happens later)." msgstr "" #: ../../source/guides/deep_dive.rst:736 msgid "In case the played animation is a :class:`.Wait` animation (this is the case in a :meth:`.Scene.wait` call), the method checks whether a static image should be rendered, or whether the render loop should be processed as usual (see :meth:`.Scene.should_update_mobjects` for the exact conditions, basically it checks whether there are any time-dependent updater functions and so on)." msgstr "" #: ../../source/guides/deep_dive.rst:742 msgid "Finally, the method determines the total run time of the play call (which at this point is computed as the maximum of the run times of the passed animations). This is stored in the ``duration`` attribute of the scene." msgstr "" #: ../../source/guides/deep_dive.rst:747 msgid "After the animation data has been compiled by the scene, the renderer continues to prepare for entering the render loop. It now checks the skipping status which has been determined before. If the renderer can skip this play call, it does so: it sets the current play call hash (which we will get back to in a moment) to ``None`` and increases the time of the renderer by the determined animation run time." msgstr "" #: ../../source/guides/deep_dive.rst:754 msgid "Otherwise, the renderer checks whether or not Manim's caching system should be used. The idea of the caching system is simple: for every play call, a hash value is computed, which is then stored and upon re-rendering the scene, the hash is generated again and checked against the stored value. If it is the same, the cached output is reused, otherwise it is fully rerendered again. We will not go into details of the caching system here; if you would like to learn more, the :func:`.get_hash_from_play_call` function in the :mod:`.utils.hashing` module is essentially the entry point to the caching mechanism." msgstr "" #: ../../source/guides/deep_dive.rst:764 msgid "In the event that the animation has to be rendered, the renderer asks its :class:`.SceneFileWriter` to start a writing process. The process is started by a call to ``ffmpeg`` and opens a pipe to which rendered raw frames can be written. As long as the pipe is open, the process can be accessed via the ``writing_process`` attribute of the file writer. With the writing process in place, the renderer then asks the scene to \"begin\" the animations." msgstr "" #: ../../source/guides/deep_dive.rst:772 msgid "First, it literally *begins* all of the animations by calling their setup methods (:meth:`.Animation._setup_scene`, :meth:`.Animation.begin`). In doing so, the mobjects that are newly introduced by an animation (like via :class:`.Create` etc.) are added to the scene. Furthermore, the animation suspends updater functions being called on its mobject, and it sets its mobject to the state that corresponds to the first frame of the animation." msgstr "" #: ../../source/guides/deep_dive.rst:780 msgid "After this has happened for all animations in the current ``play`` call, the Cairo renderer determines which of the scene's mobjects can be painted statically to the background, and which ones have to be redrawn every frame. It does so by calling :meth:`.Scene.get_moving_and_static_mobjects`, and the resulting partition of mobjects is stored in the corresponding ``moving_mobjects`` and ``static_mobjects`` attributes." msgstr "" #: ../../source/guides/deep_dive.rst:790 msgid "The mechanism that determines static and moving mobjects is specific for the Cairo renderer, the OpenGL renderer works differently. Basically, moving mobjects are determined by checking whether they, any of their children, or any of the mobjects \"below\" them (in the sense of the order in which mobjects are processed in the scene) either have an update function attached, or whether they appear in one of the current animations. See the implementation of :meth:`.Scene.get_moving_mobjects` for more details." msgstr "" #: ../../source/guides/deep_dive.rst:799 msgid "Up to this very point, we did not actually render any (partial) image or movie files from the scene yet. This is, however, about to change. Before we enter the render loop, let us briefly revisit our toy example and discuss how the generic :meth:`.Scene.play` call setup looks like there." msgstr "" #: ../../source/guides/deep_dive.rst:805 msgid "For the call that plays the :class:`.ReplacementTransform`, there is no subcaption to be taken care of. The renderer then asks the scene to compile the animation data: the passed argument already is an animation (no additional preparations needed), there is no need for processing any keyword arguments (as we did not specify any additional ones to ``play``). The mobject bound to the animation, ``orange_square``, is already part of the scene (so again, no action taken). Finally, the run time is extracted (3 seconds long) and stored in ``Scene.duration``. The renderer then checks whether it should skip (it should not), then whether the animation is already cached (it is not). The corresponding animation hash value is determined and passed to the file writer, which then also calls ``ffmpeg`` to start the writing process which waits for rendered frames from the library." msgstr "" #: ../../source/guides/deep_dive.rst:821 msgid "The scene then ``begin``\\ s the animation: for the :class:`.ReplacementTransform` this means that the animation populates all of its relevant animation attributes (i.e., compatible copies of the starting and the target mobject so that it can safely interpolate between the two)." msgstr "" #: ../../source/guides/deep_dive.rst:827 msgid "The mechanism determining static and moving mobjects considers all of the scenes mobjects (at this point only the ``orange_square``), and determines that the ``orange_square`` is bound to an animation that is currently played. As a result, the square is classified as a \"moving mobject\"." msgstr "" #: ../../source/guides/deep_dive.rst:833 msgid "Time to render some frames." msgstr "" #: ../../source/guides/deep_dive.rst:837 msgid "The render loop (for real this time)" msgstr "" #: ../../source/guides/deep_dive.rst:839 msgid "As mentioned above, due to the mechanism that determines static and moving mobjects in the scene, the renderer knows which mobjects it can paint statically to the background of the scene. Practically, this means that it partially renders a scene (to produce a background image), and then when iterating through the time progression of the animation only the \"moving mobjects\" are re-painted on top of the static background." msgstr "" #: ../../source/guides/deep_dive.rst:846 msgid "The renderer calls :meth:`.CairoRenderer.save_static_frame_data`, which first checks whether there are currently any static mobjects, and if there are, it updates the frame (only with the static mobjects; more about how exactly this works in a moment) and then saves a NumPy array representing the rendered frame in the ``static_image`` attribute. In our toy example, there are no static mobjects, and so the ``static_image`` attribute is simply set to ``None``." msgstr "" #: ../../source/guides/deep_dive.rst:854 msgid "Next, the renderer asks the scene whether the current animation is a \"frozen frame\" animation, which would mean that the renderer actually does not have to repaint the moving mobjects in every frame of the time progression. It can then just take the latest static frame, and display it throughout the animation." msgstr "" #: ../../source/guides/deep_dive.rst:862 msgid "An animation is considered a \"frozen frame\" animation if only a static :class:`.Wait` animation is played. See the description of :meth:`.Scene.compile_animation_data` above, or the implementation of :meth:`.Scene.should_update_mobjects` for more details." msgstr "" #: ../../source/guides/deep_dive.rst:868 msgid "If this is not the case (just as in our toy example), the renderer then calls the :meth:`.Scene.play_internal` method, which is the integral part of the render loop (in which the library steps through the time progression of the animation and renders the corresponding frames)." msgstr "" #: ../../source/guides/deep_dive.rst:874 msgid "Within :meth:`.Scene.play_internal`, the following steps are performed:" msgstr "" #: ../../source/guides/deep_dive.rst:876 msgid "The scene determines the run time of the animations by calling :meth:`.Scene.get_run_time`. This method basically takes the maximum ``run_time`` attribute of all of the animations passed to the :meth:`.Scene.play` call." msgstr "" #: ../../source/guides/deep_dive.rst:880 msgid "Then the *time progression* is constructed via the (internal) :meth:`.Scene._get_animation_time_progression` method, which wraps the actual :meth:`.Scene.get_time_progression` method. The time progression is a ``tqdm`` `progress bar object `__ for an iterator over ``np.arange(0, run_time, 1 / config.frame_rate)``. In other words, the time progression holds the time stamps (relative to the current animations, so starting at 0 and ending at the total animation run time, with the step size determined by the render frame rate) of the timeline where a new animation frame should be rendered." msgstr "" #: ../../source/guides/deep_dive.rst:889 msgid "Then the scene iterates over the time progression: for each time stamp ``t``, :meth:`.Scene.update_to_time` is called, which ..." msgstr "" #: ../../source/guides/deep_dive.rst:892 msgid "... first computes the time passed since the last update (which might be 0, especially for the initial call) and references it as ``dt``," msgstr "" #: ../../source/guides/deep_dive.rst:894 msgid "then (in the order in which the animations are passed to :meth:`.Scene.play`) calls :meth:`.Animation.update_mobjects` to trigger all updater functions that are attached to the respective animation except for the \"main mobject\" of the animation (that is, for example, for :class:`.Transform` the unmodified copies of start and target mobject -- see :meth:`.Animation.get_all_mobjects_to_update` for more details)," msgstr "" #: ../../source/guides/deep_dive.rst:900 msgid "then the relative time progression with respect to the current animation is computed (``alpha = t / animation.run_time``), which is then used to update the state of the animation with a call to :meth:`.Animation.interpolate`." msgstr "" #: ../../source/guides/deep_dive.rst:903 msgid "After all of the passed animations have been processed, the updater functions of all mobjects in the scene, all meshes, and finally those attached to the scene itself are run." msgstr "" #: ../../source/guides/deep_dive.rst:907 msgid "At this point, the internal (Python) state of all mobjects has been updated to match the currently processed timestamp. If rendering should not be skipped, then it is now time to *take a picture*!" msgstr "" #: ../../source/guides/deep_dive.rst:913 msgid "The update of the internal state (iteration over the time progression) happens *always* once :meth:`.Scene.play_internal` is entered. This ensures that even if frames do not need to be rendered (because, e.g., the ``-n`` CLI flag has been passed, something has been cached, or because we might be in a *Section* with skipped rendering), updater functions still run correctly, and the state of the first frame that *is* rendered is kept consistent." msgstr "" #: ../../source/guides/deep_dive.rst:920 msgid "To render an image, the scene calls the corresponding method of its renderer, :meth:`.CairoRenderer.render` and passes just the list of *moving mobjects* (remember, the *static mobjects* are assumed to have already been painted statically to the background of the scene). All of the hard work then happens when the renderer updates its current frame via a call to :meth:`.CairoRenderer.update_frame`:" msgstr "" #: ../../source/guides/deep_dive.rst:926 msgid "First, the renderer prepares its :class:`.Camera` by checking whether the renderer has a ``static_image`` different from ``None`` stored already. If so, it sets the image as the *background image* of the camera via :meth:`.Camera.set_frame_to_background`, and otherwise it just resets the camera via :meth:`.Camera.reset`. The camera is then asked to capture the scene with a call to :meth:`.Camera.camture_mobjects`." msgstr "" #: ../../source/guides/deep_dive.rst:932 msgid "Things get a bit technical here, and at some point it is more efficient to delve into the implementation -- but here is a summary of what happens once the camera is asked to capture the scene:" msgstr "" #: ../../source/guides/deep_dive.rst:936 msgid "First, a flat list of mobjects is created (so submobjects get extracted from their parents). This list is then processed in groups of the same type of mobjects (e.g., a batch of vectorized mobjects, followed by a batch of image mobjects, followed by more vectorized mobjects, etc. -- in many cases there will just be one batch of vectorized mobjects)." msgstr "" #: ../../source/guides/deep_dive.rst:941 msgid "Depending on the type of the currently processed batch, the camera uses dedicated *display functions* to convert the :class:`.Mobject` Python object to a NumPy array stored in the camera's ``pixel_array`` attribute. The most important example in that context is the display function for vectorized mobjects, :meth:`.Camera.display_multiple_vectorized_mobjects`, or the more particular (in case you did not add a background image to your :class:`.VMobject`), :meth:`.Camera.display_multiple_non_background_colored_vmobjects`. This method first gets the current Cairo context, and then, for every (vectorized) mobject in the batch, calls :meth:`.Camera.display_vectorized`. There, the actual background stroke, fill, and then stroke of the mobject is drawn onto the context. See :meth:`.Camera.apply_stroke` and :meth:`.Camera.set_cairo_context_color` for more details -- but it does not get much deeper than that, in the latter method the actual Bézier curves determined by the points of the mobject are drawn; this is where the low-level interaction with Cairo happens." msgstr "" #: ../../source/guides/deep_dive.rst:957 msgid "After all batches have been processed, the camera has an image representation of the Scene at the current time stamp in form of a NumPy array stored in its ``pixel_array`` attribute. The renderer then takes this array and passes it to its :class:`.SceneFileWriter`. This concludes one iteration of the render loop, and once the time progression has been processed completely, a final bit of cleanup is performed before the :meth:`.Scene.play_internal` call is completed." msgstr "" #: ../../source/guides/deep_dive.rst:964 msgid "A TL;DR for the render loop, in the context of our toy example, reads as follows:" msgstr "" #: ../../source/guides/deep_dive.rst:966 msgid "The scene finds that a 3 second long animation (the :class:`.ReplacementTransform` changing the orange square to the blue circle) should be played. Given the requested medium render quality, the frame rate is 30 frames per second, and so the time progression with steps ``[0, 1/30, 2/30, ..., 89/30]`` is created." msgstr "" #: ../../source/guides/deep_dive.rst:970 msgid "In the internal render loop, each of these time stamps is processed: there are no updater functions, so effectively the scene updates the state of the transformation animation to the desired time stamp (for example, at time stamp ``t = 45/30``, the animation is completed to a rate of ``alpha = 0.5``)." msgstr "" #: ../../source/guides/deep_dive.rst:975 msgid "Then the scene asks the renderer to do its job. The renderer asks its camera to capture the scene, the only mobject that needs to be processed at this point is the main mobject attached to the transformation; the camera converts the current state of the mobject to entries in a NumPy array. The renderer passes this array to the file writer." msgstr "" #: ../../source/guides/deep_dive.rst:980 msgid "At the end of the loop, 90 frames have been passed to the file writer." msgstr "" #: ../../source/guides/deep_dive.rst:983 msgid "Completing the render loop" msgstr "" #: ../../source/guides/deep_dive.rst:985 msgid "The last few steps in the :meth:`.Scene.play_internal` call are not too exciting: for every animation, the corresponding :meth:`.Animation.finish` and :meth:`.Animation.clean_up_from_scene` methods are called." msgstr "" #: ../../source/guides/deep_dive.rst:991 msgid "Note that as part of :meth:`.Animation.finish`, the :meth:`.Animation.interpolate` method is called with an argument of 1.0 -- you might have noticed already that the last frame of an animation can sometimes be a bit off or incomplete. This is by current design! The last frame rendered in the render loop (and displayed for a duration of ``1 / frame_rate`` seconds in the rendered video) corresponds to the state of the animation ``1 / frame_rate`` seconds before it ends. To display the final frame as well in the video, we would need to append another ``1 / frame_rate`` seconds to the video -- which would then mean that a 1 second rendered Manim video would be slightly longer than 1 second. We decided against this at some point." msgstr "" #: ../../source/guides/deep_dive.rst:1001 msgid "In the end, the time progression is closed (which completes the displayed progress bar) in the terminal. With the closing of the time progression, the :meth:`.Scene.play_internal` call is completed, and we return to the renderer, which now orders the :class:`.SceneFileWriter` to close the movie pipe that has been opened for this animation: a partial movie file is written." msgstr "" #: ../../source/guides/deep_dive.rst:1007 msgid "This pretty much concludes the walkthrough of a :class:`.Scene.play` call, and actually there is not too much more to say for our toy example either: at this point, a partial movie file that represents playing the :class:`.ReplacementTransform` has been written. The initialization of the :class:`.Dot` happens analogous to the initialization of ``blue_circle``, which has been discussed above. The :meth:`.Mobject.add_updater` call literally just attaches a function to the ``updaters`` attribute of the ``small_dot``. And the remaining :meth:`.Scene.play` and :meth:`.Scene.wait` calls follow the exact same procedure as discussed in the render loop section above; each such call produces a corresponding partial movie file." msgstr "" #: ../../source/guides/deep_dive.rst:1018 msgid "Once the :meth:`.Scene.construct` method has been fully processed (and thus all of the corresponding partial movie files have been written), the scene calls its cleanup method :meth:`.Scene.tear_down`, and then asks its renderer to finish the scene. The renderer, in turn, asks its scene file writer to wrap things up by calling :meth:`.SceneFileWriter.finish`, which triggers the combination of the partial movie files into the final product." msgstr "" ================================================ FILE: docs/i18n/gettext/guides/index.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/guides/index.rst:4 #: ../../source/guides/index.rst:4 msgid "Table of Contents" msgstr "" ================================================ FILE: docs/i18n/gettext/guides/using_text.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/guides/using_text.rst:3 msgid "Rendering Text and Formulas" msgstr "" #: ../../source/guides/using_text.rst:5 msgid "There are two different ways by which you can render **Text** in videos:" msgstr "" #: ../../source/guides/using_text.rst:7 msgid "Using Pango (:mod:`~.text_mobject`)" msgstr "" #: ../../source/guides/using_text.rst:8 msgid "Using LaTeX (:mod:`~.tex_mobject`)" msgstr "" #: ../../source/guides/using_text.rst:10 msgid "If you want to render simple text, you should use either :class:`~.Text` or :class:`~.MarkupText`, or one of its derivatives like :class:`~.Paragraph`. See :ref:`using-text-objects` for more information." msgstr "" #: ../../source/guides/using_text.rst:14 msgid "LaTeX should be used when you need mathematical typesetting. See :ref:`rendering-with-latex` for more information." msgstr "" #: ../../source/guides/using_text.rst:20 msgid "Text Without LaTeX" msgstr "" #: ../../source/guides/using_text.rst:22 msgid "The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the `Pango library`_ to render text. With Pango, you can also render non-English alphabets like 你好 or こんにちは or 안녕하세요 or مرحبا بالعالم." msgstr "" #: ../../source/guides/using_text.rst:27 msgid "Here is a simple *Hello World* animation." msgstr "" #: ../../source/guides/using_text.rst:38 msgid "You can also use :class:`~.MarkupText` which allows the use of PangoMarkup (see the documentation of :class:`~.MarkupText` for details) to render text. For example:" msgstr "" #: ../../source/guides/using_text.rst:56 msgid "Working with :class:`~.Text`" msgstr "" #: ../../source/guides/using_text.rst:58 msgid "This section explains the properties of :class:`~.Text` and how can it be used in your animations." msgstr "" #: ../../source/guides/using_text.rst:62 msgid "Using Fonts" msgstr "" #: ../../source/guides/using_text.rst:64 msgid "You can set a different font using :attr:`~.Text.font`." msgstr "" #: ../../source/guides/using_text.rst:68 msgid "The font used must be installed in your system, and Pango should know about it. You can get a list of fonts using :func:`manimpango.list_fonts`." msgstr "" #: ../../source/guides/using_text.rst:85 msgid "Setting Slant and Weight" msgstr "" #: ../../source/guides/using_text.rst:86 msgid "Slant is the style of the Text, and it can be ``NORMAL`` (the default), ``ITALIC`` or ``OBLIQUE``. Usually, for many fonts both ``ITALIC`` and ``OBLIQUE`` look similar, but ``ITALIC`` uses **Roman Style**, whereas ``OBLIQUE`` uses **Italic Style**." msgstr "" #: ../../source/guides/using_text.rst:91 msgid "Weight specifies the boldness of a font. You can see a list of weights in :class:`manimpango.Weight`." msgstr "" #: ../../source/guides/using_text.rst:126 msgid "Using Colors" msgstr "" #: ../../source/guides/using_text.rst:128 msgid "You can set the color of the text using :attr:`~.Text.color`:" msgstr "" #: ../../source/guides/using_text.rst:138 msgid "You can use utilities like :attr:`~.Text.t2c` for coloring specific characters. This may be problematic if your text contains ligatures as explained in :ref:`iterating-text`." msgstr "" #: ../../source/guides/using_text.rst:142 msgid ":attr:`~Text.t2c` accepts two types of dictionaries," msgstr "" #: ../../source/guides/using_text.rst:144 msgid "The keys can contain indices like ``[2:-1]`` or ``[4:8]``, this works similar to how `slicing `_ works in Python. The values should be the color of the Text from :class:`~.Color`." msgstr "" #: ../../source/guides/using_text.rst:149 msgid "The keys contain words or characters which should be colored separately and the values should be the color from :class:`~.Color`:" msgstr "" #: ../../source/guides/using_text.rst:161 msgid "If you want to avoid problems when using colors (due to ligatures), consider using :class:`MarkupText`." msgstr "" #: ../../source/guides/using_text.rst:166 msgid "Using Gradients" msgstr "" #: ../../source/guides/using_text.rst:168 msgid "You can add a gradient using :attr:`~.Text.gradient`. The value must be an iterable of any length:" msgstr "" #: ../../source/guides/using_text.rst:179 msgid "You can also use :attr:`~.Text.t2g` for gradients with specific characters of the text. It shares a similar syntax to :ref:`the interface for colors `:" msgstr "" #: ../../source/guides/using_text.rst:203 msgid "Setting Line Spacing" msgstr "" #: ../../source/guides/using_text.rst:205 msgid "You can set the line spacing using :attr:`~.Text.line_spacing`:" msgstr "" #: ../../source/guides/using_text.rst:220 msgid "Disabling Ligatures" msgstr "" #: ../../source/guides/using_text.rst:222 msgid "By disabling ligatures you would get a one-to-one mapping between characters and submobjects. This fixes the issues with coloring text." msgstr "" #: ../../source/guides/using_text.rst:228 msgid "Be aware that using this method with text that heavily depends on ligatures (Arabic text) may yield unexpected results." msgstr "" #: ../../source/guides/using_text.rst:231 msgid "You can disable ligatures by passing ``disable_ligatures`` to :class:`Text`. For example:" msgstr "" #: ../../source/guides/using_text.rst:246 msgid "Iterating :class:`~.Text`" msgstr "" #: ../../source/guides/using_text.rst:248 msgid "Text objects behave like :class:`VGroups <.VGroup>`. Therefore, you can slice and index the text." msgstr "" #: ../../source/guides/using_text.rst:251 msgid "For example, you can set each letter to different color by iterating it." msgstr "" #: ../../source/guides/using_text.rst:265 msgid "Please note that `Ligature`_ can cause problems here. If you need a one-to-one mapping of characters to submobjects you should pass the ``disable_ligatures`` parameter to :class:`~.Text`. See :ref:`disable-ligatures`." msgstr "" #: ../../source/guides/using_text.rst:273 msgid "Working with :class:`~.MarkupText`" msgstr "" #: ../../source/guides/using_text.rst:275 msgid "MarkupText is similar to :class:`~.Text`, the only difference between them is that this accepts and processes PangoMarkup (which is similar to html), instead of just rendering plain text." msgstr "" #: ../../source/guides/using_text.rst:279 msgid "Consult the documentation of :class:`~.MarkupText` for more details and further references about PangoMarkup." msgstr "" #: ../../source/guides/using_text.rst:297 msgid "Text With LaTeX" msgstr "" #: ../../source/guides/using_text.rst:299 msgid "Just as you can use :class:`~.Text` to add text to your videos, you can use :class:`~.Tex` to insert LaTeX." msgstr "" #: ../../source/guides/using_text.rst:302 msgid "For example," msgstr "" #: ../../source/guides/using_text.rst:314 msgid "Note that we are using a raw string (``r'...'``) instead of a regular string (``'...'``). This is because TeX code uses a lot of special characters - like ``\\`` for example - that have special meaning within a regular python string. An alternative would have been to write ``\\\\`` to escape the backslash: ``Tex('\\\\LaTeX')``." msgstr "" #: ../../source/guides/using_text.rst:320 msgid "Working with :class:`~.MathTex`" msgstr "" #: ../../source/guides/using_text.rst:322 msgid "Everything passed to :class:`~.MathTex` is in math mode by default. To be more precise, :class:`~.MathTex` is processed within an ``align*`` environment. You can achieve a similar effect with :class:`~.Tex` by enclosing your formula with ``$`` symbols: ``$\\xrightarrow{x^6y^8}$``:" msgstr "" #: ../../source/guides/using_text.rst:339 msgid "LaTeX commands and keyword arguments" msgstr "" #: ../../source/guides/using_text.rst:341 msgid "We can use any standard LaTeX commands in the AMS maths packages. Such as the ``mathtt`` math-text type or the ``looparrowright`` arrow." msgstr "" #: ../../source/guides/using_text.rst:352 msgid "On the Manim side, the :class:`~.Tex` class also accepts attributes to change the appearance of the output. This is very similar to the :class:`~.Text` class. For example, the ``color`` keyword changes the color of the TeX mobject." msgstr "" #: ../../source/guides/using_text.rst:366 msgid "Extra LaTeX Packages" msgstr "" #: ../../source/guides/using_text.rst:368 msgid "Some commands require special packages to be loaded into the TeX template. For example, to use the ``mathscr`` script, we need to add the ``mathrsfs`` package. Since this package isn't loaded into Manim's tex template by default, we have to add it manually." msgstr "" #: ../../source/guides/using_text.rst:388 msgid "Substrings and parts" msgstr "" #: ../../source/guides/using_text.rst:390 msgid "The TeX mobject can accept multiple strings as arguments. Afterwards you can refer to the individual parts either by their index (like ``tex[1]``), or by selecting parts of the tex code. In this example, we set the color of the ``\\bigstar`` using :func:`~.set_color_by_tex`:" msgstr "" #: ../../source/guides/using_text.rst:404 msgid "Note that :func:`~.set_color_by_tex` colors the entire substring containing the Tex, not just the specific symbol or Tex expression. Consider the following example:" msgstr "" #: ../../source/guides/using_text.rst:418 msgid "As you can see, this colors the entire equation yellow, contrary to what may be expected. To color only ``x`` yellow, we have to do the following:" msgstr "" #: ../../source/guides/using_text.rst:433 msgid "By setting ``substrings_to_isolate`` to ``x``, we split up the :class:`~.MathTex` into substrings automatically and isolate the ``x`` components into individual substrings. Only then can :meth:`~.set_color_by_tex` be used to achieve the desired result." msgstr "" #: ../../source/guides/using_text.rst:438 msgid "Note that Manim also supports a custom syntax that allows splitting a TeX string into substrings easily: simply enclose parts of your formula that you want to isolate with double braces. In the string ``MathTex(r\"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}\")``, the rendered mobject will consist of the substrings ``a^2``, ``+``, ``b^2``, ``=``, and ``c^2``. This makes transformations between similar text fragments easy to write using :class:`~.TransformMatchingTex`." msgstr "" #: ../../source/guides/using_text.rst:447 msgid "Using ``index_labels`` to work with complicated strings" msgstr "" #: ../../source/guides/using_text.rst:449 msgid "You might sometimes be working with a very complicated :class:`~.MathTex` mobject that makes it difficult to work with its individual components. This is where the debugging function :func:`.index_labels` is very useful." msgstr "" #: ../../source/guides/using_text.rst:453 msgid "The method shows the index of a mobject's submobjects, allowing you to easily find the components of the mobject you would like to change." msgstr "" #: ../../source/guides/using_text.rst:472 msgid "LaTeX Maths Fonts - The Template Library" msgstr "" #: ../../source/guides/using_text.rst:474 msgid "Changing fonts in LaTeX when typesetting mathematical formulae is trickier than regular text. It requires changing the template that is used to compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates` ready for you to use. These templates will all work in math mode:" msgstr "" #: ../../source/guides/using_text.rst:491 msgid "Manim also has a :class:`~.TexTemplateLibrary` containing the TeX templates used by 3Blue1Brown. One example is the ctex template, used for typesetting Chinese script. For this to work, the ctex LaTeX package must be installed on your system. Furthermore, if you are only typesetting Text, you probably do not need :class:`~.Tex` at all, and should use :class:`~.Text` instead." msgstr "" #: ../../source/guides/using_text.rst:508 msgid "Aligning formulae" msgstr "" ================================================ FILE: docs/i18n/gettext/index.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/index.rst:7 msgid "Manim Community Edition" msgstr "" #: ../../source/index.rst:9 msgid "Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. Manim relies on Python's simplicity to generate animations programmatically, making it convenient to specify exactly how each one should run. Take a look at the :doc:`Example Gallery <../examples>` for some inspiration on how to create beautiful images and videos with Manim." msgstr "" #: ../../source/index.rst:17 msgid "First Steps" msgstr "" #: ../../source/index.rst:19 msgid "Are you new to Manim and are looking for where to get started? Then you are in the right place!" msgstr "" #: ../../source/index.rst:24 msgid "Please be aware that there are different, incompatible versions of Manim available. Check our :ref:`installation FAQ ` to learn more!" msgstr "" #: ../../source/index.rst:28 msgid "The :doc:`Installation ` section has the latest and up-to-date installation instructions for Windows, MacOS, and Linux. You can also find information on Manim's docker images and (online) notebook environments there." msgstr "" #: ../../source/index.rst:32 msgid "Want to try the library before installing it? Take a look at our interactive online playground at https://try.manim.community in form of a Jupyter notebook." msgstr "" #: ../../source/index.rst:35 msgid "In our :doc:`Tutorials ` section you will find a collection of resources that will teach you how to use Manim. In particular, the :doc:`tutorials/quickstart` tutorial teaches you Manim's basics, and in :doc:`tutorials/building_blocks` the classes used to compose your animations are described in more detail." msgstr "" #: ../../source/index.rst:43 msgid "Finding Help" msgstr "" #: ../../source/index.rst:45 msgid "Are you struggling with installing or using Manim? Don't worry, we've all been there. Here are some good resources to help you out:" msgstr "" #: ../../source/index.rst:48 msgid "Perhaps your problem is one that occurs frequently, then chances are it is addressed in our :doc:`collection of FAQs `." msgstr "" #: ../../source/index.rst:50 msgid "If you are looking for information on some specific class, look for it in the :doc:`reference manual ` and/or use the search feature of the documentation." msgstr "" #: ../../source/index.rst:53 msgid "Still no luck? Then you are welcome to ask the community for help, together we usually manage to find a solution for your problem! Consult the :doc:`FAQ page on getting help ` for instructions." msgstr "" #: ../../source/index.rst:59 msgid "Navigating the Documentation" msgstr "" #: ../../source/index.rst:61 msgid "Here are some short summaries for all of the sections in this documentation:" msgstr "" #: ../../source/index.rst:63 msgid "The :doc:`Example Gallery ` is a collection of examples (rendered videos and images together with the code they were generated from) that show a few different, simple things that you can do with Manim." msgstr "" #: ../../source/index.rst:66 msgid "The :doc:`Installation ` section has information on installing Manim." msgstr "" #: ../../source/index.rst:67 msgid "In :doc:`Tutorials & Guides ` you can find learning resources: proper tutorials that guide you through the process of creating a video are in the :doc:`Tutorial ` section; guides on specific topics are in the :doc:`Guides ` section, and the answers to frequently asked questions can be found in the :doc:`FAQ ` section." msgstr "" #: ../../source/index.rst:72 msgid "The :doc:`Reference Manual ` contains a comprehensive list of all of Manim's (documented) modules, classes, and functions. If you are somewhat familiar with Manim's module structure feel free to browse the manual directly. If you are searching for something specific, feel free to use the documentation's search feature in the sidebar. Many classes and methods come with their own illustrated examples too!" msgstr "" #: ../../source/index.rst:77 msgid "The :doc:`Plugins ` page documents how to install, write, and distribute plugins (that is, separate Python packages that extend the feature set of the core library)." msgstr "" #: ../../source/index.rst:79 msgid "Changes between versions are documented in our :doc:`Changelog `." msgstr "" #: ../../source/index.rst:80 msgid "If you are looking into contributing to the development of Manim, you can find information on how to get involved in our :doc:`Contributing ` section." msgstr "" #: ../../source/index.rst:82 msgid "And finally, the :doc:`Code of Conduct ` page has a formal description of the rules you should abide by when interacting within our community." msgstr "" #: ../../source/index.rst:86 msgid "Sharing Your Work" msgstr "" #: ../../source/index.rst:88 msgid "We'd love to hear from you and see your manimations `on Twitter `_, `Reddit `_, or `Discord `_. If you're using Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_." msgstr "" #: ../../source/index.rst:95 msgid "Index" msgstr "" ================================================ FILE: docs/i18n/gettext/installation/docker.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation/docker.rst:2 msgid "Docker" msgstr "" #: ../../source/installation/docker.rst:4 msgid "The community maintains a docker image, which can be found `on DockerHub `__. For our image ``manimcommunity/manim``, there are the following tags:" msgstr "" #: ../../source/installation/docker.rst:8 msgid "``latest``: the most recent version corresponding to `the main branch `__," msgstr "" #: ../../source/installation/docker.rst:10 msgid "``stable``: the latest released version (according to `the releases page `__)," msgstr "" #: ../../source/installation/docker.rst:12 msgid "``vX.Y.Z``: any particular released version (according to `the releases page `__)." msgstr "" #: ../../source/installation/docker.rst:17 msgid "When using Manim's CLI within a Docker container, some flags like ``-p`` (preview file) and ``-f`` (show output file in the file browser) are not supported." msgstr "" #: ../../source/installation/docker.rst:23 msgid "Basic usage of the Docker container" msgstr "" #: ../../source/installation/docker.rst:25 msgid "Assuming that you can access the docker installation on your system from a terminal (bash / PowerShell) via ``docker``, you can render a scene ``CircleToSquare`` in a file `test_scenes.py` with the following command." msgstr "" #: ../../source/installation/docker.rst:36 msgid "For Linux users there might be permission problems when letting the user in the container write to the mounted volume. Add ``--user=\"$(id -u):$(id -g)\"`` to the ``docker`` CLI arguments to prevent the creation of output files not belonging to your user." msgstr "" #: ../../source/installation/docker.rst:42 msgid "Instead of using the \"throwaway container\" approach outlined above, you can also create a named container that you can modify to your liking. First, run" msgstr "" #: ../../source/installation/docker.rst:51 msgid "to obtain an interactive shell inside your container allowing you to, e.g., install further dependencies (like texlive packages using ``tlmgr``). Exit the container as soon as you are satisfied. Then, before using it, start the container by running" msgstr "" #: ../../source/installation/docker.rst:60 msgid "which starts the container in the background. Then, to render a scene ``CircleToSquare`` in a file ``test_scenes.py``, run" msgstr "" #: ../../source/installation/docker.rst:69 msgid "Running JupyterLab via Docker" msgstr "" #: ../../source/installation/docker.rst:71 msgid "Another alternative to using the Docker image is to spin up a local JupyterLab instance. To do that, simply run" msgstr "" ================================================ FILE: docs/i18n/gettext/installation/jupyter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation/jupyter.rst:2 msgid "Jupyter Notebooks" msgstr "" #: ../../source/installation/jupyter.rst:6 msgid "Binder" msgstr "" #: ../../source/installation/jupyter.rst:8 msgid "`Binder `__ is an online platform that hosts shareable and customizable computing environments in the form of Jupyter notebooks. Manim ships with a built-in ``%%manim`` Jupyter magic command which makes it easy to use in these notebooks." msgstr "" #: ../../source/installation/jupyter.rst:13 msgid "To see an example for such an environment, visit our interactive tutorial over at https://try.manim.community/." msgstr "" #: ../../source/installation/jupyter.rst:16 msgid "It is relatively straightforward to prepare your own notebooks in a way that allows them to be shared interactively via Binder as well:" msgstr "" #: ../../source/installation/jupyter.rst:19 msgid "First, prepare a directory containing one or multiple notebooks which you would like to share in an interactive environment. You can create these notebooks by using Jupyter notebooks with a local installation of Manim, or also by working in our pre-existing `interactive tutorial environment `__." msgstr "" #: ../../source/installation/jupyter.rst:24 msgid "In the same directory containing your notebooks, add a file named ``Dockerfile`` with the following content:" msgstr "" #: ../../source/installation/jupyter.rst:33 msgid "Don't forget to change the version tag ``v0.9.0`` to the version you were working with locally when creating your notebooks." msgstr "" #: ../../source/installation/jupyter.rst:35 msgid "Make the directory with your worksheets and the ``Dockerfile`` available to the public (and in particular: to Binder!). There are `several different options to do so `__, within the community we usually work with GitHub repositories or gists." msgstr "" #: ../../source/installation/jupyter.rst:41 msgid "Once your material is publicly available, visit https://mybinder.org and follow the instructions there to generate an interactive environment for your worksheets." msgstr "" #: ../../source/installation/jupyter.rst:47 msgid "The repository containing our `interactive tutorial `__ can be found at https://github.com/ManimCommunity/jupyter_examples." msgstr "" #: ../../source/installation/jupyter.rst:53 msgid "Google Colaboratory" msgstr "" #: ../../source/installation/jupyter.rst:55 msgid "It is also possible to install Manim in a `Google Colaboratory `__ environment. In contrast to Binder, where you can customize and prepare the environment beforehand (such that Manim is already installed and ready to be used), you will have to take care of that every time you start a new notebook in Google Colab. Fortunately, this is not particularly difficult." msgstr "" #: ../../source/installation/jupyter.rst:63 msgid "After creating a new notebook, paste the following code block in a cell, then execute it." msgstr "" #: ../../source/installation/jupyter.rst:76 msgid "You should start to see Colab installing all the dependencies specified in these commands. After the execution has completed, you will be prompted to restart the runtime. Click the \"restart runtime\" button at the bottom of the cell output. You are now ready to use Manim in Colab!" msgstr "" #: ../../source/installation/jupyter.rst:81 msgid "To check that everything works as expected, first import Manim by running" msgstr "" #: ../../source/installation/jupyter.rst:87 msgid "in a new code cell. Then create another cell containing the following code::" msgstr "" ================================================ FILE: docs/i18n/gettext/installation/linux.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation/linux.rst:2 msgid "Linux" msgstr "" #: ../../source/installation/linux.rst:4 msgid "The installation instructions depend on your particular operating system and package manager. If you happen to know exactly what you are doing, you can also simply ensure that your system has:" msgstr "" #: ../../source/installation/linux.rst:8 msgid "a reasonably recent version of Python 3 (3.7–3.10)," msgstr "" #: ../../source/installation/linux.rst:9 msgid "with working Cairo bindings in the form of `pycairo `__," msgstr "" #: ../../source/installation/linux.rst:11 msgid "FFmpeg accessible from the command line as ``ffmpeg``," msgstr "" #: ../../source/installation/linux.rst:12 msgid "and `Pango `__ headers." msgstr "" #: ../../source/installation/linux.rst:14 msgid "Then, installing Manim is just a matter of running:" msgstr "" #: ../../source/installation/linux.rst:22 msgid "In light of the current efforts of migrating to rendering via OpenGL, this list might be incomplete. Please `let us know ` if you ran into missing dependencies while installing." msgstr "" #: ../../source/installation/linux.rst:27 msgid "In any case, we have also compiled instructions for several common combinations of operating systems and package managers below." msgstr "" #: ../../source/installation/linux.rst:31 msgid "Required Dependencies" msgstr "" #: ../../source/installation/linux.rst:34 msgid "apt – Ubuntu / Mint / Debian" msgstr "" #: ../../source/installation/linux.rst:36 msgid "To first update your sources, and then install Cairo, Pango, and FFmpeg simply run:" msgstr "" #: ../../source/installation/linux.rst:44 msgid "If you don't have python3-pip installed, install it via:" msgstr "" #: ../../source/installation/linux.rst:50 msgid "Then, to install Manim, run:" msgstr "" #: ../../source/installation/linux.rst:56 #: ../../source/installation/linux.rst:90 #: ../../source/installation/linux.rst:123 msgid "Continue by reading the :ref:`optional dependencies ` section." msgstr "" #: ../../source/installation/linux.rst:60 msgid "dnf – Fedora / CentOS / RHEL" msgstr "" #: ../../source/installation/linux.rst:62 msgid "To install Cairo and Pango:" msgstr "" #: ../../source/installation/linux.rst:68 msgid "In order to successfully build the ``pycairo`` wheel, you will also need the Python development headers:" msgstr "" #: ../../source/installation/linux.rst:75 msgid "FFmpeg is only available via the RPMfusion repository which you have to configure first – please consult https://rpmfusion.org/Configuration/ for instructions. Then, install FFmpeg:" msgstr "" #: ../../source/installation/linux.rst:83 msgid "At this point you have all required dependencies and can install Manim by running:" msgstr "" #: ../../source/installation/linux.rst:94 msgid "pacman – Arch / Manjaro" msgstr "" #: ../../source/installation/linux.rst:98 msgid "Thanks to *groctel*, there is a `dedicated Manim package on the AUR! `" msgstr "" #: ../../source/installation/linux.rst:101 msgid "If you don't want to use the packaged version from AUR, here is what you need to do manually: Update your package sources, then install Cairo, Pango, and FFmpeg:" msgstr "" #: ../../source/installation/linux.rst:110 msgid "If you don't have ``python-pip`` installed, get it by running:" msgstr "" #: ../../source/installation/linux.rst:116 msgid "then simply install Manim via:" msgstr "" #: ../../source/installation/linux.rst:130 msgid "Optional Dependencies" msgstr "" #: ../../source/installation/linux.rst:132 msgid "In order to make use of Manim's interface to LaTeX for, e.g., rendering equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it." msgstr "" #: ../../source/installation/linux.rst:136 msgid "You can use whichever LaTeX distribution you like or whichever is easiest to install with your package manager. Usually, `TeX Live `__ is a good candidate if you don't care too much about disk space." msgstr "" ================================================ FILE: docs/i18n/gettext/installation/macos.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation/macos.rst:2 msgid "MacOS" msgstr "" #: ../../source/installation/macos.rst:4 msgid "For the sake of simplicity, the following instructions assume that you have the popular `package manager Homebrew `__ installed. While you can certainly also install all dependencies without it, using Homebrew makes the process much easier." msgstr "" #: ../../source/installation/macos.rst:9 msgid "If you want to use Homebrew but do not have it installed yet, please follow `Homebrew's installation instructions `__." msgstr "" #: ../../source/installation/macos.rst:14 msgid "For a while after Apple released its new ARM-based processors (the *\"M1 chip\"*), the recommended way of installing Manim relied on *Rosetta*, Apple's compatibility layer between Intel and ARM architectures. This is no longer necessary, Manim can (and is recommended to) be installed natively." msgstr "" #: ../../source/installation/macos.rst:21 msgid "Required Dependencies" msgstr "" #: ../../source/installation/macos.rst:23 msgid "To install all required dependencies for installing Manim (namely: ffmpeg, Python, and some required Python packages), run:" msgstr "" #: ../../source/installation/macos.rst:30 msgid "On *Apple Silicon* based machines (i.e., devices with the M1 chip or similar; if you are unsure which processor you have check by opening the Apple menu, select *About This Mac* and check the entry next to *Chip*), some additional dependencies are required, namely:" msgstr "" #: ../../source/installation/macos.rst:39 msgid "After all required dependencies are installed, simply run:" msgstr "" #: ../../source/installation/macos.rst:45 msgid "to install Manim." msgstr "" #: ../../source/installation/macos.rst:49 msgid "A frequent source for installation problems is if ``pip3`` does not point to the correct Python installation on your system. To check this, run ``pip3 -V``: for MacOS Intel, the path should start with ``/usr/local``, and for Apple Silicon with ``/opt/homebrew``. If this is not the case, you either forgot to modify your shell profile (``.zprofile``) during the installation of Homebrew, or did not reload your shell (e.g., by opening a new terminal) after doing so. It is also possible that some other software (like Pycharm) changed the ``PATH`` variable – to fix this, make sure that the Homebrew-related lines in your ``.zprofile`` are at the very end of the file." msgstr "" #: ../../source/installation/macos.rst:63 msgid "Optional Dependencies" msgstr "" #: ../../source/installation/macos.rst:65 msgid "In order to make use of Manim's interface to LaTeX for, e.g., rendering equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it." msgstr "" #: ../../source/installation/macos.rst:69 msgid "For MacOS, the recommended LaTeX distribution is `MacTeX `__. You can install it by following the instructions from the link, or alternatively also via Homebrew by running:" msgstr "" #: ../../source/installation/macos.rst:80 msgid "MacTeX is a *full* LaTeX distribution and will require more than 4GB of disk space. If this is an issue for you, consider installing a smaller distribution like `BasicTeX `__." msgstr "" #: ../../source/installation/macos.rst:85 msgid "Should you choose to work with some partial TeX distribution, the full list of LaTeX packages which Manim interacts with in some way (a subset might be sufficient for your particular application) is::" msgstr "" #: ../../source/installation/macos.rst:96 msgid "Working with Manim" msgstr "" ================================================ FILE: docs/i18n/gettext/installation/troubleshooting.pot ================================================ ================================================ FILE: docs/i18n/gettext/installation/versions.pot ================================================ ================================================ FILE: docs/i18n/gettext/installation/windows.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation/windows.rst:2 msgid "Windows" msgstr "" #: ../../source/installation/windows.rst:4 msgid "The easiest way of installing Manim and its dependencies is by using a package manager like `Chocolatey `__ or `Scoop `__. If you are not afraid of editing your System's ``PATH``, a manual installation is also possible. In fact, if you already have an existing Python installation (3.7-3.10), it might be the easiest way to get everything up and running." msgstr "" #: ../../source/installation/windows.rst:12 msgid "If you choose to use one of the package managers, please follow their installation instructions (`for Chocolatey `__, `for Scoop `__) to make one of them available on your system." msgstr "" #: ../../source/installation/windows.rst:20 msgid "Required Dependencies" msgstr "" #: ../../source/installation/windows.rst:22 msgid "Manim requires a recent version of Python (3.7–3.10) and ``ffmpeg`` in order to work." msgstr "" #: ../../source/installation/windows.rst:26 msgid "Chocolatey" msgstr "" #: ../../source/installation/windows.rst:28 msgid "Manim can be installed via Chocolatey simply by running:" msgstr "" #: ../../source/installation/windows.rst:34 msgid "That's it, no further steps required. You can continue with installing the :ref:`optional dependencies ` below." msgstr "" #: ../../source/installation/windows.rst:38 msgid "Scoop" msgstr "" #: ../../source/installation/windows.rst:40 msgid "While there is no recipe for installing Manim with Scoop directly, you can install all requirements by running:" msgstr "" #: ../../source/installation/windows.rst:47 msgid "and then Manim can be installed by running:" msgstr "" #: ../../source/installation/windows.rst:53 msgid "Manim should now be installed on your system. Continue reading the :ref:`optional dependencies ` section below." msgstr "" #: ../../source/installation/windows.rst:58 msgid "Manual Installation" msgstr "" #: ../../source/installation/windows.rst:60 msgid "As mentioned above, Manim needs a reasonably recent version of Python 3 (3.7–3.10) and FFmpeg." msgstr "" #: ../../source/installation/windows.rst:63 msgid "**Python:** Head over to https://www.python.org, download an installer for Python (3.7–3.10), and follow its instructions to get Python installed on your system." msgstr "" #: ../../source/installation/windows.rst:69 msgid "We have received reports of problems caused by using the version of Python that can be installed from the Windows Store. At this point, we recommend staying away from the Windows Store version. Instead, install Python directly from the `official website `__." msgstr "" #: ../../source/installation/windows.rst:75 msgid "**FFmpeg:** In order to install FFmpeg, you can get a pre-compiled and ready-to-use version from one of the resources linked at https://ffmpeg.org/download.html#build-windows, such as `the version available here `__ (recommended), or if you know exactly what you are doing you can alternatively get the source code from https://ffmpeg.org/download.html and compile it yourself." msgstr "" #: ../../source/installation/windows.rst:85 msgid "After downloading the pre-compiled archive, `unzip it `__ and, if you like, move the extracted directory to some more permanent place (e.g., ``C:\\Program Files\\``). Next, edit the ``PATH`` environment variable: first, visit ``Control Panel`` > ``System`` > ``System settings`` > ``Environment Variables``, then add the full path to the ``bin`` directory inside of the (moved) ffmpeg directory to the ``PATH`` variable. Finally, save your changes and exit." msgstr "" #: ../../source/installation/windows.rst:94 msgid "If you now open a new command line prompt (or PowerShell) and run ``ffmpeg``, the command should be recognized." msgstr "" #: ../../source/installation/windows.rst:97 msgid "At this point, you have all the required dependencies and can now install Manim via" msgstr "" #: ../../source/installation/windows.rst:108 msgid "Optional Dependencies" msgstr "" #: ../../source/installation/windows.rst:110 msgid "In order to make use of Manim's interface to LaTeX to, for example, render equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it." msgstr "" #: ../../source/installation/windows.rst:114 msgid "For Windows, the recommended LaTeX distribution is `MiKTeX `__. You can install it by using the installer from the linked MiKTeX site, or by using the package manager of your choice (Chocolatey: ``choco install miktex.install``, Scoop: ``scoop install latex``)." msgstr "" #: ../../source/installation/windows.rst:120 msgid "If you are concerned about disk space, there are some alternative, smaller distributions of LaTeX." msgstr "" #: ../../source/installation/windows.rst:123 msgid "**Using Chocolatey:** If you used Chocolatey to install manim or are already a chocolatey user, then you can simply run ``choco install manim-latex``. It is a dedicated package for Manim based on TinyTeX which contains all the required packages that Manim interacts with." msgstr "" #: ../../source/installation/windows.rst:128 msgid "**Manual Installation:** You can also use `TinyTeX `__ (Chocolatey: ``choco install tinytex``, Scoop: first ``scoop bucket add r-bucket https://github.com/cderv/r-bucket.git``, then ``scoop install tinytex``) alternative installation instructions can be found at their website. Keep in mind that you will have to manage the LaTeX packages installed on your system yourself via ``tlmgr``. Therefore we only recommend this option if you know what you are doing." msgstr "" #: ../../source/installation/windows.rst:135 msgid "The full list of LaTeX packages which Manim interacts with in some way (a subset might be sufficient for your particular application) are::" msgstr "" #: ../../source/installation/windows.rst:146 msgid "Working with Manim" msgstr "" ================================================ FILE: docs/i18n/gettext/installation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/installation.rst:2 msgid "Installation" msgstr "" #: ../../source/installation.rst:4 msgid "Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try." msgstr "" #: ../../source/installation.rst:10 msgid "Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker)." msgstr "" #: ../../source/installation.rst:16 msgid "Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :ref:`differences between Manim versions ` if you are unsure which version you should install." msgstr "" #: ../../source/installation.rst:22 msgid ":ref:`Installing Manim to your system's Python `" msgstr "" #: ../../source/installation.rst:23 msgid ":ref:`Using Manim via Docker `" msgstr "" #: ../../source/installation.rst:24 msgid ":ref:`Interactive Jupyter notebooks via Binder / Google Colab `" msgstr "" #: ../../source/installation.rst:31 msgid "Installing Manim locally" msgstr "" #: ../../source/installation.rst:33 msgid "Manim is a Python library, and it can be `installed via pip `__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow." msgstr "" #: ../../source/installation.rst:39 msgid "Manim requires Python version ``3.7`` or above to run." msgstr "" #: ../../source/installation.rst:43 msgid "Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord `__, or start a new Discussion `directly on GitHub `__." msgstr "" #: ../../source/installation.rst:58 msgid "Once Manim is installed locally, you can proceed to our :doc:`quickstart guide ` which walks you through rendering a first simple scene." msgstr "" #: ../../source/installation.rst:62 msgid "As mentioned above, do not worry if there are errors or other problems: consult our :doc:`FAQ section ` for help (including instructions for how to ask Manim's community for help)." msgstr "" #: ../../source/installation.rst:71 msgid "Using Manim via Docker" msgstr "" #: ../../source/installation.rst:73 msgid "`Docker `__ is a virtualization tool that allows the distribution of encapsulated software environments (containers)." msgstr "" #: ../../source/installation.rst:76 msgid "The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:" msgstr "" #: ../../source/installation.rst:87 msgid "Interactive Jupyter notebooks for your browser" msgstr "" #: ../../source/installation.rst:89 msgid "Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks `__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook." msgstr "" #: ../../source/installation.rst:94 msgid "The following pages explain how you can setup interactive environments like that yourself:" msgstr "" #: ../../source/installation.rst:104 msgid "Editors" msgstr "" #: ../../source/installation.rst:106 msgid "If you're using Visual Studio Code you can install an extension called *Manim Sideview* which provides automated rendering and an integrated preview of the animation inside the editor. The extension can be installed through the `marketplace of VS Code `__." msgstr "" #: ../../source/installation.rst:113 msgid "Installation for developers" msgstr "" ================================================ FILE: docs/i18n/gettext/internals.pot ================================================ ================================================ FILE: docs/i18n/gettext/plugins.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/plugins.rst:5 msgid "Plugins" msgstr "" #: ../../source/plugins.rst:7 msgid "Plugins are features that extend Manim's core functionality. Since Manim is extensible and not everything belongs in its core, we'll go over how to install, use, and create your own plugins." msgstr "" #: ../../source/plugins.rst:13 msgid "The standard naming convention for plugins is to prefix the plugin with ``manim-``. This makes them easy for users to find on package repositories such as PyPI." msgstr "" #: ../../source/plugins.rst:19 msgid "The plugin feature is new and under active development. Expect updates for the best practices on installing, using, and creating plugins; as well as new subcommands/flags for ``manim plugins``" msgstr "" #: ../../source/plugins.rst:25 msgid "See https://plugins.manim.community/ for the list of plugins available." msgstr "" #: ../../source/plugins.rst:28 msgid "Installing Plugins" msgstr "" #: ../../source/plugins.rst:29 msgid "Plugins can be easily installed via the ``pip`` command:" msgstr "" #: ../../source/plugins.rst:36 msgid "After installing a plugin, you may use the ``manim plugins`` command to list your available plugins, see the following help output:" msgstr "" #: ../../source/plugins.rst:52 msgid "You can list plugins as such:" msgstr "" #: ../../source/plugins.rst:61 msgid "Using Plugins in Projects" msgstr "" #: ../../source/plugins.rst:62 msgid "For enabling a plugin ``manim.cfg`` or command line parameters should be used." msgstr "" #: ../../source/plugins.rst:66 msgid "The plugins should be module name of the plugin and not PyPi name." msgstr "" #: ../../source/plugins.rst:68 msgid "Enabling plugins through ``manim.cfg``" msgstr "" #: ../../source/plugins.rst:75 msgid "For specifying multiple plugins, comma-separated values must be used." msgstr "" #: ../../source/plugins.rst:83 msgid "Creating Plugins" msgstr "" #: ../../source/plugins.rst:84 msgid "Plugins are intended to extend Manim's core functionality. If you aren't sure whether a feature should be included in Manim's core, feel free to ask over on the `Discord server `_. Visit `manim-plugintemplate `_ on PyPI.org which serves as an in-depth tutorial for creating plugins." msgstr "" #: ../../source/plugins.rst:94 msgid "The only requirement of manim plugins is that they specify an entry point with the group, ``\"manim.plugins\"``. This allows Manim to discover plugins available in the user's environment. Everything regarding the plugin's directory structure, build system, and naming are completely up to your discretion as an author. The aforementioned template plugin is only a model using Poetry since this is the build system Manim uses. The plugin's `entry point `_ can be specified in poetry as:" msgstr "" #: ../../source/plugins.rst:108 msgid "Here ``name`` is the name of the module of the plugin." msgstr "" #: ../../source/plugins.rst:110 msgid "Here ``object_reference`` can point to either a function in a module or a module itself. For example," msgstr "" #: ../../source/plugins.rst:118 msgid "Here a module is used as ``object_reference``, and when this plugin is enabled, Manim will look for ``__all__`` keyword defined in ``manim_plugintemplate`` and everything as a global variable one by one." msgstr "" #: ../../source/plugins.rst:122 msgid "If ``object_reference`` is a function, Manim calls the function and expects the function to return a list of modules or functions that need to be defined globally." msgstr "" #: ../../source/plugins.rst:125 msgid "For example," msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.logger_utils.JSONFormatter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:2 msgid "JSONFormatter" msgstr "" #: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:4 msgid "Qualified name: ``manim.\\_config.logger\\_utils.JSONFormatter``" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:1 msgid "Bases: :py:class:`logging.Formatter`" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:1 msgid "A formatter that outputs logs in a custom JSON format." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:3 msgid "This class is used internally for testing purposes." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:6 msgid "Initialize the formatter with specified format strings." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:8 msgid "Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:13 msgid "Use a style parameter of '%', '{' or '$' to specify that you want to use one of %-formatting, :meth:`str.format` (``{}``) formatting or :class:`string.Template` formatting in your format string." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:17 msgid "Added the ``style`` parameter." msgstr "" #: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:20::1 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter.format:1 msgid "Format the record in a custom JSON format." msgstr "" #: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter.format:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.logger_utils.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.logger_utils.rst:2 msgid "logger\\_utils" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:1 msgid "Utilities to create and set the logger." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:3 msgid "Manim's logger can be accessed as ``manim.logger``, or as ``logging.getLogger(\"manim\")``, once the library has been imported. Manim also exports a second object, ``console``, which should be used to print on screen messages that need not be logged." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:8 msgid "Both ``logger`` and ``console`` use the ``rich`` library to produce rich text format." msgstr "" #: ../../source/reference/manim._config.logger_utils.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim._config.logger_utils.rst:26::1 msgid "A formatter that outputs logs in a custom JSON format." msgstr "" #: ../../source/reference/manim._config.logger_utils.rst:29 msgid "Functions" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:1 msgid "Make the manim logger and console." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:0 msgid "Parameters" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:3 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:3 msgid "A parser containing any .cfg files in use." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:5 msgid "The verbosity level of the logger." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0 msgid "Returns" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:8 msgid "The manim logger and consoles. The first console outputs to stdout, the second to stderr. All use the theme returned by :func:`parse_theme`." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0 #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:0 msgid "Return type" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:16 msgid "Notes" msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:17 msgid "The ``parser`` is assumed to contain only the options related to configuring the logger at the top level." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:1 msgid "Configure the rich style of logger and console output." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:6 msgid "The rich theme to be used by the manim logger." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:1 msgid "Add a file handler to manim logger." msgstr "" #: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:3 msgid "The path to the file is built using ``config.log_dir``." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.rst:2 msgid "\\_config" msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config:1 msgid "Set the global config and logger." msgstr "" #: ../../source/reference/manim._config.rst:20 msgid "Functions" msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:1 msgid "Context manager that temporarily modifies the global ``config`` object." msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:3 msgid "Inside the ``with`` statement, the modified config will be used. After context manager exits, the config will be restored to its original state." msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:0 msgid "Parameters" msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:6 msgid "Object whose keys will be used to temporarily update the global ``config``." msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:0 msgid "Return type" msgstr "" #: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:11 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.utils.ManimConfig.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.utils.ManimConfig.rst:2 msgid "ManimConfig" msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:4 msgid "Qualified name: ``manim.\\_config.utils.ManimConfig``" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:1 msgid "Bases: :py:class:`collections.abc.MutableMapping`" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:1 msgid "Dict-like class storing all config options." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:3 msgid "The global ``config`` object is an instance of this class, and acts as a single source of truth for all of the library's customizable behavior." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:6 msgid "The global ``config`` object is capable of digesting different types of sources and converting them into a uniform interface. These sources are (in ascending order of precedence): configuration files, command line arguments, and programmatic changes. Regardless of how the user chooses to set a config option, she can access its current value using :class:`ManimConfig`'s attributes and properties." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:14 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:9 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:15 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:16 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:18 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:19 msgid "Notes" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:15 msgid "Each config option is implemented as a property of this class." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:17 msgid "Each config option can be set via a config file, using the full name of the property. If a config option has an associated CLI flag, then the flag is equal to the full name of the property. Those that admit an alternative flag or no flag at all are documented in the individual property's docstring." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:24 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:25 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:25 msgid "Examples" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:25 msgid "We use a copy of the global configuration object in the following examples for the sake of demonstration; you can skip these lines and just import ``config`` directly if you actually want to modify the configuration:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:35 msgid "Each config option allows for dict syntax and attribute syntax. For example, the following two lines are equivalent," msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:44 msgid "The former is preferred; the latter is provided mostly for backwards compatibility." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:47 msgid "The config options are designed to keep internal consistency. For example, setting ``frame_y_radius`` will affect ``frame_height``:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:58 msgid "There are many ways of interacting with config options. Take for example the config option ``background_color``. There are three ways to change it: via a config file, via CLI flags, or programmatically." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:62 msgid "To set the background color via a config file, save the following ``manim.cfg`` file with the following contents." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:70 msgid "In order to have this ``.cfg`` file apply to a manim scene, it needs to be placed in the same directory as the script," msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:79 msgid "Now, when the user executes" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:85 msgid "the background of the scene will be set to ``WHITE``. This applies regardless of where the manim command is invoked from." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:88 msgid "Command line arguments override ``.cfg`` files. In the previous example, executing" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:95 msgid "will set the background color to BLUE, regardless of the contents of ``manim.cfg``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:98 msgid "Finally, any programmatic changes made within the scene script itself will override the command line arguments. For example, if ``scene.py`` contains the following" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:111 msgid "the background color will be set to RED, regardless of the contents of ``manim.cfg`` or the CLI arguments used when invoking manim." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:1 msgid "Deepcopy the contents of this ManimConfig." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:1 msgid "Process the config options present in CLI arguments." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:1 msgid "Process the config options present in a ``.cfg`` file." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:1 msgid "Process the config options present in a :class:`ConfigParser` object." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:1 msgid "Resolve a config option that stores a directory." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:26::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:1 msgid "Digest the options found in another :class:`ManimConfig` or in a dict." msgstr "" #: ../../source/reference/manim._config.utils.ManimConfig.rst:28 msgid "Attributes" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1 msgid "Aspect ratio (width / height) in pixels (--resolution, -r)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.assets_dir:1 msgid "Directory to locate video assets (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.background_color:1 msgid "Background color of the scene (-c)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.background_opacity:1 msgid "A number between 0.0 (fully transparent) and 1.0 (fully opaque)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.bottom:1 msgid "Coordinate at the center bottom of the frame." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.custom_folders:1 msgid "Whether to use custom folder output." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.disable_caching:1 msgid "Whether to use scene caching." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.disable_caching_warning:1 msgid "Whether a warning is raised if there are too much submobjects to hash." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.dry_run:1 msgid "Whether dry run is enabled." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.enable_gui:1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.gui_location:1 msgid "Enable GUI interaction." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.enable_wireframe:1 msgid "Enable wireframe debugging mode in opengl." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.ffmpeg_executable:1 msgid "Manually specify the path to the ffmpeg executable" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.ffmpeg_loglevel:1 msgid "Verbosity level of ffmpeg (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.flush_cache:1 msgid "Whether to delete all the cached partial movie files." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.force_window:1 msgid "Set to force window when using the opengl renderer" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.format:1 msgid "File format; \"png\", \"gif\", \"mp4\", \"webm\" or \"mov\"." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_height:1 msgid "Frame height in logical units (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_rate:1 msgid "Frame rate in frames per second." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_size:1 msgid "Tuple with (pixel width, pixel height) (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_width:1 msgid "Frame width in logical units (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_x_radius:1 msgid "Half the frame width (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_y_radius:1 msgid "Half the frame height (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.from_animation_number:1 msgid "Start rendering animations at this number (-n)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.fullscreen:1 msgid "Expand the window to its maximum possible size." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place images (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.input_file:1 msgid "Input file name." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.left_side:1 msgid "Coordinate at the middle left of the frame." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place logs." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.log_to_file:1 msgid "Whether to save logs to a file." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Maximum number of files cached." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Main output directory." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_embed:1 msgid "Embed videos in Jupyter notebook" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_width:1 msgid "Media width in Jupyter notebook" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.movie_file_extension:1 msgid "Either .mp4, .webm or .mov." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.notify_outdated_version:1 msgid "Whether to notify if there is a version update available." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.output_file:1 msgid "Output file name (-o)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place partial movie files (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.pixel_height:1 msgid "Frame height in pixels (--resolution, -r)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.pixel_width:1 msgid "Frame width in pixels (--resolution, -r)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.plugins:1 msgid "List of plugins to enable." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.preview:1 msgid "Whether to play the rendered movie (-p)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.progress_bar:1 msgid "Whether to show progress bars while rendering animations." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.quality:1 msgid "Video quality (-q)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:1 msgid "\"cairo\", \"opengl" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.right_side:1 msgid "Coordinate at the middle right of the frame." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_as_gif:1 msgid "Whether to save the rendered scene in .gif format (-i)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_last_frame:1 msgid "Whether to save the last frame of the scene as an image file (-s)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_pngs:1 msgid "Whether to save all frames in the scene as images files (-g)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_sections:1 msgid "Whether to save single videos for each section in addition to the movie file." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.scene_names:1 msgid "Scenes to play from file." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place section videos (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.show_in_file_browser:1 msgid "Whether to show the output file in the file browser (-f)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place tex (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Template used when rendering Tex." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "File to read Tex template from (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place text (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.top:1 msgid "Coordinate at the center top of the frame." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.transparent:1 msgid "Whether the background opacity is 0.0 (-t)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Stop rendering animations at this nmber." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_opengl_renderer:1 msgid "Whether or not to use the OpenGL renderer." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_projection_fill_shaders:1 msgid "Use shaders for OpenGLVMobject fill which are compatible with transformation matrices." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_projection_stroke_shaders:1 msgid "Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.verbosity:1 msgid "Logger verbosity; \"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", or \"CRITICAL\" (-v)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Directory to place videos (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_monitor:1 msgid "The monitor on which the scene will be rendered" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "Set the position of preview window." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "The size of the opengl window." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.write_all:1 msgid "Whether to render all scenes in the input file (-a)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.write_to_movie:1 msgid "Whether to render the scene to a movie file (-w)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1::1 msgid "PNG zero padding." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0 msgid "Return type" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0 msgid "Returns" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:3 msgid "A copy of this object containing no shared references." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:10 msgid "This is the main mechanism behind :func:`tempconfig`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0 msgid "Parameters" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:3 msgid "An object returned by :func:`.main_utils.parse_args()`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:6 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:12 msgid "**self** -- This object, after processing the contents of ``parser``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:16 msgid "If ``args.config_file`` is a non-empty string, ``ManimConfig`` tries to digest the contents of said file with :meth:`~ManimConfig.digest_file` before digesting any other CLI arguments." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:3 msgid "This method processes a single ``.cfg`` file, whereas :meth:`~ManimConfig.digest_parser` can process arbitrary parsers, built perhaps from multiple ``.cfg`` files." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:7 msgid "Path to the ``.cfg`` file." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:10 msgid "**self** -- This object, after processing the contents of ``filename``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:17 msgid "If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first and digesting them with one call to :meth:`~ManimConfig.digest_parser`, instead of calling this method multiple times." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:3 msgid "This method processes arbitrary parsers, not only those read from a single file, whereas :meth:`~ManimConfig.digest_file` can only process one file at a time." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:7 msgid "An object reflecting the contents of one or many ``.cfg`` files. In particular, it may reflect the contents of multiple files that have been parsed in a cascading fashion." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:19 msgid "If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first, and then call this function once (instead of calling :meth:`~.ManimConfig.digest_file` multiple times)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:26 msgid "To digest the config options set in two files, first create a ConfigParser and parse both files and then digest the parser:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:35 msgid "In fact, the global ``config`` object is initialized like so:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:3 msgid "Config options that store directories may depend on one another. This method is used to provide the actual directory to the end user." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:6 msgid "The config option to be resolved. Must be an option ending in ``'_dir'``, for example ``'media_dir'`` or ``'video_dir'``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:9 msgid "Any strings to be used when resolving the directory." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:12 msgid "Path to the requested directory. If the path resolves to the empty string, return ``None`` instead." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0 msgid "Raises" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:16 msgid "When ``key`` is not a config option that stores a directory and thus :meth:`~ManimConfig.get_dir` is not appropriate; or when ``key`` is appropriate but there is not enough information to resolve the directory." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:20 msgid "Standard :meth:`str.format` syntax is used to resolve the paths so the paths may contain arbitrary placeholders using f-string notation. However, these will require ``kwargs`` to contain the required values." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:26 msgid "The value of ``config.tex_dir`` is ``'{media_dir}/Tex'`` by default, i.e. it is a subfolder of wherever ``config.media_dir`` is located. In order to get the *actual* directory, use :meth:`~ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:41 msgid "Resolving directories is done in a lazy way, at the last possible moment, to reflect any changes in other config options:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:50 msgid "Some directories depend on information that is not available to :class:`ManimConfig`. For example, the default value of `video_dir` includes the name of the input file and the video quality (e.g. 480p15). This informamtion has to be supplied via ``kwargs``:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:65 msgid "Note the quality does not need to be passed as keyword argument since :class:`ManimConfig` does store information about quality." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:68 msgid "Directories may be recursively defined. For example, the config option ``partial_movie_dir`` depends on ``video_dir``, which in turn depends on ``media_dir``:" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:84 msgid "Standard f-string syntax is used. Arbitrary names can be used when defining directories, as long as the corresponding values are passed to :meth:`ManimConfig.get_dir` via ``kwargs``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.images_dir:1 msgid "Directory to place images (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.log_dir:1 msgid "Directory to place logs. See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.max_files_cached:1 msgid "Maximum number of files cached. Use -1 for infinity (no flag)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_dir:1 msgid "Main output directory. See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.partial_movie_dir:1 msgid "Directory to place partial movie files (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:0 msgid "type" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:3 msgid "Renderer" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.sections_dir:1 msgid "Directory to place section videos (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_dir:1 msgid "Directory to place tex (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_template:1 msgid "Template used when rendering Tex. See :class:`.TexTemplate`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_template_file:1 msgid "File to read Tex template from (no flag). See :class:`.TexTemplateFromFile`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.text_dir:1 msgid "Directory to place text (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:3 msgid "Similar to :meth:`dict.update`, replaces the values of this object with those of ``obj``." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:6 msgid "The object to copy values from." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:11 msgid "If ``obj`` is a dict but contains keys that do not belong to any config options." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.upto_animation_number:1 msgid "Stop rendering animations at this nmber. Use -1 to avoid skipping (-n)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.video_dir:1 msgid "Directory to place videos (no flag). See :meth:`ManimConfig.get_dir`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_position:1 msgid "Set the position of preview window. You can use directions, e.g. UL/DR/ORIGIN/LEFT...or the position(pixel) of the upper left corner of the window, e.g. '960,540'" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_size:1 msgid "The size of the opengl window. 'default' to automatically scale the window based on the display monitor." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.utils.ManimFrame.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.utils.ManimFrame.rst:2 msgid "ManimFrame" msgstr "" #: ../../source/reference/manim._config.utils.ManimFrame.rst:4 msgid "Qualified name: ``manim.\\_config.utils.ManimFrame``" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimFrame:1 msgid "Bases: :py:class:`collections.abc.Mapping`" msgstr "" #: ../../source/reference/manim._config.utils.ManimFrame.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim._config.utils.ManimFrame.rst:21 msgid "Attributes" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimFrame:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim._config.utils.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim._config.utils.rst:2 msgid "utils" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils:1 msgid "Utilities to create and set the config." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils:3 msgid "The main class exported by this module is :class:`ManimConfig`. This class contains all configuration options, including frame geometry (e.g. frame height/width, frame rate), output (e.g. directories, logging), styling (e.g. background color, transparency), and general behavior (e.g. writing a movie vs writing a single frame)." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils:9 msgid "See :doc:`/guides/configuration` for an introduction to Manim's configuration system." msgstr "" #: ../../source/reference/manim._config.utils.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim._config.utils.rst:28::1 msgid "Dict-like class storing all config options." msgstr "" #: ../../source/reference/manim._config.utils.rst:31 msgid "Functions" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:1 msgid "The paths where ``.cfg`` files will be searched for." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:3 msgid "When manim is first imported, it processes any ``.cfg`` files it finds. This function returns the locations in which these files are searched for. In ascending order of precedence, these are: the library-wide config file, the user-wide config file, and the folder-wide config file." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:8 msgid "The library-wide config file determines manim's default behavior. The user-wide config file is stored in the user's home folder, and determines the behavior of manim whenever the user invokes it from anywhere in the system. The folder-wide config file only affects scenes that are in the same folder. The latter two files are optional." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:14 msgid "These files, if they exist, are meant to loaded into a single :class:`configparser.ConfigParser` object, and then processed by :class:`ManimConfig`." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0 msgid "Returns" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:18 msgid "List of paths which may contain ``.cfg`` files, in ascending order of precedence." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:0 #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0 msgid "Return type" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:20 msgid "List[:class:`Path`]" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:25 msgid "Notes" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:26 msgid "The location of the user-wide config file is OS-specific." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:1 msgid "Make a :class:`ConfigParser` object and load any ``.cfg`` files." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:3 msgid "The user-wide file, if it exists, overrides the library-wide file. The folder-wide file, if it exists, overrides the other two." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:6 msgid "The folder-wide file can be ignored by passing ``custom_file``. However, the user-wide and library-wide config files cannot be ignored." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0 msgid "Parameters" msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:9 msgid "Path to a custom config file. If used, the folder-wide file in the relevant directory will be ignored, if it exists. If None, the folder-wide file will be used, if it exists." msgstr "" #: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:14 msgid "A parser containing the config options found in the .cfg files that were found. It is guaranteed to contain at least the config options found in the library-wide file." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.animation.Animation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.animation.Animation.rst:2 msgid "Animation" msgstr "" #: ../../source/reference/manim.animation.animation.Animation.rst:4 msgid "Qualified name: ``manim.animation.animation.Animation``" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:1 msgid "An animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:3 msgid "Animations have a fixed time span." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.update_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:5 msgid "The mobject to be animated. This is not required for all types of animations." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:6 msgid "Defines the delay after which the animation is applied to submobjects. This lag is relative to the duration of the animation. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:6 msgid "Defines the delay after which the animation is applied to submobjects. This lag is relative to the duration of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:9 msgid "This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:12 msgid "The duration of the animation in seconds." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:13 msgid "The function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`) . For example ``rate_func(0.5)`` is the proportion of the animation that is done after half of the animations run time." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:13 msgid "The function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`) ." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:15 msgid "For example ``rate_func(0.5)`` is the proportion of the animation that is done after half of the animations run time." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:21 msgid "reverse_rate_function" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:19 msgid "Reverses the rate function of the animation. Setting ``reverse_rate_function`` does not have any effect on ``remover`` or ``introducer``. These need to be set explicitly if an introducer-animation should be turned into a remover one and vice versa." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:24 msgid "name" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:24 msgid "The name of the animation. This gets displayed while rendering the animation. Defaults to ()." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:26 msgid "remover" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:27 msgid "Whether the given mobject should be removed from the scene after this animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:30 msgid "suspend_mobject_updating" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:29 msgid "Whether updaters of the mobject should be suspended during the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:34 msgid "In the current implementation of this class, the specified rate function is applied within :meth:`.Animation.interpolate_mobject` call as part of the call to :meth:`.Animation.interpolate_submobject`. For subclasses of :class:`.Animation` that are implemented by overriding :meth:`interpolate_mobject`, the rate function has to be applied manually (e.g., by passing ``self.rate_func(alpha)`` instead of just ``alpha``)." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:43 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.animation.Animation.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:1 msgid "Create a copy of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:1 msgid "Finish the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:1 msgid "Get all mobjects involved in the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:1 msgid "Get all mobjects to be updated during the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:1 msgid "Get the rate function of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:1 msgid "Get the run time of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:1 msgid "Get the animation progress of any submobjects subanimation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:1 msgid "Test if the animation is an introducer." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:1 msgid "Test if the animation is a remover." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:1 msgid "Set the name of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:1 msgid "Set the rate function of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:1 msgid "Set the run time of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1::1 msgid "Updates things like starting_mobject, and (for Transforms) target_mobject." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0 msgid "Returns" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:3 msgid "A copy of ``self``" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:3 msgid "This method gets called when the animation is over." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:3 msgid "Ordering must match the ordering of arguments to interpolate_submobject" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:5 msgid "The sequence of mobjects." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:3 msgid "The list of mobjects to be updated during the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:3 msgid "The rate function of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:3 msgid "The time the animation takes in seconds." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:3 msgid "The overall animation progress" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:4 msgid "The index of the subanimation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:5 msgid "The total count of subanimations." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:7 msgid "The progress of the subanimation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:3 msgid "``True`` if the animation is an introducer, ``False`` otherwise." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:3 msgid "``True`` if the animation is a remover, ``False`` otherwise." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:3 msgid "The new name of the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:5 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:5 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:7 msgid "``self``" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:3 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:3 msgid "The new time the animation should take in seconds." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:4 msgid "The run_time of an animation should not be changed while it is already running." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.animation.Wait.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.animation.Wait.rst:2 msgid "Wait" msgstr "" #: ../../source/reference/manim.animation.animation.Wait.rst:4 msgid "Qualified name: ``manim.animation.animation.Wait``" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:1 msgid "A \"no operation\" animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.update_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:3 msgid "The amount of time that should pass." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:4 msgid "A function without positional arguments that evaluates to a boolean. The function is evaluated after every new frame has been rendered. Playing the animation only stops after the return value is truthy. Overrides the specified ``run_time``." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:8 msgid "Controls whether or not the wait animation is static, i.e., corresponds to a frozen frame. If ``False`` is passed, the render loop still progresses through the animation as usual and (among other things) continues to call updater functions. If ``None`` (the default value), the :meth:`.Scene.play` call tries to determine whether the Wait call can be static or not itself via :meth:`.Scene.should_mobjects_update`." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:14 msgid "Keyword arguments to be passed to the parent class, :class:`.Animation`." msgstr "" #: ../../source/reference/manim.animation.animation.Wait.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:1 msgid "Finish the animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1::1 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1::1 msgid "Updates things like starting_mobject, and (for Transforms) target_mobject." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:3 msgid "This method gets called when the animation is over." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.animation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.animation.rst:2 msgid "animation" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation:1 msgid "Animate mobjects." msgstr "" #: ../../source/reference/manim.animation.animation.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.animation.rst:28::1 msgid "An animation." msgstr "" #: ../../source/reference/manim.animation.animation.rst:28::1 msgid "A \"no operation\" animation." msgstr "" #: ../../source/reference/manim.animation.animation.rst:31 msgid "Functions" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:1 msgid "Decorator used to mark methods as overrides for specific :class:`~.Animation` types." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:3 msgid "Should only be used to decorate methods of classes derived from :class:`~.Mobject`. ``Animation`` overrides get inherited to subclasses of the ``Mobject`` who defined them. They don't override subclasses of the ``Animation`` they override." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:9 msgid "The animation to be overridden." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0 msgid "Returns" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:11 msgid "The actual decorator. This marks the method as overriding an animation." msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:0 msgid "Return type" msgstr "" #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:15 #: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:5 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.changing.AnimatedBoundary.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:2 msgid "AnimatedBoundary" msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:4 msgid "Qualified name: ``manim.animation.changing.AnimatedBoundary``" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:1 msgid "Boundary of a :class:`.VMobject` with animated color change." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:23 msgid "Attributes" msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.changing.TracedPath.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.changing.TracedPath.rst:2 msgid "TracedPath" msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:4 msgid "Qualified name: ``manim.animation.changing.TracedPath``" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:1 msgid "Traces the path of a point returned by a function call." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:3 msgid "The function to be traced." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:4 msgid "The width of the trace." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:5 msgid "The color of the trace." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:6 msgid "The time taken for the path to dissipate. Default set to ``None`` which disables dissipation." msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:10 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.animation.changing.TracedPath.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.changing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.changing.rst:2 msgid "changing" msgstr "" #: ../../../manim/animation/changing.py:docstring of manim.animation.changing:1 msgid "Animation of a mobject boundary and tracing of points." msgstr "" #: ../../source/reference/manim.animation.changing.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.changing.rst:22::1 msgid "Boundary of a :class:`.VMobject` with animated color change." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.composition.AnimationGroup.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.composition.AnimationGroup.rst:2 msgid "AnimationGroup" msgstr "" #: ../../source/reference/manim.animation.composition.AnimationGroup.rst:4 msgid "Qualified name: ``manim.animation.composition.AnimationGroup``" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../source/reference/manim.animation.composition.AnimationGroup.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.build_animations_with_timings:1 msgid "Creates a list of triplets of the form (anim, start_time, end_time)" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:1 msgid "Finish the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:1 msgid "Get all mobjects involved in the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1::1 msgid "Updates things like starting_mobject, and (for Transforms) target_mobject." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.build_animations_with_timings:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.update_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:3 msgid "This method gets called when the animation is over." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:3 msgid "Ordering must match the ordering of arguments to interpolate_submobject" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:0 msgid "Returns" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:5 msgid "The sequence of mobjects." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.composition.LaggedStart.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.composition.LaggedStart.rst:2 msgid "LaggedStart" msgstr "" #: ../../source/reference/manim.animation.composition.LaggedStart.rst:4 msgid "Qualified name: ``manim.animation.composition.LaggedStart``" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.LaggedStart:1 msgid "Bases: :py:class:`manim.animation.composition.AnimationGroup`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.composition.LaggedStartMap.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.composition.LaggedStartMap.rst:2 msgid "LaggedStartMap" msgstr "" #: ../../source/reference/manim.animation.composition.LaggedStartMap.rst:4 msgid "Qualified name: ``manim.animation.composition.LaggedStartMap``" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.LaggedStartMap:1 msgid "Bases: :py:class:`manim.animation.composition.LaggedStart`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.composition.Succession.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.composition.Succession.rst:2 msgid "Succession" msgstr "" #: ../../source/reference/manim.animation.composition.Succession.rst:4 msgid "Qualified name: ``manim.animation.composition.Succession``" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession:1 msgid "Bases: :py:class:`manim.animation.composition.AnimationGroup`" msgstr "" #: ../../source/reference/manim.animation.composition.Succession.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:1 msgid "Finish the animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1::1 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1::1 msgid "Updates things like starting_mobject, and (for Transforms) target_mobject." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:3 msgid "This method gets called when the animation is over." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:0 #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.update_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.composition.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.composition.rst:2 msgid "composition" msgstr "" #: ../../../manim/animation/composition.py:docstring of manim.animation.composition:1 msgid "Tools for displaying multiple animations at once." msgstr "" #: ../../source/reference/manim.animation.composition.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.AddTextLetterByLetter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.AddTextLetterByLetter.rst:2 msgid "AddTextLetterByLetter" msgstr "" #: ../../source/reference/manim.animation.creation.AddTextLetterByLetter.rst:4 msgid "Qualified name: ``manim.animation.creation.AddTextLetterByLetter``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:1 msgid "Bases: :py:class:`manim.animation.creation.ShowIncreasingSubsets`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:1 msgid "Show a :class:`~.Text` letter by letter on the scene." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:3 msgid "Frequency of appearance of the letters." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:5 msgid "This is currently only possible for class:`~.Text` and not for class:`~.MathTex`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.AddTextWordByWord.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.AddTextWordByWord.rst:2 msgid "AddTextWordByWord" msgstr "" #: ../../source/reference/manim.animation.creation.AddTextWordByWord.rst:4 msgid "Qualified name: ``manim.animation.creation.AddTextWordByWord``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextWordByWord:1 msgid "Bases: :py:class:`manim.animation.composition.Succession`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextWordByWord:1 msgid "Show a :class:`~.Text` word by word on the scene. Note: currently broken." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.Create.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.Create.rst:2 msgid "Create" msgstr "" #: ../../source/reference/manim.animation.creation.Create.rst:4 msgid "Qualified name: ``manim.animation.creation.Create``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:1 msgid "Bases: :py:class:`manim.animation.creation.ShowPartial`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:1 msgid "Incrementally show a VMobject." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:3 msgid "The VMobject to animate." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:0 msgid "Raises" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:6 msgid "If ``mobject`` is not an instance of :class:`~.VMobject`." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:9 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.DrawBorderThenFill.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:2 msgid "DrawBorderThenFill" msgstr "" #: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:4 msgid "Qualified name: ``manim.animation.creation.DrawBorderThenFill``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:1 msgid "Draw the border first and then show the fill." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:1 msgid "Get all mobjects involved in the animation." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:0 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:3 msgid "Ordering must match the ordering of arguments to interpolate_submobject" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:0 msgid "Returns" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.ShowIncreasingSubsets.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:2 msgid "ShowIncreasingSubsets" msgstr "" #: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:4 msgid "Qualified name: ``manim.animation.creation.ShowIncreasingSubsets``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:1 msgid "Show one submobject at a time, leaving all previous ones displayed on screen." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.ShowPartial.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.ShowPartial.rst:2 msgid "ShowPartial" msgstr "" #: ../../source/reference/manim.animation.creation.ShowPartial.rst:4 msgid "Qualified name: ``manim.animation.creation.ShowPartial``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:1 msgid "Abstract class for Animations that show the VMobject partially." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:0 msgid "Raises" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:3 msgid "If ``mobject`` is not an instance of :class:`~.VMobject`." msgstr "" #: ../../source/reference/manim.animation.creation.ShowPartial.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.ShowSubmobjectsOneByOne.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:2 msgid "ShowSubmobjectsOneByOne" msgstr "" #: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:4 msgid "Qualified name: ``manim.animation.creation.ShowSubmobjectsOneByOne``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowSubmobjectsOneByOne:1 msgid "Bases: :py:class:`manim.animation.creation.ShowIncreasingSubsets`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowSubmobjectsOneByOne:1 msgid "Show one submobject at a time, removing all previously displayed ones from screen." msgstr "" #: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.SpiralIn.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.SpiralIn.rst:2 msgid "SpiralIn" msgstr "" #: ../../source/reference/manim.animation.creation.SpiralIn.rst:4 msgid "Qualified name: ``manim.animation.creation.SpiralIn``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:1 msgid "Create the Mobject with sub-Mobjects flying in on spiral trajectories." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:0 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:3 msgid "The Mobject on which to be operated." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:4 msgid "The factor used for scaling the effect." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:5 msgid "Fractional duration of initial fade-in of sub-Mobjects as they fly inward." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.creation.SpiralIn.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.Uncreate.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.Uncreate.rst:2 msgid "Uncreate" msgstr "" #: ../../source/reference/manim.animation.creation.Uncreate.rst:4 msgid "Qualified name: ``manim.animation.creation.Uncreate``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:1 msgid "Bases: :py:class:`manim.animation.creation.Create`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:1 msgid "Like :class:`Create` but in reverse." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:4 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.Unwrite.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.Unwrite.rst:2 msgid "Unwrite" msgstr "" #: ../../source/reference/manim.animation.creation.Unwrite.rst:4 msgid "Qualified name: ``manim.animation.creation.Unwrite``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:1 msgid "Bases: :py:class:`manim.animation.creation.Write`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:1 msgid "Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:3 msgid "Set True to have the animation start erasing from the last submobject first." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:7 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.Write.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.Write.rst:2 msgid "Write" msgstr "" #: ../../source/reference/manim.animation.creation.Write.rst:4 msgid "Qualified name: ``manim.animation.creation.Write``" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:1 msgid "Bases: :py:class:`manim.animation.creation.DrawBorderThenFill`" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:1 msgid "Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.creation.Write.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1 msgid "Begin the animation." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1::1 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.finish:1 msgid "Finish the animation." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:0 #: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.finish:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.creation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.creation.rst:2 msgid "creation" msgstr "" #: ../../../manim/animation/creation.py:docstring of manim.animation.creation:1 msgid "Animate the display or removal of a mobject from a scene." msgstr "" #: ../../source/reference/manim.animation.creation.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Show a :class:`~.Text` letter by letter on the scene." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Show a :class:`~.Text` word by word on the scene." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Incrementally show a VMobject." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Draw the border first and then show the fill." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Show one submobject at a time, leaving all previous ones displayed on screen." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Abstract class for Animations that show the VMobject partially." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Show one submobject at a time, removing all previously displayed ones from screen." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Create the Mobject with sub-Mobjects flying in on spiral trajectories." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Like :class:`Create` but in reverse." msgstr "" #: ../../source/reference/manim.animation.creation.rst:40::1 msgid "Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.fading.FadeIn.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.fading.FadeIn.rst:2 msgid "FadeIn" msgstr "" #: ../../source/reference/manim.animation.fading.FadeIn.rst:4 msgid "Qualified name: ``manim.animation.fading.FadeIn``" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:1 msgid "Bases: :py:class:`manim.animation.fading._Fade`" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:1 msgid "Fade in :class:`~.Mobject` s." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:3 msgid "The mobjects to be faded in." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:4 msgid "The vector by which the mobject shifts while being faded in." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:5 msgid "The position from which the mobject starts while being faded in. In case another mobject is given as target position, its center is used." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:7 msgid "The factor by which the mobject is scaled initially before being rescaling to its original size while being faded in." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.fading.FadeIn.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.fading.FadeIn.rst:23 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.fading.FadeOut.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.fading.FadeOut.rst:2 msgid "FadeOut" msgstr "" #: ../../source/reference/manim.animation.fading.FadeOut.rst:4 msgid "Qualified name: ``manim.animation.fading.FadeOut``" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:1 msgid "Bases: :py:class:`manim.animation.fading._Fade`" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:1 msgid "Fade out :class:`~.Mobject` s." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:0 #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:3 msgid "The mobjects to be faded out." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:4 msgid "The vector by which the mobject shifts while being faded out." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:5 msgid "The position to which the mobject moves while being faded out. In case another mobject is given as target position, its center is used." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:7 msgid "The factor by which the mobject is scaled while being faded out." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:10 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.fading.FadeOut.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.fading.FadeOut.rst:21::1 #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../source/reference/manim.animation.fading.FadeOut.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.fading.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.fading.rst:2 msgid "fading" msgstr "" #: ../../../manim/animation/fading.py:docstring of manim.animation.fading:1 msgid "Fading in and out of view." msgstr "" #: ../../source/reference/manim.animation.fading.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.fading.rst:22::1 msgid "Fade in :class:`~.Mobject` s." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.GrowArrow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.GrowArrow.rst:2 msgid "GrowArrow" msgstr "" #: ../../source/reference/manim.animation.growing.GrowArrow.rst:4 msgid "Qualified name: ``manim.animation.growing.GrowArrow``" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:1 msgid "Bases: :py:class:`manim.animation.growing.GrowFromPoint`" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:1 msgid "Introduce an :class:`~.Arrow` by growing it from its start toward its tip." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:3 msgid "The arrow to be introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:4 msgid "Initial color of the arrow before growing to its full size. Leave empty to match arrow's color." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.growing.GrowArrow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.growing.GrowArrow.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.GrowFromCenter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:2 msgid "GrowFromCenter" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:4 msgid "Qualified name: ``manim.animation.growing.GrowFromCenter``" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:1 msgid "Bases: :py:class:`manim.animation.growing.GrowFromPoint`" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:1 msgid "Introduce an :class:`~.Mobject` by growing it from its center." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:3 msgid "The mobjects to be introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:4 msgid "Initial color of the mobject before growing to its full size. Leave empty to match mobject's color." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.GrowFromEdge.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:2 msgid "GrowFromEdge" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:4 msgid "Qualified name: ``manim.animation.growing.GrowFromEdge``" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:1 msgid "Bases: :py:class:`manim.animation.growing.GrowFromPoint`" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:1 msgid "Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:3 msgid "The mobjects to be introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:4 msgid "The direction to seek bounding box edge of mobject." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:5 msgid "Initial color of the mobject before growing to its full size. Leave empty to match mobject's color." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.GrowFromPoint.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:2 msgid "GrowFromPoint" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:4 msgid "Qualified name: ``manim.animation.growing.GrowFromPoint``" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:1 msgid "Introduce an :class:`~.Mobject` by growing it from a point." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:3 msgid "The mobjects to be introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:4 msgid "The point from which the mobject grows." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:5 msgid "Initial color of the mobject before growing to its full size. Leave empty to match mobject's color." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:23 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.SpinInFromNothing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:2 msgid "SpinInFromNothing" msgstr "" #: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:4 msgid "Qualified name: ``manim.animation.growing.SpinInFromNothing``" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:1 msgid "Bases: :py:class:`manim.animation.growing.GrowFromCenter`" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:1 msgid "Introduce an :class:`~.Mobject` spinning and growing it from its center." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:3 msgid "The mobjects to be introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:4 msgid "The amount of spinning before mobject reaches its full size. E.g. 2*PI means that the object will do one full spin before being fully introduced." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:6 msgid "Initial color of the mobject before growing to its full size. Leave empty to match mobject's color." msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.growing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.growing.rst:2 msgid "growing" msgstr "" #: ../../../manim/animation/growing.py:docstring of manim.animation.growing:1 msgid "Animations that introduce mobjects to scene by growing them from points." msgstr "" #: ../../source/reference/manim.animation.growing.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.growing.rst:28::1 msgid "Introduce an :class:`~.Arrow` by growing it from its start toward its tip." msgstr "" #: ../../source/reference/manim.animation.growing.rst:28::1 msgid "Introduce an :class:`~.Mobject` by growing it from its center." msgstr "" #: ../../source/reference/manim.animation.growing.rst:28::1 msgid "Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges." msgstr "" #: ../../source/reference/manim.animation.growing.rst:28::1 msgid "Introduce an :class:`~.Mobject` by growing it from a point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.ApplyWave.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.ApplyWave.rst:2 msgid "ApplyWave" msgstr "" #: ../../source/reference/manim.animation.indication.ApplyWave.rst:4 msgid "Qualified name: ``manim.animation.indication.ApplyWave``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:1 msgid "Bases: :py:class:`manim.animation.movement.Homotopy`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:1 msgid "Send a wave through the Mobject distorting it temporarily." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:3 msgid "The mobject to be distorted." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:4 msgid "The direction in which the wave nudges points of the shape" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:5 msgid "The distance points of the shape get shifted" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:6 msgid "The function defining the shape of one wave flank." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:7 msgid "The length of the wave relative to the width of the mobject." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:8 msgid "The number of ripples of the wave" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:9 msgid "The duration of the animation." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:12 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.Circumscribe.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.Circumscribe.rst:2 msgid "Circumscribe" msgstr "" #: ../../source/reference/manim.animation.indication.Circumscribe.rst:4 msgid "Qualified name: ``manim.animation.indication.Circumscribe``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:1 msgid "Bases: :py:class:`manim.animation.composition.Succession`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:1 msgid "Draw a temporary line surrounding the mobject." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:3 msgid "The mobject to be circumscribed." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:4 msgid "The shape with which to surrond the given mobject. Should be either :class:`~.Rectangle` or :class:`~.Circle`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:6 msgid "Whether to make the surrounding shape to fade in. It will be drawn otherwise." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:7 msgid "Whether to make the surrounding shape to fade out. It will be undrawn otherwise." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:8 msgid "The time_width of the drawing and undrawing. Gets ignored if either `fade_in` or `fade_out` is `True`." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:9 msgid "The distance between the surrounding shape and the given mobject." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:10 msgid "The color of the surrounding shape." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:11 msgid "The duration of the entire animation." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:12 msgid "Additional arguments to be passed to the :class:`~.Succession` constructor" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:16 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.Flash.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.Flash.rst:2 msgid "Flash" msgstr "" #: ../../source/reference/manim.animation.indication.Flash.rst:4 msgid "Qualified name: ``manim.animation.indication.Flash``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:1 msgid "Bases: :py:class:`manim.animation.composition.AnimationGroup`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:1 msgid "Send out lines in all directions." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:3 msgid "The center of the flash lines. If it is a :class:`.~Mobject` its center will be used." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:4 msgid "The length of the flash lines." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:5 msgid "The number of flash lines." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:6 msgid "The distance from `point` at which the flash lines start." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:7 msgid "The stroke width of the flash lines." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:8 msgid "The color of the flash lines." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:9 msgid "The time width used for the flash lines. See :class:`.~ShowPassingFlash` for more details." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:10 msgid "The duration of the animation." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:11 msgid "Additional arguments to be passed to the :class:`~.Succession` constructor" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:15 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.Flash.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.FocusOn.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.FocusOn.rst:2 msgid "FocusOn" msgstr "" #: ../../source/reference/manim.animation.indication.FocusOn.rst:4 msgid "Qualified name: ``manim.animation.indication.FocusOn``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:1 msgid "Shrink a spotlight to a position." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:3 msgid "The point at which to shrink the spotlight. If it is a :class:`.~Mobject` its center will be used." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:4 msgid "The opacity of the spotlight." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:5 msgid "The color of the spotlight." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:6 msgid "The duration of the animation." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:7 msgid "Additional arguments to be passed to the :class:`~.Succession` constructor" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.FocusOn.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.indication.FocusOn.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.Indicate.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.Indicate.rst:2 msgid "Indicate" msgstr "" #: ../../source/reference/manim.animation.indication.Indicate.rst:4 msgid "Qualified name: ``manim.animation.indication.Indicate``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:1 msgid "Indicate a Mobject by temporarily resizing and recoloring it." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:3 msgid "The mobject to indicate." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:4 msgid "The factor by which the mobject will be temporally scaled" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:5 msgid "The color the mobject temporally takes." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:6 msgid "The function definig the animation progress at every point in time." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:7 msgid "Additional arguments to be passed to the :class:`~.Succession` constructor" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.Indicate.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.indication.Indicate.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.ShowCreationThenFadeOut.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.ShowCreationThenFadeOut.rst:2 msgid "ShowCreationThenFadeOut" msgstr "" #: ../../source/reference/manim.animation.indication.ShowCreationThenFadeOut.rst:4 msgid "Qualified name: ``manim.animation.indication.ShowCreationThenFadeOut``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowCreationThenFadeOut:1 msgid "Bases: :py:class:`manim.animation.composition.Succession`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowCreationThenFadeOut:1 msgid "Deprecated The class ShowCreationThenFadeOut has been deprecated since v0.15.0 and is expected to be removed after v0.16.0. Use Create then FadeOut to achieve this effect." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.ShowPassingFlash.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:2 msgid "ShowPassingFlash" msgstr "" #: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:4 msgid "Qualified name: ``manim.animation.indication.ShowPassingFlash``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:1 msgid "Bases: :py:class:`manim.animation.creation.ShowPartial`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:1 msgid "Show only a sliver of the VMobject each frame." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:0 #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:3 msgid "The mobject whose stroke is animated." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:4 msgid "The length of the sliver relative to the length of the stroke." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:1::1 #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.rst:2 msgid "ShowPassingFlashWithThinningStrokeWidth" msgstr "" #: ../../source/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.rst:4 msgid "Qualified name: ``manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth:1 msgid "Bases: :py:class:`manim.animation.composition.AnimationGroup`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.Wiggle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.Wiggle.rst:2 msgid "Wiggle" msgstr "" #: ../../source/reference/manim.animation.indication.Wiggle.rst:4 msgid "Qualified name: ``manim.animation.indication.Wiggle``" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:1 msgid "Wiggle a Mobject." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:3 msgid "The mobject to wiggle." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:5 msgid "The factor by which the mobject will be temporarily scaled." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:6 msgid "The wiggle angle." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:7 msgid "The number of wiggles." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:8 msgid "The point about which the mobject gets scaled." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:9 msgid "The point around which the mobject gets rotated." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:10 msgid "The duration of the animation" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.Wiggle.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.indication.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.indication.rst:2 msgid "indication" msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication:1 msgid "Animations drawing attention to particular mobjects." msgstr "" #: ../../../manim/animation/indication.py:docstring of manim.animation.indication:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.indication.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Send a wave through the Mobject distorting it temporarily." msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Draw a temporary line surrounding the mobject." msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Send out lines in all directions." msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Shrink a spotlight to a position." msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Indicate a Mobject by temporarily resizing and recoloring it." msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Deprecated" msgstr "" #: ../../source/reference/manim.animation.indication.rst:36::1 msgid "Show only a sliver of the VMobject each frame." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.ComplexHomotopy.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.ComplexHomotopy.rst:2 msgid "ComplexHomotopy" msgstr "" #: ../../source/reference/manim.animation.movement.ComplexHomotopy.rst:4 msgid "Qualified name: ``manim.animation.movement.ComplexHomotopy``" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.ComplexHomotopy:1 msgid "Bases: :py:class:`manim.animation.movement.Homotopy`" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.ComplexHomotopy:1 msgid "Complex Homotopy a function Cx[0, 1] to C" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.Homotopy.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.Homotopy.rst:2 msgid "Homotopy" msgstr "" #: ../../source/reference/manim.animation.movement.Homotopy.rst:4 msgid "Qualified name: ``manim.animation.movement.Homotopy``" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:1 msgid "A Homotopy." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:3 msgid "This is an animation transforming the points of a mobject according to the specified transformation function. With the parameter :math:`t` moving from 0 to 1 throughout the animation and :math:`(x, y, z)` describing the coordinates of the point of a mobject, the function passed to the ``homotopy`` keyword argument should transform the tuple :math:`(x, y, z, t)` to :math:`(x', y', z')`, the coordinates the original point is transformed to at time :math:`t`." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:11 msgid "A function mapping :math:`(x, y, z, t)` to :math:`(x', y', z')`." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:12 msgid "The mobject transformed under the given homotopy." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:13 msgid "The run time of the animation." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:14 msgid "Keyword arguments propagated to :meth:`.Mobject.apply_function`." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:15 msgid "Further keyword arguments passed to the parent class." msgstr "" #: ../../source/reference/manim.animation.movement.Homotopy.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.MoveAlongPath.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:2 msgid "MoveAlongPath" msgstr "" #: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:4 msgid "Qualified name: ``manim.animation.movement.MoveAlongPath``" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath:1 msgid "Make one mobject move along the path of another mobject. .. rubric:: Example" msgstr "" #: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:1::1 #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.PhaseFlow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.PhaseFlow.rst:2 msgid "PhaseFlow" msgstr "" #: ../../source/reference/manim.animation.movement.PhaseFlow.rst:4 msgid "Qualified name: ``manim.animation.movement.PhaseFlow``" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../source/reference/manim.animation.movement.PhaseFlow.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:1::1 #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.SmoothedVectorizedHomotopy.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:2 msgid "SmoothedVectorizedHomotopy" msgstr "" #: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:4 msgid "Qualified name: ``manim.animation.movement.SmoothedVectorizedHomotopy``" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement.SmoothedVectorizedHomotopy:1 msgid "Bases: :py:class:`manim.animation.movement.Homotopy`" msgstr "" #: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.movement.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.movement.rst:2 msgid "movement" msgstr "" #: ../../../manim/animation/movement.py:docstring of manim.animation.movement:1 msgid "Animations related to movement." msgstr "" #: ../../source/reference/manim.animation.movement.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.movement.rst:28::1 msgid "Complex Homotopy a function Cx[0, 1] to C" msgstr "" #: ../../source/reference/manim.animation.movement.rst:28::1 msgid "A Homotopy." msgstr "" #: ../../source/reference/manim.animation.movement.rst:28::1 msgid "Make one mobject move along the path of another mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.numbers.ChangeDecimalToValue.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.numbers.ChangeDecimalToValue.rst:2 msgid "ChangeDecimalToValue" msgstr "" #: ../../source/reference/manim.animation.numbers.ChangeDecimalToValue.rst:4 msgid "Qualified name: ``manim.animation.numbers.ChangeDecimalToValue``" msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangeDecimalToValue:1 msgid "Bases: :py:class:`manim.animation.numbers.ChangingDecimal`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.numbers.ChangingDecimal.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:2 msgid "ChangingDecimal" msgstr "" #: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:4 msgid "Qualified name: ``manim.animation.numbers.ChangingDecimal``" msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:1::1 #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.numbers.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.numbers.rst:2 msgid "numbers" msgstr "" #: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers:1 msgid "Animations for changing numbers." msgstr "" #: ../../source/reference/manim.animation.numbers.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.rotation.Rotate.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.rotation.Rotate.rst:2 msgid "Rotate" msgstr "" #: ../../source/reference/manim.animation.rotation.Rotate.rst:4 msgid "Qualified name: ``manim.animation.rotation.Rotate``" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:1 msgid "Animation that rotates a Mobject." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:3 msgid "The mobject to be rotated." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:4 msgid "The rotation angle." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:5 msgid "The rotation axis as a numpy vector." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:6 msgid "The rotation center." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:7 msgid "If ``about_point``is ``None``, this argument specifies the direction of the bounding box point to be taken as the rotation center." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:12 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.rotation.Rotate.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.rotation.Rotate.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.rotation.Rotating.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.rotation.Rotating.rst:2 msgid "Rotating" msgstr "" #: ../../source/reference/manim.animation.rotation.Rotating.rst:4 msgid "Qualified name: ``manim.animation.rotation.Rotating``" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../source/reference/manim.animation.rotation.Rotating.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:1::1 #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.rotation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.rotation.rst:2 msgid "rotation" msgstr "" #: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation:1 msgid "Animations related to rotation." msgstr "" #: ../../source/reference/manim.animation.rotation.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.rotation.rst:22::1 msgid "Animation that rotates a Mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.specialized.Broadcast.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.specialized.Broadcast.rst:2 msgid "Broadcast" msgstr "" #: ../../source/reference/manim.animation.specialized.Broadcast.rst:4 msgid "Qualified name: ``manim.animation.specialized.Broadcast``" msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:1 msgid "Bases: :py:class:`manim.animation.composition.LaggedStart`" msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:1 msgid "Broadcast a mobject starting from an ``initial_width``, up to the actual size of the mobject." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:3 msgid "The mobject to be broadcast." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:4 msgid "The center of the broadcast, by default ORIGIN." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:5 msgid "The number of mobjects that emerge from the focal point, by default 5." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:6 msgid "The starting stroke opacity of the mobjects emitted from the broadcast, by default 1." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:7 msgid "The final stroke opacity of the mobjects emitted from the broadcast, by default 0." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:8 msgid "The initial width of the mobjects, by default 0.0." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:9 msgid "Whether the mobjects should be removed from the scene after the animation, by default True." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:10 msgid "The time between each iteration of the mobject, by default 0.2." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:11 msgid "The total duration of the animation, by default 3." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:12 msgid "Additional arguments to be passed to :class:`~.LaggedStart`." msgstr "" #: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:15 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.specialized.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.specialized.rst:2 msgid "specialized" msgstr "" #: ../../source/reference/manim.animation.specialized.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.speedmodifier.ChangeSpeed.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:2 msgid "ChangeSpeed" msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:4 msgid "Qualified name: ``manim.animation.speedmodifier.ChangeSpeed``" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:1 msgid "Modifies the speed of passed animation. :class:`AnimationGroup` with different ``lag_ratio`` can also be used which combines multiple animations into one. The ``run_time`` of the passed animation is changed to modify the speed." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.update_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:6 msgid "Animation of which the speed is to be modified." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:7 msgid "Contains nodes (percentage of ``run_time``) and its corresponding speed factor." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:8 msgid "Overrides ``rate_func`` of passed animation, applied before changing speed." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:1 msgid "This static method can be used to apply speed change to updaters." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:1 msgid "Begin the animation." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:1 msgid "Finish the animation." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.get_scaled_total_time:1 msgid "The time taken by the animation under the assumption that the ``run_time`` is 1." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27::1 msgid "Updates things like starting_mobject, and (for Transforms) target_mobject." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:29 msgid "Attributes" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:3 msgid "This updater will follow speed and rate function of any :class:`.ChangeSpeed` animation that is playing with ``affects_speed_updaters=True``. By default, updater functions added via the usual :meth:`.Mobject.add_updater` method do not respect the change of animation speed." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:8 msgid "The mobject to which the updater should be attached." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:9 msgid "The function that is called whenever a new frame is rendered." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:10 msgid "The position in the list of the mobject's updaters at which the function should be inserted." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:12 msgid "If ``True``, calls the update function when attaching it to the mobject." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.get_scaled_total_time:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:0 #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:3 msgid "This method gets called when the animation is over." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.speedmodifier.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.speedmodifier.rst:2 msgid "speedmodifier" msgstr "" #: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier:1 msgid "Utilities for modifying the speed at which animations are played." msgstr "" #: ../../source/reference/manim.animation.speedmodifier.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyComplexFunction.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:2 msgid "ApplyComplexFunction" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyComplexFunction``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyComplexFunction:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyMethod`" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyFunction.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyFunction.rst:2 msgid "ApplyFunction" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyFunction.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyFunction``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyFunction:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyFunction.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyFunction.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyMatrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:2 msgid "ApplyMatrix" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyMatrix``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyPointwiseFunction`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:1 msgid "Applies a matrix transform to an mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:3 msgid "The transformation matrix." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:4 msgid "The :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:5 msgid "The origin point for the transform. Defaults to ``ORIGIN``." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:6 msgid "Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyMethod.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyMethod.rst:2 msgid "ApplyMethod" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMethod.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyMethod``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:1 msgid "Animates a mobject by applying a method." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:3 msgid "Note that only the method needs to be passed to this animation, it is not required to pass the corresponding mobject. Furthermore, this animation class only works if the method returns the modified mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:8 msgid "The method that will be applied in the animation." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:9 msgid "Any positional arguments to be passed when applying the method." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:10 msgid "Any keyword arguments passed to :class:`~.Transform`." msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMethod.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyMethod.rst:23 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyPointwiseFunction.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:2 msgid "ApplyPointwiseFunction" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyPointwiseFunction``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyMethod`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:1 msgid "Animation that applies a pointwise function to a mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:2 msgid "ApplyPointwiseFunctionToCenter" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:4 msgid "Qualified name: ``manim.animation.transform.ApplyPointwiseFunctionToCenter``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyPointwiseFunction`" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:20::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter.begin:1 msgid "Begin the animation." msgstr "" #: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ClockwiseTransform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:2 msgid "ClockwiseTransform" msgstr "" #: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:4 msgid "Qualified name: ``manim.animation.transform.ClockwiseTransform``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:1 msgid "Transforms the points of a mobject along a clockwise oriented arc." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.CounterclockwiseTransform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:2 msgid "CounterclockwiseTransform" msgstr "" #: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:4 msgid "Qualified name: ``manim.animation.transform.CounterclockwiseTransform``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:1 msgid "Transforms the points of a mobject along a counterclockwise oriented arc." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.CyclicReplace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.CyclicReplace.rst:2 msgid "CyclicReplace" msgstr "" #: ../../source/reference/manim.animation.transform.CyclicReplace.rst:4 msgid "Qualified name: ``manim.animation.transform.CyclicReplace``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CyclicReplace:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../source/reference/manim.animation.transform.CyclicReplace.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.CyclicReplace.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.FadeToColor.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.FadeToColor.rst:2 msgid "FadeToColor" msgstr "" #: ../../source/reference/manim.animation.transform.FadeToColor.rst:4 msgid "Qualified name: ``manim.animation.transform.FadeToColor``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyMethod`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:1 msgid "Animation that changes color of a mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.FadeToColor.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.FadeToColor.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.FadeTransform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:2 msgid "FadeTransform" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:4 msgid "Qualified name: ``manim.animation.transform.FadeTransform``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:1 msgid "Fades one mobject into another." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:0 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:3 msgid "The starting :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:4 msgid "The target :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:5 msgid "Controls whether the target :class:`~.Mobject` is stretched during the animation. Default: ``True``." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:7 msgid "If the target mobject is not stretched automatically, this allows to adjust the initial scale of the target :class:`~.Mobject` while it is shifted in. Setting this to 0, 1, and 2, respectively, matches the length of the target with the length of the starting :class:`~.Mobject` in x, y, and z direction, respectively." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:12 msgid "Further keyword arguments are passed to the parent class." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:15 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:24::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.begin:1 msgid "Initial setup for the animation." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:24::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:24::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:1 msgid "Get all mobjects involved in the animation." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:24::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.ghost_to:1 msgid "Replaces the source by the target and sets the opacity to 0." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransform.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.begin:3 msgid "The mobject to which this animation is bound is a group consisting of both the starting and the ending mobject. At the start, the ending mobject replaces the starting mobject (and is completely faded). In the end, it is set to be the other way around." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:3 msgid "Ordering must match the ordering of arguments to interpolate_submobject" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:0 msgid "Returns" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:5 msgid "The sequence of mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.FadeTransformPieces.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:2 msgid "FadeTransformPieces" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:4 msgid "Qualified name: ``manim.animation.transform.FadeTransformPieces``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:1 msgid "Bases: :py:class:`manim.animation.transform.FadeTransform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:1 msgid "Fades submobjects of one mobject into submobjects of another one." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:21::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces.begin:1 msgid "Initial setup for the animation." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:21::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces.ghost_to:1 msgid "Replaces the source submobjects by the target submobjects and sets the opacity to 0." msgstr "" #: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:23 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.MoveToTarget.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.MoveToTarget.rst:2 msgid "MoveToTarget" msgstr "" #: ../../source/reference/manim.animation.transform.MoveToTarget.rst:4 msgid "Qualified name: ``manim.animation.transform.MoveToTarget``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:1 msgid "Transforms a mobject to the mobject stored in its ``target`` attribute." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:3 msgid "After calling the :meth:`~.Mobject.generate_target` method, the :attr:`target` attribute of the mobject is populated with a copy of it. After modifying the attribute, playing the :class:`.MoveToTarget` animation transforms the original mobject into the modified one stored in the :attr:`target` attribute." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.MoveToTarget.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.MoveToTarget.rst:22 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ReplacementTransform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:2 msgid "ReplacementTransform" msgstr "" #: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:4 msgid "Qualified name: ``manim.animation.transform.ReplacementTransform``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:1 msgid "Replaces and morphs a mobject into a target mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:3 msgid "The starting :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:4 msgid "The target :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:5 msgid "Further keyword arguments that are passed to :class:`Transform`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.Restore.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.Restore.rst:2 msgid "Restore" msgstr "" #: ../../source/reference/manim.animation.transform.Restore.rst:4 msgid "Qualified name: ``manim.animation.transform.Restore``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyMethod`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:1 msgid "Transforms a mobject to its last saved state." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:3 msgid "To save the state of a mobject, use the :meth:`~.Mobject.save_state` method." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.Restore.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.Restore.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ScaleInPlace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:2 msgid "ScaleInPlace" msgstr "" #: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:4 msgid "Qualified name: ``manim.animation.transform.ScaleInPlace``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:1 msgid "Bases: :py:class:`manim.animation.transform.ApplyMethod`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:1 msgid "Animation that scales a mobject by a certain factor." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.ShrinkToCenter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:2 msgid "ShrinkToCenter" msgstr "" #: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:4 msgid "Qualified name: ``manim.animation.transform.ShrinkToCenter``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:1 msgid "Bases: :py:class:`manim.animation.transform.ScaleInPlace`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:1 msgid "Animation that makes a mobject shrink to center." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.Swap.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.Swap.rst:2 msgid "Swap" msgstr "" #: ../../source/reference/manim.animation.transform.Swap.rst:4 msgid "Qualified name: ``manim.animation.transform.Swap``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Swap:1 msgid "Bases: :py:class:`manim.animation.transform.CyclicReplace`" msgstr "" #: ../../source/reference/manim.animation.transform.Swap.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.Swap.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.Transform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.Transform.rst:2 msgid "Transform" msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:4 msgid "Qualified name: ``manim.animation.transform.Transform``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:1 msgid "A Transform transforms a Mobject into a target Mobject." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:0 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:3 msgid "The :class:`.Mobject` to be transformed. It will be mutated to become the ``target_mobject``." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:4 msgid "The target of the transformation." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:5 msgid "A function defining the path that the points of the ``mobject`` are being moved along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:7 msgid "The arc angle (in radians) that the points of ``mobject`` will follow to reach the points of the target if using a circular path arc, see ``path_arc_centers``. See also :func:`manim.utils.paths.path_along_arc`." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:10 msgid "The axis to rotate along if using a circular path arc, see ``path_arc_centers``." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:11 msgid "The center of the circular arcs along which the points of ``mobject`` are moved by the transformation. If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:11 msgid "The center of the circular arcs along which the points of ``mobject`` are moved by the transformation." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:14 msgid "If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:17 msgid "Controls which mobject is replaced when the transformation is complete. If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:17 msgid "Controls which mobject is replaced when the transformation is complete." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:19 msgid "If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:23 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:25::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:1 msgid "Begin the animation." msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:25::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:25::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:1 msgid "Get all mobjects involved in the animation." msgstr "" #: ../../source/reference/manim.animation.transform.Transform.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:3 msgid "This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:0 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:0 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:3 msgid "Ordering must match the ordering of arguments to interpolate_submobject" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:0 msgid "Returns" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.TransformAnimations.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.TransformAnimations.rst:2 msgid "TransformAnimations" msgstr "" #: ../../source/reference/manim.animation.transform.TransformAnimations.rst:4 msgid "Qualified name: ``manim.animation.transform.TransformAnimations``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../source/reference/manim.animation.transform.TransformAnimations.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.TransformAnimations.rst:20::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../source/reference/manim.animation.transform.TransformAnimations.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.TransformFromCopy.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:2 msgid "TransformFromCopy" msgstr "" #: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:4 msgid "Qualified name: ``manim.animation.transform.TransformFromCopy``" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy:1 msgid "Bases: :py:class:`manim.animation.transform.Transform`" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy:1 msgid "Performs a reversed Transform" msgstr "" #: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:20::1 #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:1 msgid "Set the animation progress." msgstr "" #: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:3 msgid "This method gets called for every frame during an animation." msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:5 msgid "The relative time to set the animation to, 0 meaning the start, 1 meaning the end." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform.rst:2 msgid "transform" msgstr "" #: ../../../manim/animation/transform.py:docstring of manim.animation.transform:1 msgid "Animations transforming one mobject into another." msgstr "" #: ../../source/reference/manim.animation.transform.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Applies a matrix transform to an mobject." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Animates a mobject by applying a method." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Animation that applies a pointwise function to a mobject." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Transforms the points of a mobject along a clockwise oriented arc." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Transforms the points of a mobject along a counterclockwise oriented arc." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Animation that changes color of a mobject." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Fades one mobject into another." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Fades submobjects of one mobject into submobjects of another one." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Transforms a mobject to the mobject stored in its ``target`` attribute." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Replaces and morphs a mobject into a target mobject." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Transforms a mobject to its last saved state." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Animation that scales a mobject by a certain factor." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "Animation that makes a mobject shrink to center." msgstr "" #: ../../source/reference/manim.animation.transform.rst:60::1 msgid "A Transform transforms a Mobject into a target Mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:2 msgid "TransformMatchingAbstractBase" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:4 msgid "Qualified name: ``manim.animation.transform\\_matching\\_parts.TransformMatchingAbstractBase``" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:1 msgid "Bases: :py:class:`manim.animation.composition.AnimationGroup`" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:1 msgid "Abstract base class for transformations that keep track of matching parts." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:3 msgid "Subclasses have to implement the two static methods :meth:`~.TransformMatchingAbstractBase.get_mobject_parts` and :meth:`~.TransformMatchingAbstractBase.get_mobject_key`." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:7 msgid "Basically, this transformation first maps all submobjects returned by the ``get_mobject_parts`` method to certain keys by applying the ``get_mobject_key`` method. Then, submobjects with matching keys are transformed into each other." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:0 #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:12 msgid "The starting :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:13 msgid "The target :class:`~.Mobject`." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:14 msgid "Controls whether submobjects without a matching key are transformed into each other by using :class:`~.Transform`. Default: ``False``." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:16 msgid "Controls whether submobjects without a matching key are transformed into each other by using :class:`~.FadeTransform`. Default: ``False``." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:18 msgid "Optional. A dictionary mapping keys belonging to some of the starting mobject's submobjects (i.e., the return values of the ``get_mobject_key`` method) to some keys belonging to the target mobject's submobjects that should be transformed although the keys don't match." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:22 msgid "All further keyword arguments are passed to the submobject transformations." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:26 msgid "If neither ``transform_mismatches`` nor ``fade_transform_mismatches`` are set to ``True``, submobjects without matching keys in the starting mobject are faded out in the direction of the unmatched submobjects in the target mobject, and unmatched submobjects in the target mobject are faded in from the direction of the unmatched submobjects in the start mobject." msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:1::1 #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:1 msgid "Clean up the :class:`~.Scene` after finishing the animation." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:3 msgid "This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:6 msgid "The scene the animation should be cleaned up from." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:2 msgid "TransformMatchingShapes" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:4 msgid "Qualified name: ``manim.animation.transform\\_matching\\_parts.TransformMatchingShapes``" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:1 msgid "Bases: :py:class:`manim.animation.transform_matching_parts.TransformMatchingAbstractBase`" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:1 msgid "An animation trying to transform groups by matching the shape of their submobjects." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:4 msgid "Two submobjects match if the hash of their point coordinates after normalization (i.e., after translation to the origin, fixing the submobject height at 1 unit, and rounding the coordinates to three decimal places) matches." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:12 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingTex.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:2 msgid "TransformMatchingTex" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:4 msgid "Qualified name: ``manim.animation.transform\\_matching\\_parts.TransformMatchingTex``" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:1 msgid "Bases: :py:class:`manim.animation.transform_matching_parts.TransformMatchingAbstractBase`" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:1 msgid "A transformation trying to transform rendered LaTeX strings." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:3 msgid "Two submobjects match if their ``tex_string`` matches." msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:14 msgid "Methods" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.transform_matching_parts.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.transform_matching_parts.rst:2 msgid "transform\\_matching\\_parts" msgstr "" #: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts:1 msgid "Animations that try to transform Mobjects while keeping track of identical parts." msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.rst:24::1 msgid "Abstract base class for transformations that keep track of matching parts." msgstr "" #: ../../source/reference/manim.animation.transform_matching_parts.rst:24::1 msgid "An animation trying to transform groups by matching the shape of their submobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.update.MaintainPositionRelativeTo.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.animation.update.UpdateFromAlphaFunc.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.animation.update.UpdateFromFunc.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.animation.update.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.mobject_update_utils.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.mobject_update_utils.rst:2 msgid "mobject\\_update\\_utils" msgstr "" #: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils:1 msgid "Utility functions for continuous animation of mobjects." msgstr "" #: ../../source/reference/manim.animation.updaters.mobject_update_utils.rst:20 msgid "Functions" msgstr "" #: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils.f_always:1 msgid "More functional version of always, where instead of taking in args, it takes in functions which output the relevant arguments." msgstr "" #: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils.turn_animation_into_updater:1 msgid "Add an updater to the animation's mobject which applies the interpolation and update functions of the animation" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.rst:2 msgid "updaters" msgstr "" #: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:1 msgid "Animations and utility mobjects related to update functions." msgstr "" #: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:4 msgid "Modules" msgstr "" #: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:11::1 msgid "Utility functions for continuous animation of mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:2 msgid "MaintainPositionRelativeTo" msgstr "" #: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:4 msgid "Qualified name: ``manim.animation.updaters.update.MaintainPositionRelativeTo``" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:1::1 #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:2 msgid "UpdateFromAlphaFunc" msgstr "" #: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:4 msgid "Qualified name: ``manim.animation.updaters.update.UpdateFromAlphaFunc``" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc:1 msgid "Bases: :py:class:`manim.animation.updaters.update.UpdateFromFunc`" msgstr "" #: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:1::1 #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.update.UpdateFromFunc.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:2 msgid "UpdateFromFunc" msgstr "" #: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:4 msgid "Qualified name: ``manim.animation.updaters.update.UpdateFromFunc``" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc:1 msgid "Bases: :py:class:`manim.animation.animation.Animation`" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc:1 msgid "update_function of the form func(mobject), presumably to be used when the state of one mobject is dependent on another simultaneously animated mobject" msgstr "" #: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:14 msgid "Methods" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:1::1 #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:1 msgid "Interpolates the mobject of the :class:`Animation` based on alpha value." msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:0 msgid "Parameters" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:3 msgid "A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.animation.updaters.update.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.animation.updaters.update.rst:2 msgid "update" msgstr "" #: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update:1 msgid "Animations that update mobjects." msgstr "" #: ../../source/reference/manim.animation.updaters.update.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:2 msgid "BackgroundColoredVMobjectDisplayer" msgstr "" #: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:4 msgid "Qualified name: ``manim.camera.camera.BackgroundColoredVMobjectDisplayer``" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:1 msgid "Camera object to use." msgstr "" #: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:14 msgid "Methods" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1 msgid "Displays the colored VMobjects." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:1 msgid "Gets the background array that has the passed file_name." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:1 msgid "Resizes the pixel array representing the background." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:1 msgid "Resizes the background array to match the passed pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:3 msgid "The VMobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0 msgid "Returns" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:6 msgid "The pixel array with the `cvmobjects` displayed." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0 msgid "Return type" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:3 msgid "The background image or its file name." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:5 msgid "The pixel array of the image." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:3 msgid "The pixel" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:5 msgid "The new width of the background" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:7 msgid "The new height of the background" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:9 msgid "The PIL image mode, by default \"RGBA\"" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:12 msgid "The numpy pixel array of the resized background." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:3 msgid "The prospective pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:5 msgid "The pixel array whose width and height should be matched." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.camera.Camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.camera.Camera.rst:2 msgid "Camera" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:4 msgid "Qualified name: ``manim.camera.camera.Camera``" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:1 msgid "Base camera class." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:3 msgid "This is the object which takes care of what exactly is displayed on screen at any given moment." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:6 msgid "Some important configuration values and local variables to note are:" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:10 msgid "background_image : :class:`str`, optional" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:9 msgid "str, optional" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:9 msgid "The path to an image that should be the background image. If not set, the background is filled with `self.background_color`" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:14 msgid "pixel_height : :class:`int`, optional" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:13 msgid "int, optional" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:13 msgid "The height of the scene in pixels." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:16 msgid "Initialises the Camera." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjusted_thickness:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_thickening_nudges:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:18 msgid "What self.background should be, by default None as will be set later." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:20 msgid "Any local variables to be set." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:1 msgid "If any of the points in the passed array are out of the viable range, they are adjusted suitably." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::0 #: ../../source/reference/manim.camera.camera.Camera.rst:63::0 msgid "param thickness" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:1 msgid "Fills the cairo context" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:1 msgid "Applies a stroke to the VMobject in the cairo context." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:1 msgid "Caches the passed Pixel array into a Cairo Context" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:1 msgid "Capture mobjects by storing it in :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:1 msgid "Converts a pixel array from values that have floats in then to proper RGB values." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:1 msgid "Displays an ImageMobject by changing the pixel_array suitably." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:1 msgid "Displays multiple vmobjects that have the same color as the background." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:1 msgid "Displays multiple image mobjects by modifying the passed pixel_array." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:1 msgid "Displays multiple VMobjects in the cairo context, as long as they don't have background colors." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:1 msgid "Displays multiple PMobjects by modifying the passed pixel array." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:1 msgid "Displays multiple VMobjects in the pixel_array" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 msgid "Displays a PMobject by modifying the Pixel array suitably." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:1 msgid "Displays a VMobject in the cairo context" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:1 msgid "Returns the background_colored_vmobject_displayer if it exists or makes one and returns it if not." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:1 msgid "Returns the cached cairo context of the passed pixel array if it exists, and None if it doesn't." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:1 msgid "Returns the cairo context for a pixel array after caching it to self.pixel_array_to_cairo_context If that array has already been cached, it returns the cached version instead." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:1 msgid "Returns the cartesian coordinates of each pixel." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:1 msgid "Returns the RGBA array of the fill of the passed VMobject" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:1 msgid "Returns an image from the passed pixel array, or from the current frame if the passed pixel array is none." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:1 msgid "Used to get the list of mobjects to display with the camera." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:1 msgid "Gets the RGBA array for the stroke of the passed VMobject." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 msgid "Initialize the background." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:1 msgid "Checks whether the passed mobject is in frame or not." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 msgid "Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:1 msgid "Returns array of pixels that are on the screen from a given array of pixel_coordinates" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:1 msgid "Overlays a PIL image on the passed pixel array." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:1 msgid "Overlays an RGBA array on top of the given Pixel array." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:1 msgid "Resets the camera's pixel array to that of the background" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:1 msgid "This method resets the height and width of a single pixel to the passed new_height and new_width." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:1 msgid "Changes frame_shape to match the aspect ratio of the pixels, where fixed_dimension determines whether frame_height or frame_width remains fixed while the other changes accordingly." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:1 msgid "Sets the background to the passed pixel_array after converting to valid RGB values." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 msgid "Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:1 msgid "Sets the color of the cairo context" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:1 msgid "Sets a path for the cairo context with the vmobject passed" msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:1 msgid "Sets the pixel array of the camera to the passed pixel array." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:1 msgid "Returns thickened coordinates for a passed array of pixel coords and a thickness to thicken by." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:63::1 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:1 msgid "Return the type of mobject, if it is a type that can be rendered." msgstr "" #: ../../source/reference/manim.camera.camera.Camera.rst:65 msgid "Attributes" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:4 msgid "The points to adjust" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0 msgid "Returns" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:7 msgid "The adjusted points." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjusted_thickness:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_thickening_nudges:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0 msgid "Return type" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:3 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:3 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:3 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:3 msgid "The cairo context" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:5 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:5 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:3 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:4 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:5 msgid "The VMobject" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:8 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:8 msgid "The camera object." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:7 msgid "Whether or not to consider the background when applying this stroke width, by default False" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:11 msgid "The camera object with the stroke applied." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:3 msgid "The pixel array to cache" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:5 msgid "The context to cache it into." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:3 msgid "This is a single-mobject version of :meth:`capture_mobjects`." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:5 msgid "Mobject to capture." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:6 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:12 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:12 msgid "Notes" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:13 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:13 msgid "For a list of classes that can currently be rendered, see :meth:`display_funcs`." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:4 msgid "Pixel array to convert." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:6 msgid "Whether or not to convert float values to ints, by default False" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:9 msgid "The new, converted pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:3 msgid "The imageMobject to display" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:5 msgid "The Pixel array to put the imagemobject in." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:3 msgid "List of Colored VMobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:5 msgid "The pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:3 msgid "list of ImageMobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:5 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:5 msgid "The pixel array to modify." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:4 msgid "list of the VMobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:6 msgid "The Pixel array to add the VMobjects to." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:3 msgid "List of PMobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:3 msgid "list of VMobjects to display" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:5 msgid "The pixel array" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_point_cloud:1 msgid "Displays a PMobject by modifying the Pixel array suitably.. TODO: Write a description for the rgbas argument. :param pmobject: Point Cloud Mobject :type pmobject: PMobject :param points: The points to display in the point cloud mobject :type points: list :param rgbas: :type rgbas: np.array :param thickness: The thickness of each point of the PMobject :type thickness: int, float :param pixel_array: The pixel array to modify. :type pixel_array: np.array" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:3 msgid "The Vectorized Mobject to display" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:5 msgid "The cairo context to use." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:8 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:10 msgid "The camera object" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:4 msgid "Object that displays VMobjects that have the same color as the background." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:4 msgid "The pixel array to check." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:7 msgid "The cached cairo context." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:6 msgid "The Pixel array to get the cairo context of." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:9 msgid "The cairo context of the pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:3 msgid "The array of cartesian coordinates." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:6 msgid "The RGBA Array of the fill of the VMobject" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:5 msgid "The pixel array from which to get an image, by default None" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:8 msgid "The PIL image of the array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:4 msgid "The Mobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:6 msgid "Whether or not to include the submobjects of mobjects, by default True" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:8 msgid "Any mobjects to exclude, by default None" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:11 msgid "list of mobjects" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:6 msgid "Whether or not to consider the background when getting the stroke RGBAs, by default False" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:10 msgid "The RGBA array of the stroke." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.init_background:1 msgid "Initialize the background. If self.background_image is the path of an image the image is set as background; else, the default background color fills the background." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:4 msgid "The mobject for which the checking needs to be done." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:7 msgid "True if in frame, False otherwise." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:1 msgid "Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:5 #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:5 msgid "The function whose input is an (x,y) pair of coordinates and whose return values must be the colors for that point" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:9 msgid "The pixel array which can then be passed to set_background." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:4 msgid "The pixel coords to check." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:7 msgid "The pixel coords on screen." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:3 msgid "The Pixel array" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:5 msgid "The Image to overlay." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:3 msgid "The original pixel array to modify." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:5 msgid "The new pixel array to overlay." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:4 msgid "The camera object after setting the pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:4 msgid "The new height of the entire scene in pixels" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:6 msgid "The new width of the entire scene in pixels" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:6 msgid "If 0, height is scaled with respect to width else, width is scaled with respect to height." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:4 msgid "The pixel array to set the background to." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:6 msgid "Whether or not to convert floats values to proper RGB valid ones, by default False" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:1 msgid "Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:5 msgid "The RGBA array with which to color the context." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:7 msgid "The VMobject with which to set the color." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:8 msgid "Camera object after setting cairo_context_path" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:3 msgid "The pixel array to convert and then set as the camera's pixel array." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:5 msgid "Whether or not to convert float values to proper RGB values, by default False" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:4 msgid "Pixel coordinates" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:6 msgid "Thickness" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:9 msgid "Array of thickened pixel coords." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:3 msgid "If `mobject` is an instance of a class that inherits from a class that can be rendered, return the super class. For example, an instance of a Square is also an instance of VMobject, and these can be rendered. Therefore, `type_or_raise(Square())` returns True." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:8 msgid "The object to take the type of." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:15 msgid "The type of mobjects, if it can be rendered." msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:16 msgid "Type[:class:`~.Mobject`]" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0 msgid "Raises" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.camera.rst:2 msgid "camera" msgstr "" #: ../../../manim/camera/camera.py:docstring of manim.camera.camera:1 msgid "A camera converts the mobjects contained in a Scene into an array of pixels." msgstr "" #: ../../source/reference/manim.camera.camera.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.camera.camera.rst:22::0 msgid "param camera" msgstr "" #: ../../source/reference/manim.camera.camera.rst:22::1 msgid "Camera object to use." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.mapping_camera.MappingCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:2 msgid "MappingCamera" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:4 msgid "Qualified name: ``manim.camera.mapping\\_camera.MappingCamera``" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:1 msgid "Bases: :py:class:`manim.camera.camera.Camera`" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:1 msgid "Camera object that allows mapping between objects." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:4 msgid "Initialises the Camera." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:0 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:6 msgid "What self.background should be, by default None as will be set later." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:8 msgid "Any local variables to be set." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:21::1 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:12 msgid "Notes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.mapping_camera.OldMultiCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:2 msgid "OldMultiCamera" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:4 msgid "Qualified name: ``manim.camera.mapping\\_camera.OldMultiCamera``" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:1 msgid "Bases: :py:class:`manim.camera.camera.Camera`" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:1 msgid "Initialises the Camera." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:0 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:0 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:0 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:3 msgid "What self.background should be, by default None as will be set later." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:5 msgid "Any local variables to be set." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23::1 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23::1 msgid "Initialize the background." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23::1 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:1 msgid "Sets the background to the passed pixel_array after converting to valid RGB values." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23::1 #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:1 msgid "Sets the pixel array of the camera to the passed pixel array." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:12 msgid "Notes" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:13 msgid "For a list of classes that can currently be rendered, see :meth:`display_funcs`." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.init_background:1 msgid "Initialize the background. If self.background_image is the path of an image the image is set as background; else, the default background color fills the background." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:4 msgid "The pixel array to set the background to." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:6 msgid "Whether or not to convert floats values to proper RGB valid ones, by default False" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:3 msgid "The pixel array to convert and then set as the camera's pixel array." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.mapping_camera.SplitScreenCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:2 msgid "SplitScreenCamera" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:4 msgid "Qualified name: ``manim.camera.mapping\\_camera.SplitScreenCamera``" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:1 msgid "Bases: :py:class:`manim.camera.mapping_camera.OldMultiCamera`" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:1 msgid "Initialises the Camera." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:3 msgid "What self.background should be, by default None as will be set later." msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:5 msgid "Any local variables to be set." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:21 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.mapping_camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.mapping_camera.rst:2 msgid "mapping\\_camera" msgstr "" #: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera:1 msgid "A camera that allows mapping between objects." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.camera.mapping_camera.rst:24::1 msgid "Camera object that allows mapping between objects." msgstr "" #: ../../source/reference/manim.camera.mapping_camera.rst:24::1 #: ../../source/reference/manim.camera.mapping_camera.rst:24::1 msgid "Initialises the Camera." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.moving_camera.CameraFrame.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.camera.moving_camera.MovingCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:2 msgid "MovingCamera" msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:4 msgid "Qualified name: ``manim.camera.moving\\_camera.MovingCamera``" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:1 msgid "Bases: :py:class:`manim.camera.camera.Camera`" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:1 msgid "Stays in line with the height, width and position of it's 'frame', which is a Rectangle" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:8 msgid "Frame is a Mobject, (should almost certainly be a rectangle) determining which region of space the camera displays" msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1 msgid "Zooms on to a given array of mobjects (or a singular mobject) and automatically resizes to frame all the mobjects." msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24::1 #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24::1 msgid "Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame." msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_mobjects_indicating_movement:1 msgid "Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving" msgstr "" #: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:1 msgid "Returns the centerpoint of the frame in cartesian coordinates." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:1 msgid "Returns the height of the frame." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1::1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:1 msgid "Returns the width of the frame" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:6 msgid "This method only works when 2D-objects in the XY-plane are considered, it will not work correctly when the camera has been rotated." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:9 msgid "The mobject or array of mobjects that the camera will focus on." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:10 msgid "The width of the margin that is added to the frame (optional, 0 by default)." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:11 msgid "If set to ``True``, only allows focusing on mobjects that are already in frame." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:12 msgid "If set to ``False``, applies the changes instead of returning the corresponding animation" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:0 msgid "Returns" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:14 msgid "_AnimationBuilder that zooms the camera view to a given list of mobjects or ScreenRectangle with position and size updated to zoomed position." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:0 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_mobjects_indicating_movement:0 msgid "Return type" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.cache_cairo_context:1 #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_cached_cairo_context:1 msgid "Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame. So no caching." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:12 msgid "Notes" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:13 msgid "For a list of classes that can currently be rendered, see :meth:`display_funcs`." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:3 msgid "The cartesian coordinates of the center of the frame." msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:3 msgid "The height of the frame." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.moving_camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.moving_camera.rst:2 msgid "moving\\_camera" msgstr "" #: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera:1 msgid "A camera able to move through a scene." msgstr "" #: ../../source/reference/manim.camera.moving_camera.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.multi_camera.MultiCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:2 msgid "MultiCamera" msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:4 msgid "Qualified name: ``manim.camera.multi\\_camera.MultiCamera``" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:1 msgid "Bases: :py:class:`manim.camera.moving_camera.MovingCamera`" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:1 msgid "Camera Object that allows for multiple perspectives." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:3 msgid "Initialises the MultiCamera" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:0 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:0 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:7 msgid "Any valid keyword arguments of MovingCamera." msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24::1 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1 msgid "Adds an ImageMobject that's been obtained from the camera into the list ``self.image_mobject_from_cameras``" msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24::1 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24::1 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.get_mobjects_indicating_movement:1 msgid "Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving" msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24::1 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:1 msgid "Resets the MultiCamera." msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24::1 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.update_sub_cameras:1 msgid "Reshape sub_camera pixel_arrays" msgstr "" #: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1::1 msgid "Returns the centerpoint of the frame in cartesian coordinates." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1::1 msgid "Returns the height of the frame." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1::1 msgid "Returns the width of the frame" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:4 msgid "The ImageMobject to add to self.image_mobject_from_cameras" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:12 msgid "Notes" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:13 msgid "For a list of classes that can currently be rendered, see :meth:`display_funcs`." msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.get_mobjects_indicating_movement:0 #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:0 msgid "Return type" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:0 msgid "Returns" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.multi_camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.multi_camera.rst:2 msgid "multi\\_camera" msgstr "" #: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera:1 msgid "A camera supporting multiple perspectives." msgstr "" #: ../../source/reference/manim.camera.multi_camera.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.three_d_camera.ThreeDCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:2 msgid "ThreeDCamera" msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:4 msgid "Qualified name: ``manim.camera.three\\_d\\_camera.ThreeDCamera``" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:1 msgid "Bases: :py:class:`manim.camera.camera.Camera`" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:1 msgid "Initializes the ThreeDCamera" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_theta:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:0 msgid "Parameters" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:3 msgid "Any argument of Camera" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:4 msgid "Any keyword argument of Camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 msgid "This method allows the mobject to have a fixed position, even when the camera moves around." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 msgid "This method allows the mobject to have a fixed orientation, even when the camera moves around." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:1 msgid "Capture mobjects by printing them on :attr:`pixel_array`." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:1 msgid "Generates a rotation matrix based off the current position of the camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:1 msgid "Returns the RGBA array of the fill of the passed VMobject" msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:1 msgid "Returns focal_distance of the Camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:1 msgid "Returns the rotation of the camera about the vector from the ORIGIN to the Camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:1 msgid "Used to get the list of mobjects to display with the camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:1 msgid "Returns the Polar angle (the angle off Z_AXIS) phi." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:1 msgid "Returns the matrix corresponding to the current position of the camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:1 msgid "Gets the RGBA array for the stroke of the passed VMobject." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:1 msgid "Returns the Azimuthal i.e the angle that spins the camera around the Z_AXIS." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:1 msgid "Returns list of ValueTrackers of phi, theta, focal_distance and gamma" msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:1 msgid "Returns the zoom amount of the camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:1 msgid "Applies the current rotation_matrix as a projection matrix to the passed point." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:1 msgid "Applies the current rotation_matrix as a projection matrix to the passed array of points." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 msgid "If a mobject was fixed in frame by passing it through :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 msgid "If a mobject was fixed in its orientation by passing it through :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.reset_rotation_matrix:1 msgid "Sets the value of self.rotation_matrix to the matrix corresponding to the current position of the camera" msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:1 msgid "Sets the focal_distance of the Camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:1 msgid "Sets the angle of rotation of the camera about the vector from the ORIGIN to the Camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:1 msgid "Sets the polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_theta:1 msgid "Sets the azimuthal angle i.e the angle that spins the camera around Z_AXIS in radians." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45::1 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:1 msgid "Sets the zoom amount of the camera." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:47 msgid "Attributes" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:1 msgid "This method allows the mobject to have a fixed position, even when the camera moves around. E.G If it was passed through this method, at the top of the frame, it will continue to be displayed at the top of the frame." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:6 msgid "Highly useful when displaying Titles or formulae or the like." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:8 msgid "The mobject to fix in frame." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:1 msgid "This method allows the mobject to have a fixed orientation, even when the camera moves around. E.G If it was passed through this method, facing the camera, it will continue to face the camera even as the camera moves. Highly useful when adding labels to graphs and the like." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:7 msgid "The mobject whose orientation must be fixed." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:9 msgid "Whether or not to use the function that takes the mobject's center as centerpoint, by default False" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:12 msgid "The function which returns the centerpoint with respect to which the mobject will be oriented, by default None" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:3 msgid "This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:6 msgid "Mobjects to capture." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:8 msgid "Keyword arguments to be passed to :meth:`get_mobjects_to_display`." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:12 msgid "Notes" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:13 msgid "For a list of classes that can currently be rendered, see :meth:`display_funcs`." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0 msgid "Returns" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:3 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:3 msgid "The matrix corresponding to the current position of the camera." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0 msgid "Return type" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:3 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:4 msgid "The VMobject" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:6 msgid "The RGBA Array of the fill of the VMobject" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:3 msgid "The focal_distance of the Camera in MUnits." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:3 msgid "The angle of rotation of the camera about the vector from the ORIGIN to the Camera in radians" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:4 msgid "The Mobjects" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:6 msgid "Whether or not to include the submobjects of mobjects, by default True" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:8 msgid "Any mobjects to exclude, by default None" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:11 msgid "list of mobjects" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:3 msgid "The Polar angle in radians." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:6 msgid "Whether or not to consider the background when getting the stroke RGBAs, by default False" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:10 msgid "The RGBA array of the stroke." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:3 msgid "The Azimuthal angle in radians." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:3 msgid "list of ValueTracker objects" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:3 #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:3 msgid "The zoom amount of the camera." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:4 msgid "The point to project." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:7 msgid "The point after projection." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:4 msgid "The list of points to project." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:7 msgid "The points after projecting." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:1 msgid "If a mobject was fixed in frame by passing it through :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing. The Mobject will no longer be fixed in frame." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:5 msgid "The mobjects which need not be fixed in frame any longer." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:1 msgid "If a mobject was fixed in its orientation by passing it through :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing. The Mobject will no longer have a fixed orientation." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:5 msgid "The mobjects whose orientation need not be fixed any longer." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:3 msgid "The focal_distance of the Camera." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:3 msgid "The new angle of rotation of the camera." msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:3 msgid "The new value of the polar angle in radians." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.camera.three_d_camera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.camera.three_d_camera.rst:2 msgid "three\\_d\\_camera" msgstr "" #: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera:1 msgid "A camera that can be positioned and oriented in three-dimensional space." msgstr "" #: ../../source/reference/manim.camera.three_d_camera.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.constants.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.constants.rst:2 msgid "constants" msgstr "" #: ../../../manim/constants.py:docstring of manim.constants:1 msgid "Constant definitions." msgstr "" #: ../../source/reference/manim.constants.rst:11 msgid "Module Attributes" msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "The center of the coordinate system." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the positive Y direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the negative Y direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the positive X direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the negative X direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the negative Z direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One unit step in the positive Z direction." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One step up plus one step left." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One step up plus one step right." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One step down plus one step left." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "One step down plus one step right." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "The ratio of the circumference of a circle to its diameter." msgstr "" #: ../../source/reference/manim.constants.rst:27::1 msgid "The ratio of the circumference of a circle to its radius." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.boolean_ops.Difference.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.boolean_ops.Exclusion.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.boolean_ops.Intersection.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.boolean_ops.Union.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.boolean_ops.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.changing.AnimatedBoundary.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.changing.TracedPath.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.changing.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.Axes.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.ComplexPlane.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.CoordinateSystem.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.NumberPlane.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.PolarPlane.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.ThreeDAxes.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.coordinate_systems.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.frame.FullScreenFadeRectangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.frame.FullScreenRectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:2 msgid "FullScreenRectangle" msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:4 msgid "Qualified name: ``manim.mobject.frame.FullScreenRectangle``" msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.FullScreenRectangle:1 msgid "Bases: :py:class:`manim.mobject.frame.ScreenRectangle`" msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33::1 msgid "The aspect ratio." msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.frame.PictureInPictureFrame.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.frame.ScreenRectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:2 msgid "ScreenRectangle" msgstr "" #: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:4 msgid "Qualified name: ``manim.mobject.frame.ScreenRectangle``" msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`" msgstr "" #: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:21 msgid "Attributes" msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1 msgid "The aspect ratio." msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.frame.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.frame.rst:2 msgid "frame" msgstr "" #: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame:1 msgid "Special rectangles." msgstr "" #: ../../source/reference/manim.mobject.frame.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.functions.FunctionGraph.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.functions.ImplicitFunction.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.functions.ParametricFunction.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.functions.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Angle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.AnnotationDot.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.AnnularSector.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Annulus.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArcBetweenPoints.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArcPolygon.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArcPolygonFromArcs.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Arrow.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowCircleFilledTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowCircleTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowSquareFilledTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowSquareTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTriangleFilledTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTriangleTip.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Circle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.CubicBezier.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.CurvedArrow.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.CurvedDoubleArrow.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Cutout.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.DashedLine.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Dot.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.DoubleArrow.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Elbow.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Ellipse.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.LabeledDot.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Polygon.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Rectangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.RegularPolygon.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.RegularPolygram.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.RightAngle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.RoundedRectangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Sector.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Square.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Star.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.TangentLine.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.TipableVMobject.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Triangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.Vector.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.AnnotationDot.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:2 msgid "AnnotationDot" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.AnnotationDot``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnotationDot:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Dot`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnotationDot:1 msgid "A dot with bigger radius and bold stroke to annotate scenes." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.AnnularSector.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:2 msgid "AnnularSector" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.AnnularSector``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Arc`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:1 msgid "The inside radius of the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:2 msgid "The outside radius of the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:3 msgid "The clockwise angle of the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:4 msgid "The starting clockwise angle of the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:5 msgid "The opacity of the color filled in the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:6 msgid "The stroke width of the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:7 msgid "The color filled into the Annular Sector." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:10 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:21::1 #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:21::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Annulus.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:2 msgid "Annulus" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Annulus``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Circle`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:1 msgid "Region between two concentric :class:`Circles <.Circle>`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:3 msgid "The radius of the inner :class:`Circle`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:4 msgid "The radius of the outer :class:`Circle`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:5 msgid "Additional arguments to be passed to :class:`Annulus`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:21::1 #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:21::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Arc.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:2 msgid "Arc" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Arc``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.TipableVMobject`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:1 msgid "A circular arc." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:5 msgid "A simple arc of angle Pi." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:24::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:24::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.get_arc_center:1 msgid "Looks at the normals to the first two anchors, and finds their intersection points" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcBetweenPoints.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:2 msgid "ArcBetweenPoints" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.ArcBetweenPoints``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Arc`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:1 msgid "Inherits from Arc and additionally takes 2 points between which the arc is spanned." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:4 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcPolygon.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:2 msgid "ArcPolygon" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.ArcPolygon``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:1 msgid "A generalized polygon allowing for points to be connected with arcs." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:3 msgid "This version tries to stick close to the way :class:`Polygon` is used. Points can be passed to it directly which are used to generate the according arcs (using :class:`ArcBetweenPoints`). An angle or radius can be passed to it to use across all arcs, but to configure arcs individually an ``arc_config`` list has to be passed with the syntax explained below." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:9 msgid "A list of vertices, start and end points for the arc segments." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:10 msgid "The angle used for constructing the arcs. If no other parameters are set, this angle is used to construct all arcs." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:12 msgid "The circle radius used to construct the arcs. If specified, overrides the specified ``angle``." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:14 msgid "When passing a ``dict``, its content will be passed as keyword arguments to :class:`~.ArcBetweenPoints`. Otherwise, a list of dictionaries containing values that are passed as keyword arguments for every individual arc can be passed." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:18 msgid "Further keyword arguments that are passed to the constructor of :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:25 msgid "The arcs created from the input parameters::" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:0 msgid "type" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:36 msgid "Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``)." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:43 msgid "There is an alternative version (:class:`ArcPolygonFromArcs`) that is instantiated with pre-defined arcs." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:49 msgid "Examples" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:68 msgid "For further examples see :class:`ArcPolygonFromArcs`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:2 msgid "ArcPolygonFromArcs" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.ArcPolygonFromArcs``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:1 msgid "A generalized polygon allowing for points to be connected with arcs." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:3 msgid "This version takes in pre-defined arcs to generate the arcpolygon and introduces little new syntax. However unlike :class:`Polygon` it can't be created with points directly." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:7 msgid "For proper appearance the passed arcs should connect seamlessly: ``[a,b][b,c][c,a]``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:10 msgid "If there are any gaps between the arcs, those will be filled in with straight lines, which can be used deliberately for any straight sections. Arcs can also be passed as straight lines such as an arc initialized with ``angle=0``." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:15 msgid "These are the arcs from which the arcpolygon is assembled." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:16 msgid "Keyword arguments that are passed to the constructor of :class:`~.VMobject`. Affects how the ArcPolygon itself is drawn, but doesn't affect passed arcs." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:24 msgid "The arcs used to initialize the ArcPolygonFromArcs::" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:33 msgid "Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``)." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:40 msgid "There is an alternative version (:class:`ArcPolygon`) that can be instantiated with points." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:47 msgid "Examples" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:48 msgid "One example of an arcpolygon is the Reuleaux triangle. Instead of 3 straight lines connecting the outer points, a Reuleaux triangle has 3 arcs connecting those points, making a shape with constant width." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:53 msgid "Passed arcs are stored as submobjects in the arcpolygon. This means that the arcs are changed along with the arcpolygon, for example when it's shifted, and these arcs can be manipulated after the arcpolygon has been initialized." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:58 msgid "Also both the arcs contained in an :class:`~.ArcPolygonFromArcs`, as well as the arcpolygon itself are drawn, which affects draw time in :class:`~.Create` for example. In most cases the arcs themselves don't need to be drawn, in which case they can be passed as invisible." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:80 msgid "The arcpolygon itself can also be hidden so that instead only the contained arcs are drawn. This can be used to easily debug arcs or to highlight them." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Circle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:2 msgid "Circle" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Circle``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Arc`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:1 msgid "A circle." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:0 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:0 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:3 msgid "The color of the shape." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:4 msgid "Additional arguments to be passed to :class:`Arc`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:7 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:9 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1 msgid "Returns a circle passing through the specified three points." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:1 msgid "Returns the position of a point on the circle." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:1 msgid "Modifies a circle so that it surrounds a given mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:5 msgid "Example" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:3 msgid "The angle of the point along the circle in radians." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:5 msgid "The location of the point along the circle's circumference." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:3 msgid "The mobject that the circle will be surrounding." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:5 msgid "Scales the circle with respect to the mobject. A `buffer_factor` < 1 makes the circle smaller than the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.CubicBezier.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:2 msgid "CubicBezier" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.CubicBezier``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CubicBezier:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CubicBezier:2 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.CurvedArrow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:2 msgid "CurvedArrow" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.CurvedArrow``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CurvedArrow:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.ArcBetweenPoints`" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:2 msgid "CurvedDoubleArrow" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.CurvedDoubleArrow``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CurvedDoubleArrow:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.CurvedArrow`" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Dot.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:2 msgid "Dot" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Dot``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Circle`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:1 msgid "A circle with a very small radius." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:3 msgid "The location of the dot." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:4 msgid "The radius of the dot." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:5 msgid "The thickness of the outline of the dot." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:6 msgid "The opacity of the dot's fill_colour" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:7 msgid "The color of the dot." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:8 msgid "Additional arguments to be passed to :class:`Circle`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Ellipse.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:2 msgid "Ellipse" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Ellipse``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Circle`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:1 msgid "A circular shape; oval, circle." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:3 msgid "The horizontal width of the ellipse." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:4 msgid "The vertical height of the ellipse." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:5 msgid "Additional arguments to be passed to :class:`Circle`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.LabeledDot.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:2 msgid "LabeledDot" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.LabeledDot``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.Dot`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:1 msgid "A :class:`Dot` containing a label in its center." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:3 msgid "The label of the :class:`Dot`. This is rendered as :class:`~.MathTex` by default (i.e., when passing a :class:`str`), but other classes representing rendered strings like :class:`~.Text` or :class:`~.Tex` can be passed as well." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:7 msgid "The radius of the :class:`Dot`. If ``None`` (the default), the radius is calculated based on the size of the ``label``." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.Sector.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:2 msgid "Sector" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.Sector``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Sector:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.AnnularSector`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Sector:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.TipableVMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:2 msgid "TipableVMobject" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:4 msgid "Qualified name: ``manim.mobject.geometry.arc.TipableVMobject``" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:1 msgid "Meant for shared functionality between Arc and Line. Functionality can be classified broadly into these groups:" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:7 msgid "Adding, Creating, Modifying tips" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:5 msgid "add_tip calls create_tip, before pushing the new tip" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:6 msgid "into the TipableVMobject's list of submobjects" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:7 msgid "stylistic and positional configuration" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11 msgid "Checking for tips" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11 msgid "Boolean checks for whether the TipableVMobject has a tip" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11 msgid "and a starting tip" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15 msgid "Getters" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15 msgid "Straightforward accessors, returning information pertaining" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15 msgid "to the TipableVMobject instance's tip(s), its length etc" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1 msgid "Adds a tip to the TipableVMobject instance, recognising that the endpoints might need to be switched if it's a 'starting tip' or not." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.create_tip:1 msgid "Stylises the tip, positions it spatially, and returns the newly instantiated tip to the caller." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_end:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_start:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_tip:1 msgid "Returns the TipableVMobject instance's (first) tip, otherwise throws an exception." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_tips:1 msgid "Returns a VGroup (collection of VMobjects) containing the TipableVMObject instance's tips." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36::1 #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_unpositioned_tip:1 msgid "Returns a tip that has been stylistically configured, but has not yet been given a position in space." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:38 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.arc.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.arc.rst:2 msgid "arc" msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc:1 msgid "Mobjects that are curved." msgstr "" #: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc:4 #: ../../source/reference/manim.mobject.geometry.arc.rst:50::0 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A dot with bigger radius and bold stroke to annotate scenes." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::0 msgid "param inner_radius" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "The inside radius of the Annular Sector." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "Region between two concentric :class:`Circles <.Circle>`." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A circular arc." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "Inherits from Arc and additionally takes 2 points between which the arc is spanned." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A generalized polygon allowing for points to be connected with arcs." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A circle." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::0 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A circle with a very small radius." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A circular shape; oval, circle." msgstr "" #: ../../source/reference/manim.mobject.geometry.arc.rst:50::1 msgid "A :class:`Dot` containing a label in its center." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Difference.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:2 msgid "Difference" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:4 msgid "Qualified name: ``manim.mobject.geometry.boolean\\_ops.Difference``" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:1 msgid "Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:1 msgid "Subtracts one :class:`~.VMobject` from another one." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:3 msgid "The 1st :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:4 msgid "The 2nd :class:`~.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:7 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Exclusion.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:2 msgid "Exclusion" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:4 msgid "Qualified name: ``manim.mobject.geometry.boolean\\_ops.Exclusion``" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:1 msgid "Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:1 msgid "Find the XOR between two :class:`~.VMobject`. This creates a new :class:`~.VMobject` consisting of the region covered by exactly one of them." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:5 msgid "The 1st :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:6 msgid "The 2nd :class:`~.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:9 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Intersection.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:2 msgid "Intersection" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:4 msgid "Qualified name: ``manim.mobject.geometry.boolean\\_ops.Intersection``" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:1 msgid "Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:1 msgid "Find the intersection of two :class:`~.VMobject` s. This keeps the parts covered by both :class:`~.VMobject` s." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:4 msgid "The :class:`~.VMobject` to find the intersection." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:6 msgid "If less the 2 :class:`~.VMobject` are passed." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:9 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Union.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:2 msgid "Union" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:4 msgid "Qualified name: ``manim.mobject.geometry.boolean\\_ops.Union``" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:1 msgid "Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:1 msgid "Union of two or more :class:`~.VMobject` s. This returns the common region of the :class:`~VMobject` s." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:4 msgid "The :class:`~.VMobject` s to find the union of." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:6 msgid "If less than 2 :class:`~.VMobject` s are passed." msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:9 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:2 msgid "boolean\\_ops" msgstr "" #: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops:1 msgid "Boolean operations for two-dimensional mobjects." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26::1 msgid "Subtracts one :class:`~.VMobject` from another one." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26::1 msgid "Find the XOR between two :class:`~.VMobject`." msgstr "" #: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26::1 msgid "Find the intersection of two :class:`~.VMobject` s." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.Angle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:2 msgid "Angle" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.Angle``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:1 msgid "A circular arc or elbow-type mobject representing an angle of two lines." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:3 msgid "The first line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:4 msgid "The second line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:5 msgid "The radius of the :class:`Arc`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:6 msgid "A sequence of two :class:`int` numbers determining which of the 4 quadrants should be used. The first value indicates whether to anchor the arc on the first line closer to the end point (1) or start point (-1), and the second value functions similarly for the end (1) or start (-1) of the second line. Possibilities: (1,1), (-1,1), (1,-1), (-1,-1)." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:12 msgid "Toggles between the two possible angles defined by two points and an arc center. If set to False (default), the arc will always go counterclockwise from the point on line1 until the point on line2 is reached. If set to True, the angle will go clockwise from line1 to line2." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:15 msgid "Allows for a :class:`Dot` in the arc. Mainly used as an convention to indicate a right angle. The dot can be customized in the next three parameters." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:18 msgid "The radius of the :class:`Dot`. If not specified otherwise, this radius will be 1/10 of the arc radius." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:20 msgid "Relative distance from the center to the arc: 0 puts the dot in the center and 1 on the arc itself." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:22 msgid "The color of the :class:`Dot`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:24 msgid "Produces an elbow-type mobject indicating a right angle, see :class:`RightAngle` for more information and a shorthand." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:27 msgid "Further keyword arguments that are passed to the constructor of :class:`Arc` or :class:`Elbow`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:30 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:15 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:7 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:9 msgid "Examples" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:31 msgid "The first example shows some right angles with a dot in the middle while the second example shows all 8 possible angles defined by two lines." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1 msgid "The angle between the lines AB and BC." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:1 msgid "Get the lines forming an angle of the :class:`Angle` class." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:1 msgid "Get the value of an angle of the :class:`Angle` class." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Angle.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:3 msgid "This constructs the angle :math:`\\angle ABC`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:5 msgid "The endpoint of the first angle leg" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:6 msgid "The vertex of the angle" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:7 msgid "The endpoint of the second angle leg" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:8 msgid "Further keyword arguments are passed to :class:`.Angle`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:10 msgid "Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True)," msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:3 msgid "A :class:`~.VGroup` containing the lines that form the angle of the :class:`Angle` class." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:3 msgid "A boolean to decide the unit (deg/rad) in which the value of the angle is returned." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:5 msgid "The value in degrees/radians of an angle of the :class:`Angle` class." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.Arrow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:2 msgid "Arrow" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.Arrow``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:1 msgid "An arrow." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:3 msgid "Arguments to be passed to :class:`Line`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:5 msgid "The thickness of the arrow. Influenced by :attr:`max_stroke_width_to_length_ratio`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:7 msgid "The distance of the arrow from its start and end points." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:9 msgid ":attr:`tip_length` scales with the length of the arrow. Increasing this ratio raises the max value of :attr:`tip_length`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:11 msgid ":attr:`stroke_width` scales with the length of the arrow. Increasing this ratio ratios the max value of :attr:`stroke_width`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:13 msgid "Additional arguments to be passed to :class:`Line`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:17 msgid ":class:`ArrowTip` :class:`CurvedArrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:21 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:4 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:4 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.scale:8 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1 msgid "Returns the default tip_length of the arrow." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:1 msgid "Returns the normal of a vector." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.reset_normal_vector:1 msgid "Resets the normal of a vector" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.scale:1 msgid "Scale an arrow, but keep stroke width and arrow tip size fixed." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.DashedLine.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:2 msgid "DashedLine" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.DashedLine``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:1 msgid "A dashed :class:`Line`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:3 msgid "Arguments to be passed to :class:`Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:5 msgid "The length of each individual dash of the line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:7 msgid "The ratio of dash space to empty space. Range of 0-1." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:9 msgid "Additional arguments to be passed to :class:`Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:16 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:4 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_first_handle:4 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_last_handle:4 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_start:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1 msgid "Returns the end point of the line." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_first_handle:1 msgid "Returns the point of the first handle." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_last_handle:1 msgid "Returns the point of the last handle." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_start:1 msgid "Returns the start point of the line." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.DoubleArrow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:2 msgid "DoubleArrow" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.DoubleArrow``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Arrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:1 msgid "An arrow with tips on both ends." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:3 msgid "Arguments to be passed to :class:`Arrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:5 msgid "Additional arguments to be passed to :class:`Arrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:9 msgid ":class:`.~ArrowTip` :class:`.~CurvedDoubleArrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.Elbow.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:2 msgid "Elbow" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.Elbow``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:1 msgid "Two lines that create a right angle about each other: L-shape." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:3 msgid "The length of the elbow's sides." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:5 msgid "The rotation of the elbow." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:7 msgid "Additional arguments to be passed to :class:`~.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:12 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.Line.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:2 msgid "Line" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.Line``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line:1 msgid "Bases: :py:class:`manim.mobject.geometry.arc.TipableVMobject`" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:31::1 #: ../../source/reference/manim.mobject.geometry.line.Line.rst:31::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:31::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:1 msgid "Returns the projection of a point onto a line." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:31::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.put_start_and_end_on:1 msgid "Sets starts and end coordinates of a line." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Line.rst:33 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:3 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:3 msgid "Gets called upon creation. This is an empty method that can be implemented by subclasses." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.put_start_and_end_on:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:3 msgid "The point to which the line is projected." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.RightAngle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:2 msgid "RightAngle" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.RightAngle``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Angle`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:1 msgid "An elbow-type mobject representing a right angle between two lines." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:3 msgid "The first line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:4 msgid "The second line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:5 msgid "The length of the arms." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:6 msgid "Further keyword arguments that are passed to the constructor of :class:`Angle`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.TangentLine.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:2 msgid "TangentLine" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.TangentLine``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:1 msgid "Constructs a line tangent to a :class:`~.VMobject` at a specific point." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:3 msgid "The VMobject on which the tangent line is drawn." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:5 msgid "How far along the shape that the line will be constructed. range: 0-1." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:7 msgid "Length of the tangent line." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:9 msgid "The ``dx`` value" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:11 msgid "Additional arguments to be passed to :class:`Line`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:18 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.Vector.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.Vector.rst:2 msgid "Vector" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Vector.rst:4 msgid "Qualified name: ``manim.mobject.geometry.line.Vector``" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Arrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:1 msgid "A vector specialized for use in graphs." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:0 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:3 msgid "The direction of the arrow." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:5 msgid "The distance of the vector from its endpoints." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:7 msgid "Additional arguments to be passed to :class:`Arrow`" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:11 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:12 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Vector.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Vector.rst:20::1 #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1 msgid "Creates a label based on the coordinates of the vector." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.Vector.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:3 msgid "Whether or not to round the coordinates to integers." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:4 msgid "The number of dimensions of the vector." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:5 msgid "Sets the color of label, optional." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:6 msgid "Additional arguments to be passed to :class:`~.Matrix`." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:8 msgid "The label." msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.line.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.line.rst:2 msgid "line" msgstr "" #: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line:1 msgid "Mobjects that are lines or variations of them." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "A circular arc or elbow-type mobject representing an angle of two lines." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "An arrow." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "A dashed :class:`Line`." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "An arrow with tips on both ends." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "Two lines that create a right angle about each other: L-shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "An elbow-type mobject representing a right angle between two lines." msgstr "" #: ../../source/reference/manim.mobject.geometry.line.rst:36::1 msgid "Constructs a line tangent to a :class:`~.VMobject` at a specific point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Cutout.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:2 msgid "Cutout" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Cutout``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:1 msgid "A shape with smaller cutouts." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:3 msgid "The primary shape from which cutouts are made." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:5 msgid "The smaller shapes which are to be cut out of the ``main_shape``." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:7 msgid "Further keyword arguments that are passed to the constructor of :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:11 msgid "Technically, this class behaves similar to a symmetric difference: if parts of the ``mobjects`` are not located within the ``main_shape``, these parts will be added to the resulting :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:16 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Polygon.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:2 msgid "Polygon" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Polygon``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Polygram`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:1 msgid "A shape consisting of one closed loop of vertices." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:3 msgid "The vertices of the :class:`Polygon`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:4 msgid "Forwarded to the parent constructor." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Polygram.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:2 msgid "Polygram" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Polygram``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:1 msgid "A generalized :class:`Polygon`, allowing for disconnected sets of edges." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:0 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:3 msgid "The groups of vertices making up the :class:`Polygram`. The first vertex in each group is repeated to close the shape. Each point must be 3-dimensional: ``[x,y,z]``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:3 msgid "The groups of vertices making up the :class:`Polygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:5 msgid "The first vertex in each group is repeated to close the shape. Each point must be 3-dimensional: ``[x,y,z]``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:7 msgid "The color of the :class:`Polygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:8 msgid "Forwarded to the parent constructor." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:11 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:7 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:7 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22::1 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1 msgid "Gets the vertex groups of the :class:`Polygram`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22::1 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:1 msgid "Gets the vertices of the :class:`Polygram`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22::1 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:1 msgid "Rounds off the corners of the :class:`Polygram`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:0 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:3 msgid "The vertex groups of the :class:`Polygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:0 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:3 msgid "The vertices of the :class:`Polygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:3 msgid "The curvature of the corners of the :class:`Polygram`." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Rectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:2 msgid "Rectangle" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Rectangle``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Polygon`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:1 msgid "A quadrilateral with two sets of parallel sides." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:3 msgid "The color of the rectangle." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:5 msgid "The vertical height of the rectangle." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:7 msgid "The horizontal width of the rectangle." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:9 msgid "Space between vertical grid lines." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:11 msgid "Space between horizontal grid lines." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:13 #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:15 msgid "No purpose." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:17 msgid "Additional arguments to be passed to :class:`Polygon`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:21 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RegularPolygon.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:2 msgid "RegularPolygon" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.RegularPolygon``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.RegularPolygram`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:1 msgid "An n-sided regular :class:`Polygon`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:3 msgid "The number of sides of the :class:`RegularPolygon`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:4 msgid "Forwarded to the parent constructor." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RegularPolygram.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:2 msgid "RegularPolygram" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.RegularPolygram``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Polygram`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:1 msgid "A :class:`Polygram` with regularly spaced vertices." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:3 msgid "The number of vertices." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:4 msgid "The density of the :class:`RegularPolygram`. Can be thought of as how many vertices to hop to draw a line between them. Every ``density``-th vertex is connected." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:4 msgid "The density of the :class:`RegularPolygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:6 msgid "Can be thought of as how many vertices to hop to draw a line between them. Every ``density``-th vertex is connected." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:9 msgid "The radius of the circle that the vertices are placed on." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:10 msgid "The angle the vertices start at; the rotation of the :class:`RegularPolygram`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:12 msgid "Forwarded to the parent constructor." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:15 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RoundedRectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:2 msgid "RoundedRectangle" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.RoundedRectangle``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:1 msgid "A rectangle with rounded corners." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:3 msgid "The curvature of the corners of the rectangle." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:5 msgid "Additional arguments to be passed to :class:`Rectangle`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Square.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:2 msgid "Square" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Square``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:1 msgid "A rectangle with equal side lengths." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:3 msgid "The length of the sides of the square." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:5 msgid "Additional arguments to be passed to :class:`Rectangle`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Star.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:2 msgid "Star" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Star``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Polygon`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:1 msgid "A regular polygram without the intersecting lines." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:3 msgid "How many points on the :class:`Star`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:4 msgid "The radius of the circle that the outer vertices are placed on." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:5 msgid "The radius of the circle that the inner vertices are placed on. If unspecified, the inner radius will be calculated such that the edges of the :class:`Star` perfectly follow the edges of its :class:`RegularPolygram` counterpart." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:5 msgid "The radius of the circle that the inner vertices are placed on." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:7 msgid "If unspecified, the inner radius will be calculated such that the edges of the :class:`Star` perfectly follow the edges of its :class:`RegularPolygram` counterpart." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:11 msgid "The density of the :class:`Star`. Only used if ``inner_radius`` is unspecified. See :class:`RegularPolygram` for more information." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:11 msgid "The density of the :class:`Star`. Only used if ``inner_radius`` is unspecified." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:14 msgid "See :class:`RegularPolygram` for more information." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:15 msgid "The angle the vertices start at; the rotation of the :class:`Star`." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:17 msgid "Forwardeds to the parent constructor." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:19 msgid "If ``inner_radius`` is unspecified and ``density`` is not in the range ``[1, n/2)``." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:22 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Triangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:2 msgid "Triangle" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.polygram.Triangle``" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.RegularPolygon`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:1 msgid "An equilateral triangle." msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:3 msgid "Additional arguments to be passed to :class:`RegularPolygon`" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.polygram.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.polygram.rst:2 msgid "polygram" msgstr "" #: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram:1 msgid "Mobjects that are simple geometric shapes." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A shape with smaller cutouts." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A shape consisting of one closed loop of vertices." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A generalized :class:`Polygon`, allowing for disconnected sets of edges." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A quadrilateral with two sets of parallel sides." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "An n-sided regular :class:`Polygon`." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A :class:`Polygram` with regularly spaced vertices." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A rectangle with rounded corners." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A rectangle with equal side lengths." msgstr "" #: ../../source/reference/manim.mobject.geometry.polygram.rst:38::1 msgid "A regular polygram without the intersecting lines." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.rst:2 msgid "geometry" msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:1 msgid "Various geometric Mobjects." msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15::1 msgid "Mobjects that are curved." msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15::1 msgid "Boolean operations for two-dimensional mobjects." msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15::1 msgid "Mobjects that are lines or variations of them." msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15::1 msgid "Mobjects that are simple geometric shapes." msgstr "" #: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15::1 msgid "Mobjects used to mark and annotate other mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:2 msgid "BackgroundRectangle" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.shape\\_matchers.BackgroundRectangle``" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.shape_matchers.SurroundingRectangle`" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:1 msgid "A background rectangle. Its default color is the background color of the scene." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:5 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:22::1 #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1::1 #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:22::1 msgid "Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:0 #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:1 msgid "Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles)" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:4 msgid "The vmobject that will serve as a model." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:6 msgid "upper-bound." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:8 msgid "lower-bound" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:11 msgid "``self``" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.Cross.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:2 msgid "Cross" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:4 msgid "Qualified name: ``manim.mobject.geometry.shape\\_matchers.Cross``" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:1 msgid "Creates a cross." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:3 msgid "The mobject linked to this instance. It fits the mobject when specified. Defaults to None." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:4 msgid "Specifies the color of the cross lines. Defaults to RED." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:5 msgid "Specifies the width of the cross lines. Defaults to 6." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:6 msgid "Scales the cross to the provided units. Defaults to 1." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:2 msgid "SurroundingRectangle" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:4 msgid "Qualified name: ``manim.mobject.geometry.shape\\_matchers.SurroundingRectangle``" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.RoundedRectangle`" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:1 msgid "A rectangle surrounding a :class:`~.Mobject`" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.Underline.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:2 msgid "Underline" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:4 msgid "Qualified name: ``manim.mobject.geometry.shape\\_matchers.Underline``" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Line`" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:1 msgid "Creates an underline." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:3 msgid "The underline." msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:2 msgid "shape\\_matchers" msgstr "" #: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers:1 msgid "Mobjects used to mark and annotate other mobjects." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26::1 msgid "A background rectangle." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26::1 msgid "Creates a cross." msgstr "" #: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26::1 msgid "A rectangle surrounding a :class:`~.Mobject`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:2 msgid "ArrowCircleFilledTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowCircleFilledTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleFilledTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowCircleTip`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleFilledTip:1 msgid "Circular arrow tip with filled tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowCircleTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:2 msgid "ArrowCircleTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowCircleTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.arc.Circle`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleTip:1 msgid "Circular arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:2 msgid "ArrowSquareFilledTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowSquareFilledTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareFilledTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowSquareTip`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareFilledTip:1 msgid "Square arrow tip with filled tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowSquareTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:2 msgid "ArrowSquareTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowSquareTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.polygram.Square`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareTip:1 msgid "Square arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:2 msgid "ArrowTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:1 msgid "Base class for arrow tips." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:4 msgid ":class:`ArrowTriangleTip` :class:`ArrowTriangleFilledTip` :class:`ArrowCircleTip` :class:`ArrowCircleFilledTip` :class:`ArrowSquareTip` :class:`ArrowSquareFilledTip`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:12 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:6 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.length:4 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_angle:4 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_point:4 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.vector:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:13 msgid "Cannot be used directly, only intended for inheritance::" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:20 msgid "Instead, use one of the pre-defined ones, or make a custom one like this:" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:40 msgid "Using a class inherited from :class:`ArrowTip` to get a non-filled tip is a shorthand to manually specifying the arrow tip style as follows::" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:46 msgid "The following example illustrates the usage of all of the predefined arrow tips." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:21 msgid "Attributes" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1 msgid "The base point of the arrow tip." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.length:1 msgid "The length of the arrow tip." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_angle:1 msgid "The angle of the arrow tip." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_point:1 msgid "The tip point of the arrow tip." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.vector:1 msgid "The vector pointing from the base point to the tip point." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:2 msgid "ArrowTriangleFilledTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowTriangleFilledTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowTriangleTip`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:1 msgid "Triangular arrow tip with filled tip." msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:3 msgid "This is the default arrow tip shape." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTriangleTip.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:2 msgid "ArrowTriangleTip" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:4 msgid "Qualified name: ``manim.mobject.geometry.tips.ArrowTriangleTip``" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleTip:1 msgid "Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.polygram.Triangle`" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleTip:1 msgid "Triangular arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The base point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The length of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The angle of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The tip point of the arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37::1 msgid "The vector pointing from the base point to the tip point." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.geometry.tips.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.geometry.tips.rst:2 msgid "tips" msgstr "" #: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips:1 msgid "A collection of tip mobjects for use with :class:`~.TipableVMobject`." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Circular arrow tip with filled tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Circular arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Square arrow tip with filled tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Square arrow tip." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Base class for arrow tips." msgstr "" #: ../../source/reference/manim.mobject.geometry.tips.rst:32::1 msgid "Triangular arrow tip with filled tip." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graph.Graph.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graph.Graph.rst:2 msgid "Graph" msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:4 msgid "Qualified name: ``manim.mobject.graph.Graph``" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:1 msgid "An undirected graph (that is, a collection of vertices connected with edges)." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:3 msgid "Graphs can be instantiated by passing both a list of (distinct, hashable) vertex names, together with list of edges (as tuples of vertex names). See the examples below for details." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:9 msgid "This implementation uses updaters to make the edges move with the vertices." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:12 msgid "A list of vertices. Must be hashable elements." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:13 msgid "A list of edges, specified as tuples ``(u, v)`` where both ``u`` and ``v`` are vertices." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:15 msgid "Controls whether or not vertices are labeled. If ``False`` (the default), the vertices are not labeled; if ``True`` they are labeled using their names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively, custom labels can be specified by passing a dictionary whose keys are the vertices, and whose values are the corresponding vertex labels (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`)." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:21 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:10 msgid "Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:23 msgid "Either one of ``\"spring\"`` (the default), ``\"circular\"``, ``\"kamada_kawai\"``, ``\"planar\"``, ``\"random\"``, ``\"shell\"``, ``\"spectral\"``, ``\"spiral\"``, ``\"tree\"``, and ``\"partite\"`` for automatic vertex positioning using ``networkx`` (see `their documentation `_ for more details), or a dictionary specifying a coordinate (value) for each vertex (key) for manual positioning." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:29 msgid "Only for automatically generated layouts. A dictionary whose entries are passed as keyword arguments to the automatic layout algorithm specified via ``layout`` of``networkx``. The ``tree`` layout also accepts a special parameter ``vertex_spacing`` passed as a keyword argument inside the ``layout_config`` dictionary. Passing a tuple ``(space_x, space_y)`` as this argument overrides the value of ``layout_scale`` and ensures that vertices are arranged in a way such that the centers of siblings in the same layer are at least ``space_x`` units apart horizontally, and neighboring layers are spaced ``space_y`` units vertically." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:39 msgid "The scale of automatically generated layouts: the vertices will be arranged such that the coordinates are located within the interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)`` causing the first coordinate to be in the interval ``[-scale_x, scale_x]``, and the second in ``[-scale_y, scale_y]``. Default: 2." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:44 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:12 msgid "The mobject class used for displaying vertices in the scene." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:45 msgid "Either a dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``, or a dictionary whose keys are the vertices, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding vertex." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:49 msgid "A dictionary whose keys are the vertices, and whose values are mobjects to be used as vertices. Passing vertices here overrides all other configuration options for a vertex." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:52 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:6 msgid "The mobject class used for displaying edges in the scene." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:53 msgid "Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edges, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding edge." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:59 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:7 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:7 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:6 msgid "Examples" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:60 msgid "First, we create a small graph and demonstrate that the edges move together with the vertices." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:78 msgid "There are several automatic positioning algorithms to choose from:" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:99 msgid "Vertices can also be positioned manually:" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:112 msgid "The vertices in graphs can be labeled, and configurations for vertices and edges can be modified both by default and for specific vertices and edges." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:118 msgid "In ``edge_config``, edges can be passed in both directions: if ``(u, v)`` is an edge in the graph, both ``(u, v)`` as well as ``(v, u)`` can be used as keys in the dictionary." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:138 msgid "You can also lay out a partite graph on columns by specifying a list of the vertices on each side and choosing the partite layout." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:143 msgid "All vertices in your graph which are not listed in any of the partitions are collected in their own partition and rendered in the rightmost column." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:159 msgid "The representation of a linear artificial neural network is facilitated by the use of the partite layout and defining partitions for each layer." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:193 msgid "The custom tree layout can be used to show the graph by distance from the root vertex. You must pass the root vertex of the tree." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:219 msgid "The following code sample illustrates the use of the ``vertex_spacing`` layout parameter specific to the ``\"tree\"`` layout. As mentioned above, setting ``vertex_spacing`` overrides the specified value for ``layout_scale``, and as such it is harder to control the size of the mobject. However, we can adjust the captured frame and zoom out by using a :class:`.MovingCameraScene`::" msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1 msgid "Add new edges to the graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:1 msgid "Add a list of vertices to the graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:1 msgid "Change the layout of this graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:1 msgid "Build a :class:`~.Graph` from a given ``networkx`` graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:1 msgid "Remove several edges from the graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:25::1 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:1 msgid "Remove several vertices from the graph." msgstr "" #: ../../source/reference/manim.mobject.graph.Graph.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:3 msgid "Edges (as tuples of vertex identifiers) to be added. If a non-existing vertex is passed, a new vertex with default settings will be created. Create new vertices yourself beforehand to customize them." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:7 msgid "A dictionary either containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edge tuples, and whose values are dictionaries containing keyword arguments to be passed for the construction of the corresponding edge." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:12 msgid "Any further keyword arguments are passed to :meth:`.add_vertices` which is used to create new vertices in the passed edges." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0 #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:15 msgid "A group containing all newly added vertices and edges." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:3 msgid "Hashable vertex identifiers." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:4 msgid "A dictionary specifying the coordinates where the new vertices should be added. If ``None``, all vertices are created at the center of the graph." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:6 msgid "Controls whether or not the vertex is labeled. If ``False`` (the default), the vertex is not labeled; if ``True`` it is labeled using its names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively, any :class:`~.Mobject` can be passed to be used as the label." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:13 msgid "A dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:15 msgid "A dictionary whose keys are the vertex identifiers, and whose values are mobjects that should be used as vertices. Overrides all other vertex customization options." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:3 msgid "See the documentation of :class:`~.Graph` for details about the keyword arguments." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:3 msgid "A ``networkx`` graph." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:4 msgid "Keywords to be passed to the constructor of :class:`~.Graph`." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:3 msgid "Edges to be removed from the graph." msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:5 msgid "A group containing all removed edges." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graph.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graph.rst:2 msgid "graph" msgstr "" #: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph:1 msgid "Mobjects used to represent mathematical graphs (think graph theory, not plotting)." msgstr "" #: ../../source/reference/manim.mobject.graph.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.Axes.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:2 msgid "Axes" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.Axes``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`, :py:class:`manim.mobject.graphing.coordinate_systems.CoordinateSystem`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:1 msgid "Creates a set of axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:3 msgid "The ``(x_min, x_max, x_step)`` values of the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:4 msgid "The ``(y_min, y_max, y_step)`` values of the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:5 msgid "The length of the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:6 msgid "The length of the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:7 msgid "Arguments to be passed to :class:`~.NumberLine` that influences both axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:8 msgid "Arguments to be passed to :class:`~.NumberLine` that influence the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:9 msgid "Arguments to be passed to :class:`~.NumberLine` that influence the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:10 msgid "Whether or not to include the tips on both axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:11 msgid "Additional arguments to be passed to :class:`CoordinateSystem` and :class:`~.VGroup`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:14 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:16 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:21 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1 msgid "Accepts coordinates from the axes and returns a point with respect to the scene." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:1 msgid "Gets the axes." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:1 msgid "Draws a line graph." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:1 msgid "Accepts a point from the scene and returns its coordinates with respect to the axes." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:3 msgid "The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``. Also accepts a list of coordinates ``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )`` ``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:3 msgid "The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:5 msgid "Also accepts a list of coordinates" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:7 msgid "``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:9 msgid "``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:11 msgid "A point with respect to the scene's coordinate system. The shape of the array will be similar to the shape of the input." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:3 msgid "A pair of axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:3 msgid "The graph connects the vertices formed from zipping ``x_values``, ``y_values`` and ``z_values``. Also adds :class:`Dots <.Dot>` at the vertices if ``add_vertex_dots`` is set to ``True``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:7 msgid "Iterable of values along the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:8 msgid "Iterable of values along the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:9 msgid "Iterable of values (zeros if z_values is None) along the z-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:10 msgid "Color for the line graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:11 msgid "Whether or not to add :class:`~.Dot` at each vertex." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:12 msgid "Radius for the :class:`~.Dot` at each vertex." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:13 msgid "Style arguments to be passed into :class:`~.Dot` at each vertex." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:14 msgid "Additional arguments to be passed into :class:`~.VMobject`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:16 msgid "A VDict containing both the line and dots (if specified). The line can be accessed with: ``line_graph[\"line_graph\"]``. The dots can be accessed with: ``line_graph[\"vertex_dots\"]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:3 msgid "The point, i.e. ``RIGHT`` or ``[0, 1, 0]``. Also accepts a list of points as ``[RIGHT, [0, 1, 0]]``." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:2 msgid "ComplexPlane" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.ComplexPlane``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:1 msgid "Bases: :py:class:`manim.mobject.graphing.coordinate_systems.NumberPlane`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:1 msgid "A :class:`~.NumberPlane` specialized for use with complex numbers." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1 msgid "Adds the labels produced from :meth:`~.NumberPlane.get_coordinate_labels` to the plane." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:1 msgid "Generates the :class:`~.DecimalNumber` mobjects for the coordinates of the plane." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:1 msgid "Abbreviation for :meth:`number_to_point`." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:1 msgid "Accepts a float/complex number and returns the equivalent point on the plane." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:1 msgid "Abbreviation for :meth:`point_to_number`." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:1 msgid "Accepts a point and returns a complex number equivalent to that point on the plane." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:3 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:3 msgid "An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:4 msgid "Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:6 msgid "A :class:`~.VGroup` containing the positioned label mobjects." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:3 msgid "The number. Can be a float or a complex number." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:5 msgid "The point on the plane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:3 msgid "The point in manim's coordinate-system" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:2 msgid "CoordinateSystem" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.CoordinateSystem``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:1 msgid "Abstract base class for Axes and NumberPlane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:7 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:12 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:17 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:16 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:17 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:16 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:10 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:14 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:22 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:21 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:10 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:12 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:12 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:12 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:5 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:12 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:18 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:20 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:11 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:9 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:8 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:17 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:10 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:14 msgid "Methods" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 msgid "Adds labels to the axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:1 msgid "Returns the angle to the x-axis of the tangent to the plotted curve at a particular x-value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.c2p:1 msgid "Abbreviation for :meth:`coords_to_point`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:1 msgid "Creates a labelled triangle marker with a vertical line from the x-axis to a curve at a given x-value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:1 msgid "Returns a :class:`~.Polygon` representing the area under the graph passed." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:1 msgid "Defines labels for the x_axis and y_axis of the graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:1 msgid "Creates a properly positioned label for the passed graph, with an optional dot." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:1 msgid "A horizontal line from the y-axis to a given point in the scene." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:1 msgid "Returns a straight line from a given axis to a point in the scene." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:1 msgid "Generate both horizontal and vertical lines from the axis to a point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:1 msgid "Gets the origin of :class:`~.Axes`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:1 msgid "Generates a :class:`~.VGroup` of the Riemann Rectangles for a given curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:2 msgid "Creates two lines representing `dx` and `df`, the labels for `dx` and `df`, and" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:1 msgid "A vertical line from the x-axis to a given point in the scene." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:1 msgid "Obtains multiple lines from the x-axis to the curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:1 msgid "Generate an x-axis label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:1 msgid "Generate a y-axis label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:1 msgid "Alias for :meth:`input_to_graph_coords`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:1 msgid "Alias for :meth:`input_to_graph_point`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:1 msgid "Returns a tuple of the axis relative coordinates of the point on the graph based on the x-value given." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:1 msgid "Returns the coordinates of the point on a ``graph`` corresponding to an ``x`` value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.p2c:1 msgid "Abbreviation for :meth:`point_to_coords`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:1 msgid "Generates a curve based on a function." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:1 msgid "Plots an antiderivative graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:1 msgid "Returns the curve of the derivative of the passed graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:1 msgid "Creates the curves of an implicit function." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:1 msgid "A parametric curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:1 msgid "A polar graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:1 msgid "Generates a surface based on a function." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:1 msgid "Gets polar coordinates from a point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:1 msgid "Gets a point from polar coordinates." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:1 msgid "Abbreviation for :meth:`polar_to_point`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:1 msgid "Abbreviation for :meth:`point_to_polar`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:1 msgid "Returns the slope of the tangent to the plotted curve at a particular x-value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1 msgid "Adds labels to the axes. Use ``Axes.coordinate_labels`` to access the coordinates after creation." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:4 msgid "The numbers to be added to the axes. Use ``None`` to represent an axis with default labels." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:16 msgid "You can also specifically control the position and value of the labels using a dict." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:4 msgid "The x-value at which the tangent must touch the curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:5 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:5 msgid "The :class:`~.ParametricFunction` for which to calculate the tangent." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:6 msgid "The change in `x` used to determine the angle of the tangent to the curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:8 msgid "The angle of the tangent to the curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:4 msgid "The position along the curve at which the label, line and triangle will be constructed." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:5 msgid "The :class:`~.ParametricFunction` for which to construct the label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:6 msgid "The label of the vertical line and triangle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:7 msgid "The color of the label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:8 msgid "The size of the triangle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:9 msgid "The color of the triangle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:10 msgid "The function used to construct the vertical line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:11 msgid "The color of the vertical line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:13 msgid "A :class:`~.VGroup` of the label, triangle and vertical line mobjects." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:3 msgid "The graph/curve for which the area needs to be gotten." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:4 msgid "The range of the minimum and maximum x-values of the area. ``x_range = [x_min, x_max]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:5 msgid "The color of the area. Creates a gradient if a list of colors is provided." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:6 msgid "The opacity of the area." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:7 msgid "If a secondary :attr:`graph` is specified, encloses the area between the two curves." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:8 msgid "Additional parameters passed to :class:`~.Polygon`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:10 msgid "The :class:`~.Polygon` representing the area." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:13 msgid "When x_ranges do not match (either area x_range, graph's x_range or bounded_graph's x_range)." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:3 msgid "For increased control over the position of the labels, use :meth:`get_x_axis_label` and :meth:`get_y_axis_label`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:6 msgid "The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:7 msgid "The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:9 msgid "A :class:`~.Vgroup` of the labels for the x_axis and y_axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:13 msgid ":class:`get_x_axis_label` :class:`get_y_axis_label`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:3 msgid "The curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:4 msgid "The label for the function's curve. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:5 msgid "The x_value along the curve that positions the label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:6 msgid "The cartesian position, relative to the curve that the label will be at --> ``LEFT``, ``RIGHT``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:7 msgid "The distance between the curve and the label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:8 msgid "The color of the label. Defaults to the color of the curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:9 msgid "Whether to add a dot at the point on the graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:10 msgid "Additional parameters to be passed to :class:`~.Dot`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:12 msgid "The positioned label and :class:`~.Dot`, if applicable." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:3 msgid "The point to which the horizontal line will be drawn." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:4 msgid "Additional parameters to be passed to :class:`get_line_from_axis_to_point`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:6 msgid "A horizontal line from the y-axis to the point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:3 msgid "Specifies the axis from which to draw the line. `0 = x_axis`, `1 = y_axis`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:4 msgid "The point to which the line will be drawn." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:5 msgid "The function of the :class:`~.Line` mobject used to construct the line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:6 msgid "Optional arguments to passed to :attr:`line_func`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:7 msgid "The color of the line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:8 msgid "The stroke width of the line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:10 msgid "The line from an axis to a point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:14 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:10 msgid ":meth:`~.CoordinateSystem.get_vertical_line` :meth:`~.CoordinateSystem.get_horizontal_line`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:3 msgid "A point on the scene." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:4 msgid "Additional parameters to be passed to :meth:`get_line_from_axis_to_point`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:6 msgid "A :class:`~.VGroup` of the horizontal and vertical lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:3 msgid "The center point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:3 msgid "The graph whose area will be approximated by Riemann rectangles." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:4 msgid "The minimum and maximum x-values of the rectangles. ``x_range = [x_min, x_max]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:5 msgid "The change in x-value that separates each rectangle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:6 msgid "Can be any of ``\"left\"``, ``\"right\"`` or ``\"center\"``. Refers to where the sample point for the height of each Riemann Rectangle will be inside the segments of the partition." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:9 msgid "The stroke_width of the border of the rectangles." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:10 msgid "The color of the border of the rectangle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:11 msgid "The opacity of the rectangles." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:12 msgid "The colors of the rectangles. Creates a balanced gradient if multiple colors are passed." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:13 msgid "Indicates negative area when the curve dips below the x-axis by inverting its color." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:14 msgid "Sets the :attr:`stroke_color` to :attr:`fill_color`, blending the rectangles without clear separation." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:15 msgid "If a secondary graph is specified, encloses the area between the two curves." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:16 msgid "The factor by which the width of the rectangles is scaled." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:18 msgid "A :class:`~.VGroup` containing the Riemann Rectangles." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:2 msgid "the secant to the curve at a particular x-value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:4 msgid "The x-value at which the secant intersects the graph for the first time." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:5 msgid "The curve for which the secant will be found." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:6 msgid "The change in `x` after which the secant exits." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:7 msgid "The color of the line that indicates the change in `x`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:8 msgid "The color of the line that indicates the change in `y`. Defaults to the color of :attr:`graph`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:9 msgid "The label for the `dx` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:10 msgid "The label for the `dy` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:11 msgid "Whether to include the secant line in the graph, or just the df/dx lines and labels." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:13 msgid "The color of the secant line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:14 msgid "The length of the secant line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:16 msgid "A group containing the elements: `dx_line`, `df_line`, and if applicable also :attr:`dx_label`, :attr:`df_label`, `secant_line`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:3 msgid "The point to which the vertical line will be drawn." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:6 msgid "A vertical line from the x-axis to the point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:3 msgid "The graph along which the lines are placed." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:4 msgid "A list containing the lower and and upper bounds of the lines: ``x_range = [x_min, x_max]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:5 msgid "The number of evenly spaced lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:6 msgid "Additional arguments to be passed to :meth:`~.CoordinateSystem.get_vertical_line`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:8 msgid "The :class:`~.VGroup` of the evenly spaced lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:3 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:3 msgid "The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:4 msgid "The edge of the x-axis to which the label will be added, by default ``UR``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:5 msgid "Allows for further positioning of the label from an edge, by default ``UR``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:6 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:6 msgid "The distance of the label from the line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:8 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:8 msgid "The positioned label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:5 msgid "Allows for further positioning of the label from an edge, by default ``UR``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:3 msgid "The x-value of a point on the ``graph``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:4 msgid "The :class:`~.ParametricFunction` on which the point lies." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:6 msgid "The coordinates of the point on the :attr:`graph` corresponding to the :attr:`x` value." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:9 msgid "When the target x is not in the range of the line graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:3 msgid "The function used to construct the :class:`~.ParametricFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:4 msgid "The range of the curve along the axes. ``x_range = [x_min, x_max, x_step]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:5 msgid "Whether to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:7 msgid "Additional parameters to be passed to :class:`~.ParametricFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:9 msgid "The plotted curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:13 msgid "This method may not produce accurate graphs since Manim currently relies on interpolation between evenly-spaced samples of the curve, instead of intelligent plotting. See the example below for some solutions to this problem." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:3 msgid "The graph for which the antiderivative will be found." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:4 msgid "The y-value at which the graph intercepts the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:5 msgid "The number of points to take the area under the graph." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:6 msgid "Whether to use the vectorized version of the antiderivative. This means to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:9 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:5 msgid "Any valid keyword argument of :class:`~.ParametricFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:11 msgid "The curve of the antiderivative." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:15 msgid "This graph is plotted from the values of area under the reference graph. The result might not be ideal if the reference graph contains uncalculatable areas from x=0." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:3 msgid "The graph for which the derivative will be found." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:4 msgid "The color of the derivative curve." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:7 msgid "The curve of the derivative." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:3 msgid "The function to graph, in the form of f(x, y) = 0." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:4 msgid "The minimum depth of the function to calculate." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:5 msgid "The maximum number of quads to use." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:6 msgid "Additional parameters to pass into :class:`ImplicitFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:3 msgid "A parametric function mapping a number to a point in the coordinate system." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:5 msgid "Whether to pass in the generated t value array to the function. Only use this if your function supports it." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:6 msgid "Any further keyword arguments are passed to :class:`.ParametricFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:9 msgid "Example" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:3 msgid "The function r of theta." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:4 msgid "The range of theta as ``theta_range = [theta_min, theta_max, theta_step]``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:5 msgid "Additional parameters passed to :class:`~.ParametricFunction`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:3 msgid "The function used to construct the :class:`~.Surface`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:4 msgid "The range of the ``u`` variable: ``(u_min, u_max)``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:5 msgid "The range of the ``v`` variable: ``(v_min, v_max)``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:6 msgid "Colors of the surface. Passing a list of colors will color the surface by z-value. Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots where the color transitions." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:9 msgid "Defines the axis on which the colorscale is applied (0 = x, 1 = y, 2 = z), default is z-axis (2)." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:11 msgid "Additional parameters to be passed to :class:`~.Surface`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:13 msgid "The plotted surface." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:3 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:6 msgid "The point." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:5 msgid "The coordinate radius (:math:`r`) and the coordinate azimuth (:math:`\\theta`)." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:6 msgid "Tuple[:class:`float`, :class:`float`]" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:3 msgid "The coordinate radius (:math:`r`)." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:4 msgid "The coordinate azimuth (:math:`\\theta`)." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:2 msgid "NumberPlane" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.NumberPlane``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:1 msgid "Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:1 msgid "Creates a cartesian plane with background lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:3 msgid "The ``[x_min, x_max, x_step]`` values of the plane in the horizontal direction." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:4 msgid "The ``[y_min, y_max, y_step]`` values of the plane in the vertical direction." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:5 msgid "The width of the plane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:6 msgid "The height of the plane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:7 msgid "Arguments that influence the construction of the background lines of the plane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:8 msgid "Similar to :attr:`background_line_style`, affects the construction of the scene's background lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:9 msgid "Determines the number of boxes within the background lines: :code:`2` = 4 boxes, :code:`3` = 9 boxes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:10 msgid "Currently non-functional." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:11 msgid "Additional arguments to be passed to :class:`Axes`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:14 msgid "If :attr:`x_length` or :attr:`y_length` are not defined, they are automatically calculated such that one unit on each axis is one Manim unit long." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:18 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:23 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:2 msgid "PolarPlane" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.PolarPlane``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:1 msgid "Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:1 msgid "Creates a polar plane with background lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:3 msgid "The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default specified by ``azimuth_units``: - ``\"PI radians\"`` or ``\"TAU radians\"``: 20 - ``\"degrees\"``: 36 - ``\"gradians\"``: 40 - ``None``: 1 A non-integer value will result in a partial division at the end of the circle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:3 msgid "The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default specified by ``azimuth_units``:" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:6 msgid "``\"PI radians\"`` or ``\"TAU radians\"``: 20" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:7 msgid "``\"degrees\"``: 36" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:8 msgid "``\"gradians\"``: 40" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:9 msgid "``None``: 1" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:11 msgid "A non-integer value will result in a partial division at the end of the circle." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:12 msgid "The diameter of the plane." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:13 msgid "The distance between faded radius lines." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:14 msgid "The maximum value of the radius." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:15 msgid "Specifies a default labelling system for the azimuth. Choices are: - ``\"PI radians\"``: Fractional labels in the interval :math:`\\left[0, 2\\pi\\right]` with :math:`\\pi` as a constant. - ``\"TAU radians\"``: Fractional labels in the interval :math:`\\left[0, \\tau\\right]` (where :math:`\\tau = 2\\pi`) with :math:`\\tau` as a constant. - ``\"degrees\"``: Decimal labels in the interval :math:`\\left[0, 360\\right]` with a degree (:math:`^{\\circ}`) symbol. - ``\"gradians\"``: Decimal labels in the interval :math:`\\left[0, 400\\right]` with a superscript \"g\" (:math:`^{g}`). - ``None``: Decimal labels in the interval :math:`\\left[0, 1\\right]`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:15 msgid "Specifies a default labelling system for the azimuth. Choices are:" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:17 msgid "``\"PI radians\"``: Fractional labels in the interval :math:`\\left[0, 2\\pi\\right]` with :math:`\\pi` as a constant." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:18 msgid "``\"TAU radians\"``: Fractional labels in the interval :math:`\\left[0, \\tau\\right]` (where :math:`\\tau = 2\\pi`) with :math:`\\tau` as a constant." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:19 msgid "``\"degrees\"``: Decimal labels in the interval :math:`\\left[0, 360\\right]` with a degree (:math:`^{\\circ}`) symbol." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:20 msgid "``\"gradians\"``: Decimal labels in the interval :math:`\\left[0, 400\\right]` with a superscript \"g\" (:math:`^{g}`)." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:21 msgid "``None``: Decimal labels in the interval :math:`\\left[0, 1\\right]`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:22 msgid "If the ``azimuth_units`` choice has fractional labels, choose whether to combine the constant in a compact form :math:`\\tfrac{xu}{y}` as opposed to :math:`\\tfrac{x}{y}u`, where :math:`u` is the constant." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:25 msgid "The angle offset of the azimuth, expressed in radians." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:26 msgid "The direction of the azimuth. - ``\"CW\"``: Clockwise. - ``\"CCW\"``: Anti-clockwise." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:26 msgid "The direction of the azimuth." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:28 msgid "``\"CW\"``: Clockwise." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:29 msgid "``\"CCW\"``: Anti-clockwise." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:30 msgid "The buffer for the azimuth labels." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:31 msgid "The font size of the azimuth labels." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:32 msgid "The axis config for the radius." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:35 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1 msgid "Adds the coordinates." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:1 msgid "Gets the axes." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:1 msgid "Gets labels for the coordinates" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:3 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:3 msgid "Iterable of values along the radius, by default None." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:4 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:4 msgid "Iterable of values along the azimuth, by default None." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:3 msgid "A pair of axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:2 msgid "ThreeDAxes" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:4 msgid "Qualified name: ``manim.mobject.graphing.coordinate\\_systems.ThreeDAxes``" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:1 msgid "Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:1 msgid "A 3-dimensional set of axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:0 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:3 msgid "The ``[x_min, x_max, x_step]`` values of the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:4 msgid "The ``[y_min, y_max, y_step]`` values of the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:5 msgid "The ``[z_min, z_max, z_step]`` values of the z-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:6 msgid "The length of the x-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:7 msgid "The length of the y-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:8 msgid "The length of the z-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:9 msgid "Arguments to be passed to :class:`~.NumberLine` that influence the z-axis." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:10 msgid "The direction of the normal." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:11 msgid "The number of pieces used to construct the axes." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:12 msgid "The direction of the light source." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:13 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:14 msgid "Currently non-functional." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:15 msgid "Additional arguments to be passed to :class:`Axes`." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:20::1 #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1 msgid "Generate a z-axis label." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:3 msgid "The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:4 msgid "The edge of the x-axis to which the label will be added, by default ``UR``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:5 msgid "Allows for further positioning of the label from an edge, by default ``UR``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:6 msgid "The distance of the label from the line." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:7 msgid "The angle at which to rotate the label, by default ``PI/2``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:8 msgid "The axis about which to rotate the label, by default ``RIGHT``." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:10 msgid "The positioned label." msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:2 msgid "coordinate\\_systems" msgstr "" #: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems:1 msgid "Mobjects that represent coordinate systems." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30::1 msgid "Creates a set of axes." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30::1 msgid "A :class:`~.NumberPlane` specialized for use with complex numbers." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30::1 msgid "Abstract base class for Axes and NumberPlane." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30::1 msgid "Creates a cartesian plane with background lines." msgstr "" #: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30::1 msgid "Creates a polar plane with background lines." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.functions.FunctionGraph.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:2 msgid "FunctionGraph" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:4 msgid "Qualified name: ``manim.mobject.graphing.functions.FunctionGraph``" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:1 msgid "Bases: :py:class:`manim.mobject.graphing.functions.ParametricFunction`" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:1 msgid "A :class:`ParametricFunction` that spans the length of the scene by default." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:23 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.functions.ImplicitFunction.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:2 msgid "ImplicitFunction" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:4 msgid "Qualified name: ``manim.mobject.graphing.functions.ImplicitFunction``" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:1 msgid "An implicit function." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:3 msgid "The implicit function in the form ``f(x, y) = 0``." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:4 msgid "The x min and max of the function." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:5 msgid "The y min and max of the function." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:6 msgid "The minimum depth of the function to calculate." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:7 msgid "The maximum number of quads to use." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:8 msgid "Whether or not to smoothen the curves." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:9 msgid "Additional parameters to pass into :class:`VMobject`" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:12 msgid "A small ``min_depth`` :math:`d` means that some small details might be ignored if they don't cross an edge of one of the :math:`4^d` uniform quads." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:16 msgid "The value of ``max_quads`` strongly corresponds to the quality of the curve, but a higher number of quads may take longer to render." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:21 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:21::1 #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:21::1 #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1 #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.functions.ParametricFunction.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:2 msgid "ParametricFunction" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:4 msgid "Qualified name: ``manim.mobject.graphing.functions.ParametricFunction``" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:1 msgid "A parametric curve." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:3 msgid "The function to be plotted in the form of ``(lambda x: x**2)``" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:4 msgid "Determines the length that the function spans. By default ``[0, 1]``" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:5 msgid "Scaling class applied to the points of the function. Default of :class:`~.LinearBase`." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:6 msgid "Whether to interpolate between the points of the function after they have been created. (Will have odd behaviour with a low number of points)" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:8 msgid "Whether to pass in the generated t value array to the function as ``[t_0, t_1, ...]``. Only use this if your function supports it. Output should be a numpy array of shape ``[[x_0, x_1, ...], [y_0, y_1, ...], [z_0, z_1, ...]]`` but ``z`` can also be 0 if the Axes is 2D" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:12 msgid "Values of t at which the function experiences discontinuity." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:13 msgid "The left and right tolerance for the discontinuities." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:16 msgid "Examples" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:46 msgid "If your function has discontinuities, you'll have to specify the location of the discontinuities manually. See the following example for guidance." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:23::1 #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:23::1 #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1 #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.functions.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.functions.rst:2 msgid "functions" msgstr "" #: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions:1 msgid "Mobjects representing function graphs." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.rst:24::1 msgid "A :class:`ParametricFunction` that spans the length of the scene by default." msgstr "" #: ../../source/reference/manim.mobject.graphing.functions.rst:24::1 msgid "An implicit function." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.number_line.NumberLine.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:2 msgid "NumberLine" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:4 msgid "Qualified name: ``manim.mobject.graphing.number\\_line.NumberLine``" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:1 msgid "Bases: :py:class:`manim.mobject.geometry.line.Line`" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:1 msgid "Creates a number line with tick marks." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:3 msgid "The ``[x_min, x_max, x_step]`` values to create the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:4 msgid "The length of the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:5 msgid "The distance between each tick of the line. Overwritten by :attr:`length`, if specified." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:6 msgid "Whether to include ticks on the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:7 msgid "The length of each tick mark." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:8 msgid "An iterable of specific values with elongated ticks." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:9 msgid "Influences how many times larger elongated ticks are than regular ticks (2 = 2x)." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:10 msgid "The angle (in radians) at which the line is rotated." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:11 msgid "The thickness of the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:12 msgid "Whether to add a tip to the end of the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:13 msgid "The width of the tip." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:14 msgid "The height of the tip." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:15 msgid "Whether to add numbers to the tick marks. The number of decimal places is determined by the step size, this default can be overridden by ``decimal_number_config``." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:17 msgid "The way the ``x_range`` is value is scaled, i.e. :class:`~.LogBase` for a logarithmic numberline. Defaults to :class:`~.LinearBase`." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:18 msgid "The size of the label mobjects. Defaults to 36." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:19 msgid "The specific position to which label mobjects are added on the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:20 msgid "Determines the mobject class that will be used to construct the labels of the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:21 msgid "The distance between the line and the label mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:22 msgid "Arguments that can be passed to :class:`~.numbers.DecimalNumber` to influence number mobjects." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:23 msgid "An explicit iterable of numbers to not be added to the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:24 msgid "An explicit iterable of numbers to add to the number line" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:25 msgid "Additional arguments to be passed to :class:`~.Line`." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:29 msgid "Number ranges that include both negative and positive values will be generated from the 0 point, and may not include a tick at the min / max values as the tick locations are dependent on the step size." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:34 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:10 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:10 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 msgid "Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 msgid "Adds :class:`~.DecimalNumber` mobjects representing their position at each tick of the number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 msgid "Adds ticks to the number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:1 msgid "Generates a positioned :class:`~.DecimalNumber` mobject generated according to ``label_constructor``." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:1 msgid "Generates a tick and positions it along the number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:1 msgid "Generates the range of values on which labels are plotted based on the ``x_range`` attribute of the number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:1 msgid "Abbreviation for :meth:`~.NumberLine.number_to_point`." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:1 msgid "Accepts a value along the number line and returns a point with respect to the scene." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:1 msgid "Abbreviation for :meth:`~.NumberLine.point_to_number`." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36::1 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:1 msgid "Accepts a point with respect to the scene and returns a float along the number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:38 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1 msgid "Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``. The labels can be accessed after creation via ``self.labels``." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:4 msgid "A dictionary consisting of the position along the number line and the mobject to be added: ``{1: Tex(\"Monday\"), 3: Tex(\"Tuesday\")}``. :attr:`label_constructor` will be used to construct the labels if the value is not a mobject (``str`` or ``float``)." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:7 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:5 msgid "Determines the direction at which the label is positioned next to the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:8 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:6 msgid "The distance of the label from the line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:9 msgid "The font size of the mobject to be positioned." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:10 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:10 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:8 msgid "The :class:`~.VMobject` class that will be used to construct the label. Defaults to the ``label_constructor`` attribute of the number line if not specified." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:14 msgid "If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:1 msgid "Adds :class:`~.DecimalNumber` mobjects representing their position at each tick of the number line. The numbers can be accessed after creation via ``self.numbers``." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:5 msgid "An iterable of the values used to position and create the labels. Defaults to the output produced by :meth:`~.NumberLine.get_tick_range`" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:7 msgid "A list of values to exclude from :attr:`x_values`." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:8 msgid "The font size of the labels. Defaults to the ``font_size`` attribute of the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_ticks:1 msgid "Adds ticks to the number line. Ticks can be accessed after creation via ``self.ticks``." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:4 msgid "The x-value at which the mobject should be positioned." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:7 msgid "The font size of the label mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:12 msgid "The positioned mobject." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:0 #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:3 msgid "The position of the tick." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:4 msgid "The factor by which the tick is scaled." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:6 msgid "A positioned tick." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:4 msgid "A numpy array of floats represnting values along the number line." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:4 msgid "The value to be transformed into a coordinate. Or a list of values." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:6 msgid "A point with respect to the scene's coordinate system. Or a list of points." msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:4 msgid "A sequence of values consisting of ``(x_coord, y_coord, z_coord)``." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.number_line.UnitInterval.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:2 msgid "UnitInterval" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:4 msgid "Qualified name: ``manim.mobject.graphing.number\\_line.UnitInterval``" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.UnitInterval:1 msgid "Bases: :py:class:`manim.mobject.graphing.number_line.NumberLine`" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.number_line.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.number_line.rst:2 msgid "number\\_line" msgstr "" #: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line:1 msgid "Mobject representing a number line." msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.graphing.number_line.rst:22::1 msgid "Creates a number line with tick marks." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.rst:2 msgid "graphing" msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:1 msgid "Coordinate systems and function graphing related mobjects." msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14::1 msgid "Mobjects that represent coordinate systems." msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14::1 msgid "Mobjects representing function graphs." msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14::1 msgid "Mobject representing a number line." msgstr "" #: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14::1 msgid "Mobjects representing objects from probability theory and statistics." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.probability.BarChart.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:2 msgid "BarChart" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:4 msgid "Qualified name: ``manim.mobject.graphing.probability.BarChart``" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:1 msgid "Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:1 msgid "Creates a bar chart. Inherits from :class:`~.Axes`, so it shares its methods and attributes. Each axis inherits from :class:`~.NumberLine`, so pass in ``x_axis_config``/``y_axis_config`` to control their attributes." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:0 #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:0 #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:5 msgid "A sequence of values that determines the height of each bar. Accepts negative values." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:6 msgid "A sequence of names for each bar. Does not have to match the length of ``values``." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:7 msgid "The y_axis range of values. If ``None``, the range will be calculated based on the min/max of ``values`` and the step will be calculated based on ``y_length``." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:9 msgid "The length of the x-axis. If ``None``, it is automatically calculated based on the number of values and the width of the screen." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:11 msgid "The length of the y-axis." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:12 msgid "The color for the bars. Accepts a sequence of colors (can contain just one item). If the length of``bar_colors`` does not match that of ``values``, intermediate colors will be automatically determined." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:15 msgid "The length of a bar. Must be between 0 and 1." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:16 msgid "The fill opacity of the bars." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:17 msgid "The stroke width of the bars." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:20 #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:8 #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:10 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:21::1 #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1 msgid "Updates the height of the bars of the chart." msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:21::1 msgid "Annotates each bar with its corresponding value." msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:3 msgid "The values that will be used to update the height of the bars. Does not have to match the number of bars." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:5 msgid "Whether to re-initalize the colors of the bars based on ``self.bar_colors``." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:1 msgid "Annotates each bar with its corresponding value. Use ``self.bar_labels`` to access the labels after creation." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:4 msgid "The color of each label. By default ``None`` and is based on the parent's bar color." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:5 msgid "The font size of each label." msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:6 msgid "The distance from each label to its bar. By default 0.4." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.probability.SampleSpace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:2 msgid "SampleSpace" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:4 msgid "Qualified name: ``manim.mobject.graphing.probability.SampleSpace``" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.SampleSpace:1 msgid "Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.SampleSpace:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:34 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.probability.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.probability.rst:2 msgid "probability" msgstr "" #: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability:1 msgid "Mobjects representing objects from probability theory and statistics." msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.graphing.probability.rst:22::1 msgid "Creates a bar chart." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.scale.LinearBase.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:2 msgid "LinearBase" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:4 msgid "Qualified name: ``manim.mobject.graphing.scale.LinearBase``" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:1 msgid "Bases: :py:class:`manim.mobject.graphing.scale._ScaleBase`" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:1 msgid "The default scaling class." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:3 msgid "The slope of the linear function, by default 1.0" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:14 msgid "Methods" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1::1 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1 msgid "Multiplies the value by the scale factor." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1::1 msgid "Inverse of function." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:3 msgid "Value to be multiplied by the scale factor." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:1 msgid "Inverse of function. Divides the value by the scale factor." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.scale.LogBase.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:2 msgid "LogBase" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:4 msgid "Qualified name: ``manim.mobject.graphing.scale.LogBase``" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:1 msgid "Bases: :py:class:`manim.mobject.graphing.scale._ScaleBase`" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:1 msgid "Scale for logarithmic graphs/functions." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.inverse_function:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:3 msgid "The base of the log, by default 10." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:4 msgid "For use with :class:`~.Axes`: Whetherer or not to include ``LaTeX`` axis labels, by default True." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:14 msgid "Methods" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1::1 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1 msgid "Scales the value to fit it to a logarithmic scale.``self.function(5)==10**5``" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1::1 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:1 msgid "Produces custom :class:`~.Integer` labels in the form of ``10^2``." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1::1 msgid "Inverse of ``function``." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:0 #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.inverse_function:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:3 msgid "The iterable of values used to create the labels. Determines the exponent." msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:4 msgid "The number of decimal places to include in the exponent" msgstr "" #: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:5 msgid "Additional arguments to be passed to :class:`~.Integer`." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.graphing.scale.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.graphing.scale.rst:2 msgid "scale" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.graphing.scale.rst:22::1 msgid "The default scaling class." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.logo.ManimBanner.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:2 msgid "ManimBanner" msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:4 msgid "Qualified name: ``manim.mobject.logo.ManimBanner``" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:1 msgid "Convenience class representing Manim's banner." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:3 msgid "Can be animated using custom methods." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:5 msgid "If ``True`` (the default), the dark theme version of the logo (with light text font) will be rendered. Otherwise, if ``False``, the light theme version (with dark text font) is used." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:10 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:23 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22::1 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1 msgid "The creation animation for Manim's logo." msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22::1 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:1 msgid "An animation that expands Manim's logo into its banner." msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22::1 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:1 msgid "Scale the banner by the specified scale factor." msgstr "" #: ../../source/reference/manim.mobject.logo.ManimBanner.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:3 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:16 msgid "The run time of the animation." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:5 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:19 msgid "An animation to be used in a :meth:`.Scene.play` call." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0 #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:3 msgid "The returned animation transforms the banner from its initial state (representing Manim's logo with just the icons) to its expanded state (showing the full name together with the icons)." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:7 msgid "See the class documentation for how to use this." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:11 msgid "Before calling this method, the text \"anim\" is not a submobject of the banner object. After the expansion, it is added as a submobject so subsequent animations to the banner object apply to the text \"anim\" as well." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:17 msgid "The direction in which the logo is expanded." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:3 msgid "The factor used for scaling the banner." msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:5 msgid "The scaled banner." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.logo.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.logo.rst:2 msgid "logo" msgstr "" #: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo:1 msgid "Utilities for Manim's logo and banner." msgstr "" #: ../../source/reference/manim.mobject.logo.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.matrix.DecimalMatrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:2 msgid "DecimalMatrix" msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:4 msgid "Qualified name: ``manim.mobject.matrix.DecimalMatrix``" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:1 msgid "Bases: :py:class:`manim.mobject.matrix.Matrix`" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:1 msgid "A mobject that displays a matrix with decimal entries on the screen." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:17 msgid "Will round/truncate the decimal places as per the provided config." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:19 msgid "A numpy 2d array or list of lists" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:21 msgid "Mobject to use, by default DecimalNumber" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:23 msgid "Config for the desired mobject, by default {\"num_decimal_places\": 1}" msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.matrix.IntegerMatrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:2 msgid "IntegerMatrix" msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:4 msgid "Qualified name: ``manim.mobject.matrix.IntegerMatrix``" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:1 msgid "Bases: :py:class:`manim.mobject.matrix.Matrix`" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:1 msgid "A mobject that displays a matrix with integer entries on the screen." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:16 msgid "Will round if there are decimal entries in the matrix." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:18 msgid "A numpy 2d array or list of lists" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:20 msgid "Mobject to use, by default Integer" msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.matrix.Matrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:2 msgid "Matrix" msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:4 msgid "Qualified name: ``manim.mobject.matrix.Matrix``" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:1 msgid "A mobject that displays a matrix on the screen." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:7 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:7 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:7 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:7 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:10 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:10 msgid "Examples" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:5 msgid "The first example shows a variety of uses of this module while the second example exlpains the use of the options `add_background_rectangles_to_entries` and `include_background_rectangle`." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:56 msgid "A numpy 2d array or list of lists." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:57 msgid "Vertical distance between elements, by default 0.8." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:58 msgid "Horizontal distance between elements, by default 1.3." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:59 msgid "Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:60 msgid "Height of the brackets, by default ``MED_SMALL_BUFF``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:61 msgid "``True`` if should add backgraound rectangles to entries, by default ``False``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:62 msgid "``True`` if should include background rectangle, by default ``False``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:63 msgid "The mobject class used to construct the elements, by default :class:`~.MathTex`." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:64 msgid "Additional arguments to be passed to the constructor in ``element_to_mobject``, by default ``{}``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:66 msgid "The corner to which elements are aligned, by default ``DR``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:67 msgid "The left bracket type, by default ``\"[\"``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:68 msgid "The right bracket type, by default ``\"]\"``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:69 msgid "``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:70 msgid "Additional arguments to be passed to :class:`~.MathTex` when constructing the brackets." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1 msgid "Add a black background rectangle to the matrix, see above for an example." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:1 msgid "Return the bracket mobjects." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:1 msgid "Return columns of the matrix as VGroups." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:1 msgid "Return the individual entries of the matrix." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:1 msgid "Return the underlying mob matrix mobjects." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:1 msgid "Return rows of the matrix as VGroups." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:1 msgid "Set individual colors for each columns of the matrix." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:27::1 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:1 msgid "Set individual colors for each row of the matrix." msgstr "" #: ../../source/reference/manim.mobject.matrix.Matrix.rst:29 msgid "Attributes" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:6 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:6 msgid "The current matrix object (self)." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:3 msgid "Each VGroup contains a bracket" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:4 msgid "List[:class:`~.VGroup`]" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:3 msgid "Each VGroup contains a column of the matrix." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:3 msgid "VGroup containing entries of the matrix." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:3 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:3 msgid "Each VGroup contains a row of the matrix." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:3 msgid "The list of colors; each color specified corresponds to a column." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.matrix.MobjectMatrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:2 msgid "MobjectMatrix" msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:4 msgid "Qualified name: ``manim.mobject.matrix.MobjectMatrix``" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:1 msgid "Bases: :py:class:`manim.mobject.matrix.Matrix`" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:1 msgid "A mobject that displays a matrix of mobject entries on the screen." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:17 msgid "A numpy 2d array or list of lists." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:18 msgid "Vertical distance between elements, by default 0.8." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:19 msgid "Horizontal distance between elements, by default 1.3." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:20 msgid "Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:21 msgid "Height of the brackets, by default ``MED_SMALL_BUFF``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:22 msgid "``True`` if should add backgraound rectangles to entries, by default ``False``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:23 msgid "``True`` if should include background rectangle, by default ``False``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:24 msgid "The mobject class used to construct the elements, by default :class:`~.MathTex`." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:25 msgid "Additional arguments to be passed to the constructor in ``element_to_mobject``, by default ``{}``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:27 msgid "The corner to which elements are aligned, by default ``DR``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:28 msgid "The left bracket type, by default ``\"[\"``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:29 msgid "The right bracket type, by default ``\"]\"``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:30 msgid "``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:31 msgid "Additional arguments to be passed to :class:`~.MathTex` when constructing the brackets." msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.matrix.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.matrix.rst:2 msgid "matrix" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix:1 msgid "Mobjects representing matrices." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix:4 #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:16 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:32::1 msgid "A mobject that displays a matrix with decimal entries on the screen." msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:32::1 msgid "A mobject that displays a matrix with integer entries on the screen." msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:32::1 msgid "A mobject that displays a matrix on the screen." msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:32::1 msgid "A mobject that displays a matrix of mobject entries on the screen." msgstr "" #: ../../source/reference/manim.mobject.matrix.rst:35 msgid "Functions" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:1 msgid "Helper function to create determinant." msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:3 msgid "The matrix whose determinant is to be created" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:5 msgid "The value of the determinant of the matrix" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:7 msgid "The background rectangle" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:9 msgid "The scale of the text `det` w.r.t the matrix" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:12 msgid "A VGroup containing the determinant" msgstr "" #: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.mobject.Group.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.mobject.Group.rst:2 msgid "Group" msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:4 msgid "Qualified name: ``manim.mobject.mobject.Group``" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:1 msgid "Bases: :py:class:`manim.mobject.mobject.Mobject`" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:1 msgid "Groups together multiple :class:`Mobjects <.Mobject>`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:4 msgid "Notes" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:5 msgid "When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group." msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:28::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:28::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.mobject.Group.rst:28::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.mobject.Mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:2 msgid "Mobject" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:4 msgid "Qualified name: ``manim.mobject.mobject.Mobject``" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:1 msgid "Mathematical Object: base class for objects that can be displayed on screen." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:3 msgid "There is a compatibility layer that allows for getting and setting generic attributes with ``get_*`` and ``set_*`` methods. See :meth:`set` for more details." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:9 msgid "The contained objects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:0 msgid "type" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:11 msgid "List[:class:`Mobject`]" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:15 msgid "The points of the objects." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1 msgid "Add mobjects as submobjects." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:1 msgid "Add an animation override." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:1 msgid "Add a BackgroundRectangle as submobject." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:1 msgid "Add all passed mobjects to the back of the submobjects." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:1 msgid "Add an update function to this mobject." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:1 msgid "Aligns the data of this mobject with another mobject." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_on_border:1 msgid "Direction just needs to be a vector pointing towards side or corner in the 2d plane." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:1 msgid "Aligns mobject to another :class:`~.Mobject` in a certain direction." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:1 msgid "Returns the function defining a specific animation override for this class." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Applies a complex function to a :class:`Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:1 msgid "Apply a function to ``self`` and every submobject with points recursively." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:1 msgid "Sorts :class:`~.Mobject` next to each other on screen." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:1 msgid "Arrange submobjects in a grid." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_submobjects:1 msgid "Arrange the position of :attr:`submobjects` with a small buffer." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:1 msgid "Edit points, colors and submobjects to be identical to another :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:1 msgid "Remove every updater." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:1 msgid "Create and return an identical copy of the :class:`Mobject` including all :attr:`submobjects`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.flip:1 msgid "Flips/Mirrors an mobject about its center." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_bottom:1 msgid "Get bottom coordinates of a box bounding the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_center:1 msgid "Get center coordinates" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_color:1 msgid "Returns the color of the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_coord:1 msgid "Meant to generalize ``get_x``, ``get_y`` and ``get_z``" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_corner:1 msgid "Get corner coordinates for certain direction." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Picture a box bounding the :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_edge_center:1 msgid "Get edge coordinates for certain direction." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_end:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_left:1 msgid "Get left coordinates of a box bounding the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:1 msgid "Get coordinates of the middle of the path that forms the :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_nadir:1 msgid "Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_right:1 msgid "Get right coordinates of a box bounding the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_start:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_start_and_end:1 msgid "Returns starting and ending point of a stroke as a ``tuple``." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:1 msgid "Return all updaters using the ``dt`` parameter." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_top:1 msgid "Get top coordinates of a box bounding the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:1 msgid "Return all updaters." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_x:1 msgid "Returns x coordinate of the center of the :class:`~.Mobject` as ``float``" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_y:1 msgid "Returns y coordinate of the center of the :class:`~.Mobject` as ``float``" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_z:1 msgid "Returns z coordinate of the center of the :class:`~.Mobject` as ``float``" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_zenith:1 msgid "Get zenith coordinates of a box bounding a 3D :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_no_points:1 msgid "Check if :class:`~.Mobject` *does not* contains points." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_points:1 msgid "Check if :class:`~.Mobject` contains points." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:1 msgid "Test if ``self`` has a time based updater." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.init_colors:1 msgid "Initializes the colors." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:1 msgid "Inserts a mobject at a specific position into self.submobjects" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.interpolate:1 msgid "Turns this :class:`~.Mobject` into an interpolation between ``mobject1`` and ``mobject2``." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:1 msgid "Inverts the list of :attr:`submobjects`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.length_over_dim:1 msgid "Measure the length of an :class:`~.Mobject` in a certain direction." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_color:1 msgid "Match the color with the color of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_coord:1 msgid "Match the coordinates with the coordinates of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_depth:1 msgid "Match the depth with the depth of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_dim_size:1 msgid "Match the specified dimension with the dimension of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_height:1 msgid "Match the height with the height of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:1 msgid "Edit points, positions, and submobjects to be identical to another :class:`~.Mobject`, while keeping the style unchanged." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:1 msgid "Match the updaters of the given mobject." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_width:1 msgid "Match the width with the width of another :class:`~.Mobject`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Match x coord." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Match y coord." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Match z coord." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.move_to:1 msgid "Move center of the :class:`~.Mobject` to certain coordinate." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.next_to:1 msgid "Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or coordinate." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:1 msgid "If a :class:`~.Mobject` with points is being aligned to one without, treat both as groups, and push the one with points into its own submobjects list." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:1 msgid "Remove :attr:`submobjects`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:1 msgid "Remove an updater." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.repeat:1 msgid "This can make transition animations nicer" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.reset_points:1 msgid "Sets :attr:`points` to be an empty array." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.restore:1 msgid "Restores the state that was previously saved with :meth:`~.Mobject.save_state`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:1 msgid "Enable updating from updaters and animations." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate:1 msgid "Rotates the :class:`~.Mobject` about a certain point." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate_about_origin:1 msgid "Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.save_image:1 msgid "Saves an image of only this :class:`Mobject` at its position to a png file." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Save the current state (position, color & size)." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:1 msgid "Scale the size by a factor." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_depth:1 msgid "Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:1 msgid "Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:1 msgid "Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:1 msgid "Sets attributes." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 msgid "Condition is function which takes in one arguments, (x, y, z)." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:1 msgid "Sets the default values of keyword arguments." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_x:1 msgid "Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_y:1 msgid "Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z:1 msgid "Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:1 msgid "Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:1 msgid "Sets the :class:`~.Mobject`'s z coordinate to the value of :attr:`z_index`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:1 msgid "Shift by the given vectors." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle:1 msgid "Shuffles the list of :attr:`submobjects`." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle_submobjects:1 msgid "Shuffles the order of :attr:`submobjects`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.sort:1 msgid "Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.sort_submobjects:1 msgid "Sort the :attr:`submobjects`" msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_depth:1 msgid "Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:1 msgid "Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:1 msgid "Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:1 msgid "Disable updating from updaters and animations." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:175::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:1 msgid "Apply all updaters." msgstr "" #: ../../source/reference/manim.mobject.mobject.Mobject.rst:177 msgid "Attributes" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.depth:1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1::1 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:3 msgid "The mobjects are added to :attr:`submobjects`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:5 msgid "Subclasses of mobject may implement ``+`` and ``+=`` dunder methods." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_color:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_coord:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_depth:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_dim_size:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_width:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_x:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_y:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_z:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.repeat:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_color:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:6 msgid "The mobjects to add." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:9 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:11 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:8 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:17 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:20 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:5 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:5 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:9 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:5 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:11 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:3 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:3 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:33 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:3 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:3 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:9 msgid "``self``" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.depth:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_bottom:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_center:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_corner:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_edge_center:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_left:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_nadir:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_right:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_top:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_x:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_y:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_z:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_zenith:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_no_points:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_points:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:12 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:18 msgid "When a mobject tries to add itself." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:13 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:19 msgid "When trying to add an object that is not an instance of :class:`Mobject`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:16 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:22 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:27 msgid "Notes" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:17 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:23 msgid "A mobject cannot contain itself, and it cannot contain a submobject more than once. If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene)." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:25 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:21 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:46 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:36 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_submobjects:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:16 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.flip:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.interpolate:5 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:5 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.next_to:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:15 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:37 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:12 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:10 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle_submobjects:4 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:7 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:6 msgid "Examples" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:32 msgid "Duplicates are not added again::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:38 msgid "Adding an object to itself raises an error::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:45 msgid "A given mobject cannot be added as a submobject twice to some parent::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:3 msgid "This does not apply to subclasses." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:5 msgid "The animation type to be overridden" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:6 msgid "The function returning an animation replacing the default animation. It gets passed the parameters given to the animnation constructor." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:9 msgid "If the overridden animation was already overridden." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:3 msgid "The BackgroundRectangle is added behind other submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:5 msgid "This can be used to increase the mobjects visibility in front of a noisy background." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:7 msgid "The color of the BackgroundRectangle" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:8 msgid "The opacity of the BackgroundRectangle" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:9 msgid "Additional keyword arguments passed to the BackgroundRectangle constructor" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:3 msgid "If :attr:`submobjects` already contains the given mobjects, they just get moved to the back instead." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:13 msgid "Technically, this is done by adding (or moving) the mobjects to the head of :attr:`submobjects`. The head of this list is rendered first, which places the corresponding mobjects behind the subsequent list members." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:3 msgid "Update functions, or updaters in short, are functions that are applied to the Mobject in every frame." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:6 msgid "The update function to be added. Whenever :meth:`update` is called, this update function gets called using ``self`` as the first parameter. The updater can have a second parameter ``dt``. If it uses this parameter, it gets called using a second value ``dt``, usually representing the time in seconds since the last call of :meth:`update`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:12 msgid "The index at which the new updater should be added in ``self.updaters``. In case ``index`` is ``None`` the updater will be added at the end." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:14 msgid "Whether or not to call the updater initially. If ``True``, the updater will be called using ``dt=0``." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:3 msgid "Afterwards, the two mobjects will have the same number of submobjects (see :meth:`.align_submobjects`), the same parent structure (see :meth:`.null_point_align`). If ``skip_point_alignment`` is false, they will also have the same number of points (see :meth:`.align_points`)." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:8 msgid "The other mobject this mobject should be aligned to." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:9 msgid "Controls whether or not the computationally expensive point alignment is skipped (default: False)." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:3 msgid "Examples: mob1.align_to(mob2, UP) moves mob1 vertically so that its top edge lines ups with mob2's top edge." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:7 msgid "mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1 horizontally so that it's center is directly above/below the center of mob2" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:3 msgid "Any method called on :code:`animate` is converted to an animation of applying that method on the mobject itself." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:6 msgid "For example, :code:`square.set_fill(WHITE)` sets the fill color of a square, while :code:`square.animate.set_fill(WHITE)` animates this action." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:9 msgid "Multiple methods can be put in a single animation once via chaining:" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:17 msgid "Passing multiple animations for the same :class:`Mobject` in one call to :meth:`~.Scene.play` is discouraged and will most likely not work properly. Instead of writing an animation like" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:25 msgid "make use of method chaining." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:27 msgid "Keyword arguments that can be passed to :meth:`.Scene.play` can be passed directly after accessing ``.animate``, like so::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:32 msgid "This is especially useful when animating simultaneous ``.animate`` calls that you want to behave differently::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:89 msgid "``.animate``" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:85 msgid "will interpolate the :class:`~.Mobject` between its points prior to ``.animate`` and its points after applying ``.animate`` to it. This may result in unexpected behavior when attempting to interpolate along paths, or rotations. If you want animations to consider the points between, consider using :class:`~.ValueTracker` with updaters instead." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:3 msgid "The animation class for which the override function should be returned." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:5 msgid "The function returning the override animation or ``None`` if no such animation override is defined." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_complex_function:1 msgid "Applies a complex function to a :class:`Mobject`. The x and y coordinates correspond to the real and imaginary parts respectively." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_complex_function:5 msgid "Example" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:3 msgid "The function to apply to each mobject. ``func`` gets passed the respective (sub)mobject as parameter." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:3 msgid "The number of rows in the grid." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:4 msgid "The number of columns in the grid." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:5 msgid "The gap between grid cells. To specify a different buffer in the horizontal and vertical directions, a tuple of two values can be given - ``(row, col)``." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:7 msgid "The way each submobject is aligned in its grid cell." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:8 msgid "The vertical alignment for each row (top to bottom). Accepts the following characters: ``\"u\"`` - up, ``\"c\"`` - center, ``\"d\"`` - down." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:10 msgid "The horizontal alignment for each column (left to right). Accepts the following characters ``\"l\"`` - left, ``\"c\"`` - center, ``\"r\"`` - right." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:12 msgid "Defines a list of heights for certain rows (top to bottom). If the list contains ``None``, the corresponding row will fit its height automatically based on the highest element in that row." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:15 msgid "Defines a list of widths for certain columns (left to right). If the list contains ``None``, the corresponding column will fit its width automatically based on the widest element in that column." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:17 msgid "The order in which submobjects fill the grid. Can be one of the following values: \"rd\", \"dr\", \"ld\", \"dl\", \"ru\", \"ur\", \"lu\", \"ul\". (\"rd\" -> fill rightwards then downwards)" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:23 msgid "If ``rows`` and ``cols`` are too small to fit all submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:24 msgid "If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`, :code:`row_alignments` and :code:`row_heights` have mismatching sizes." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:28 msgid "If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big enough to fit all submobjects. If neither is set, they will be chosen to be about the same, tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high)." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:32 msgid "If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are defined, the latter has higher priority." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:6 msgid "If both match_height and match_width are ``True`` then the transformed :class:`~.Mobject` will match the height first and then the width" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:9 msgid "If ``True``, then the transformed :class:`~.Mobject` will match the height of the original" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:10 msgid "If ``True``, then the transformed :class:`~.Mobject` will match the width of the original" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:11 msgid "If ``True``, then the transformed :class:`~.Mobject` will match the depth of the original" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:12 msgid "If ``True``, then the transformed :class:`~.Mobject` will match the center of the original" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:13 msgid "If ``True``, then the transformed :class:`~.Mobject` will stretch to fit the proportions of the original" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:3 msgid "Whether to recursively call ``clear_updaters`` on all submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:4 msgid "The copy." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:7 msgid "The clone is initially not visible in the Scene, even if the original was." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.generate_points:3 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.init_colors:3 msgid "Gets called upon creation. This is an empty method that can be implemented by subclasses." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_critical_point:1 msgid "Picture a box bounding the :class:`~.Mobject`. Such a box has 9 'critical points': 4 corners, 4 edge center, the center. This returns one of them, along the given direction." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_point_mobject:1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:3 msgid "The updaters use this parameter as the input for difference in time." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:5 msgid "The list of time based updaters." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:6 #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:4 msgid "List[:class:`Callable`]" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:3 msgid "The list of updaters." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:3 msgid "**class** -- ``True`` if at least one updater uses the ``dt`` parameter, ``False`` otherwise." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:5 msgid "`bool`" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:3 msgid "Effectively just calls ``self.submobjects.insert(index, mobject)``, where ``self.submobjects`` is a list." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:6 msgid "Highly adapted from ``Mobject.add``." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:8 msgid "The index at which" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:9 msgid "The mobject to be inserted." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:3 msgid "If ``True``, all submobject lists of this mobject's family are inverted." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:3 msgid "The mobject whose updaters get matched." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:10 msgid "All updaters from submobjects are removed, but only updaters of the given mobject are matched, not those of it's submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_x:1 msgid "Match x coord. to the x coord. of another :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_y:1 msgid "Match y coord. to the x coord. of another :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_z:1 msgid "Match z coord. to the x coord. of another :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:3 msgid "The mobjects are removed from :attr:`submobjects`, if they exist." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:5 msgid "Subclasses of mobject may implement ``-`` and ``-=`` dunder methods." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:7 msgid "The mobjects to remove." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:3 msgid "If the same updater is applied multiple times, every instance gets removed." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:5 msgid "The update function to be removed." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:3 msgid "Whether to recursively enable updating on all submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.save_state:1 msgid "Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:3 msgid "Default behavior is to scale about the center of the mobject." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:5 msgid "The scaling factor :math:`\\alpha`. If :math:`0 < |\\alpha| < 1`, the mobject will shrink, and for :math:`|\\alpha| > 1` it will grow. Furthermore, if :math:`\\alpha < 0`, the mobject is also flipped." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:8 msgid "Additional keyword arguments passed to :meth:`apply_points_function_about_point`." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:3 msgid "I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:5 msgid "This is a convenience to be used along with :attr:`animate` to animate setting attributes." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:8 msgid "In addition to this method, there is a compatibility layer that allows ``get_*`` and ``set_*`` methods to get and set generic attributes. For instance::" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:20 msgid "This compatibility layer does not interfere with any ``get_*`` or ``set_*`` methods that are explicitly defined." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:26 msgid "This compatibility layer is for backwards compatibility and is not guaranteed to stay around. Where applicable, please prefer getting/setting attributes normally or with the :meth:`set` method." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:31 msgid "The attributes and corresponding values to set." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_color:1 msgid "Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:3 msgid "If this method is called without any additional keyword arguments, the original default values of the initialization method of this class are restored." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:7 msgid "Passing any keyword argument will update the default values of the keyword arguments of the initialization function of this class." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:3 msgid "The new value of :attr:`z_index` set." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:4 msgid "If ``True``, the :attr:`z_index` value of all submobjects is also set." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:6 msgid "The Mobject itself, after :attr:`z_index` is set. For chaining purposes. (Returns `self`.)" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:3 msgid "The Mobject itself, after :attr:`z_index` is set. (Returns `self`.)" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:3 msgid "Vectors to shift by. If multiple vectors are given, they are added together." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:4 msgid "Whether to recursively suspend updating on all submobjects." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:3 msgid "Does nothing if updating is suspended." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:5 msgid "The parameter ``dt`` to pass to the update functions. Usually this is the time in seconds since the last call of ``update``." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:7 msgid "Whether to recursively update all submobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.mobject.rst:2 msgid "mobject" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject:1 msgid "Base classes for objects that can be displayed." msgstr "" #: ../../source/reference/manim.mobject.mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.mobject.rst:28::1 msgid "Groups together multiple :class:`Mobjects <.Mobject>`." msgstr "" #: ../../source/reference/manim.mobject.mobject.rst:28::1 msgid "Mathematical Object: base class for objects that can be displayed on screen." msgstr "" #: ../../source/reference/manim.mobject.mobject.rst:31 msgid "Functions" msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:1 msgid "Decorator for overriding method animations." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:3 msgid "This allows to specify a method (returning an :class:`~.Animation`) which is called when the decorated method is used with the ``.animate`` syntax for animating the application of a method." msgstr "" #: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:13 msgid "Overridden methods cannot be combined with normal or other overridden methods using method chaining with the ``.animate`` syntax." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.mobject_update_utils.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.number_line.NumberLine.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.number_line.UnitInterval.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.number_line.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.numbers.DecimalNumber.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.numbers.Integer.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.numbers.Variable.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.numbers.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.Dodecahedron.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.Icosahedron.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.Octahedron.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.Polyhedron.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.Tetrahedron.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.polyhedra.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.probability.BarChart.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.probability.SampleSpace.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.probability.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.shape_matchers.BackgroundRectangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.shape_matchers.Cross.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.shape_matchers.SurroundingRectangle.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.shape_matchers.Underline.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.shape_matchers.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.ArcBrace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:2 msgid "ArcBrace" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:4 msgid "Qualified name: ``manim.mobject.svg.brace.ArcBrace``" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:1 msgid "Bases: :py:class:`manim.mobject.svg.brace.Brace`" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:1 msgid "Creates a :class:`~Brace` that wraps around an :class:`~.Arc`." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:3 msgid "The direction parameter allows the brace to be applied from outside or inside the arc." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:7 msgid "The :class:`ArcBrace` is smaller for arcs with smaller radii." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:10 msgid "The :class:`ArcBrace` is initially a vertical :class:`Brace` defined by the length of the :class:`~.Arc`, but is scaled down to match the start and end angles. An exponential function is then applied after it is shifted based on the radius of the arc." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:15 msgid "The scaling effect is not applied for arcs with radii smaller than 1 to prevent over-scaling." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:18 msgid "The :class:`~.Arc` that wraps around the :class:`Brace` mobject." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:19 msgid "The direction from which the brace faces the arc. ``LEFT`` for inside the arc, and ``RIGHT`` for the outside." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:23 msgid "Example" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.Brace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.Brace.rst:2 msgid "Brace" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.Brace.rst:4 msgid "Qualified name: ``manim.mobject.svg.brace.Brace``" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:1 msgid "Bases: :py:class:`manim.mobject.svg.svg_path.SVGPathMobject`" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:1 msgid "Takes a mobject and draws a brace adjacent to it." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:3 msgid "Passing a direction vector determines the direction from which the brace is drawn. By default it is drawn from below." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:6 msgid "The mobject adjacent to which the brace is placed." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:8 msgid "The direction from which the brace faces the mobject." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:13 #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.Brace.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.Brace.rst:24::1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.Brace.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:7 msgid "The default direction of a :class:`~.Circle` is counterclockwise::" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:13 msgid "Either ``\"CW\"`` or ``\"CCW\"``." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceBetweenPoints.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:2 msgid "BraceBetweenPoints" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:4 msgid "Qualified name: ``manim.mobject.svg.brace.BraceBetweenPoints``" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:1 msgid "Bases: :py:class:`manim.mobject.svg.brace.Brace`" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:1 msgid "Similar to Brace, but instead of taking a mobject it uses 2 points to place the brace." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:4 msgid "A fitting direction for the brace is computed, but it still can be manually overridden. If the points go from left to right, the brace is drawn from below. Swapping the points places the brace on the opposite side." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:9 msgid "The first point." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:10 msgid "The second point." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:11 msgid "The direction from which the brace faces towards the points." msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:14 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceLabel.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:2 msgid "BraceLabel" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:4 msgid "Qualified name: ``manim.mobject.svg.brace.BraceLabel``" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceLabel:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:25 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceText.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:2 msgid "BraceText" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:4 msgid "Qualified name: ``manim.mobject.svg.brace.BraceText``" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceText:1 msgid "Bases: :py:class:`manim.mobject.svg.brace.BraceLabel`" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.brace.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.brace.rst:2 msgid "brace" msgstr "" #: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace:1 msgid "Mobject representing curly braces." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.svg.brace.rst:28::1 msgid "Creates a :class:`~Brace` that wraps around an :class:`~.Arc`." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.rst:28::1 msgid "Takes a mobject and draws a brace adjacent to it." msgstr "" #: ../../source/reference/manim.mobject.svg.brace.rst:28::1 msgid "Similar to Brace, but instead of taking a mobject it uses 2 points to place the brace." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.code_mobject.Code.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.code_mobject.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.rst:2 msgid "svg" msgstr "" #: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:1 msgid "Mobjects related to SVG images." msgstr "" #: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13::1 msgid "Mobject representing curly braces." msgstr "" #: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13::1 msgid "Utility functions for parsing SVG styles." msgstr "" #: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13::1 msgid "Mobjects generated from an SVG file." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.style_utils.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.style_utils.rst:2 msgid "style\\_utils" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils:1 msgid "Utility functions for parsing SVG styles." msgstr "" #: ../../source/reference/manim.mobject.svg.style_utils.rst:20 msgid "Functions" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:1 msgid "Collect the element's style attributes based upon both its inheritance and its own attributes." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:3 msgid "SVG uses cascading element styles. A closer ancestor's style takes precedence over a more distant ancestor's style. In order to correctly calculate the styles, the attributes are passed down through the inheritance tree, updating where necessary." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:7 msgid "Note that this method only copies the values and does not parse them. See :meth:`parse_color_string` for converting from SVG attributes to manim keyword arguments." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:10 msgid "Element of the SVG parse tree" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:12 msgid "Dictionary of SVG attributes inherited from the parent element." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:15 msgid "Dictionary mapping svg attributes to values with `element`'s values overriding inherited values." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0 #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:1 msgid "Fill in the default values for properties of SVG elements, if they are not currently set in the style dictionary." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:4 msgid "Style dictionary with SVG property names. Some may be missing." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:7 msgid "Style attributes; none are missing." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:1 msgid "Handle the SVG-specific color strings and convert them to HTML #rrggbb format." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:3 msgid "String in any web-compatible format" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:6 msgid "Hexadecimal color string in the format `#rrggbb`" msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:1 msgid "Convert a dictionary of SVG attributes to Manim VMobject keyword arguments." msgstr "" #: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:3 msgid "Style attributes as a string-to-string dictionary. Keys are valid SVG element attributes (fill, stroke, etc)" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.svg_mobject.SVGMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:2 msgid "SVGMobject" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:4 msgid "Qualified name: ``manim.mobject.svg.svg\\_mobject.SVGMobject``" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:1 msgid "A SVGMobject is a Vector Mobject constructed from an SVG (or XDV) file." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:3 msgid "SVGMobjects are constructed from the XML data within the SVG file structure. As such, subcomponents from the XML data can be accessed via the submobjects attribute. There is varying amounts of support for SVG elements, experiment with SVG files at your own peril." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:9 msgid "Examples" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:16 msgid "The file's path name. When possible, the full path is preferred but a relative path may be used as well. Relative paths are relative to the directory specified by the `--assets_dir` command line argument." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:21 msgid "Whether the SVGMobject should be centered to the origin. Defaults to `True`." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:23 msgid "Specify the final height of the SVG file. Defaults to 2 units." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:25 msgid "Specify the width the SVG file should occupy. Defaults to `None`." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:27 msgid "Whether the hierarchies of VGroups generated should be flattened. Defaults to `True`." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:29 msgid "The stroke width of the outer edge of an SVG path element. Defaults to `4`." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:31 msgid "Specifies the opacity of the image. `1` is opaque, `0` is transparent. Defaults to `1`." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23::1 #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23::1 msgid "Called by the Mobject abstract base class." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23::1 #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.init_colors:1 msgid "Initializes the colors." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1 #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1 msgid "Called by the Mobject abstract base class. Responsible for generating the SVGMobject's points from XML tags, populating self.mobjects, and any submobjects within self.mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.svg_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.svg_mobject.rst:2 msgid "svg\\_mobject" msgstr "" #: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject:1 msgid "Mobjects generated from an SVG file." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_mobject.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.svg_path.SVGPathMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:2 msgid "SVGPathMobject" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:4 msgid "Qualified name: ``manim.mobject.svg.svg\\_path.SVGPathMobject``" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1 msgid "Generates points from a given an SVG ``d`` attribute." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_original_path_string:1 msgid "A simple getter for the path's ``d`` attribute." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:1 msgid "Returns a list of possible path commands used within an SVG ``d`` attribute." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.handle_command:1 msgid "Core logic for handling each of the various path commands." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26::1 #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:1 msgid "Convert an SVG command string into a sequence of absolute-positioned control points." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:28 msgid "Attributes" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:4 msgid "See: https://svgwg.org/svg2-draft/paths.html#DProperty for further details on what each path command does." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:7 msgid "The various upper and lower cased path commands." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:8 msgid "List[:class:`str`]" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:3 msgid "A string containing a single uppercase letter representing the SVG command." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:5 msgid "Whether the command is relative to the end of the previous command" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:7 msgid "A string that contains many comma- or space-separated numbers that defined the control points. Different commands require different numbers of numbers as arguments." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.svg_path.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.svg.svg_path.rst:2 msgid "svg\\_path" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path:1 msgid "Mobjects generated from an SVG pathstring." msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.svg.svg_path.rst:29 msgid "Functions" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.correct_out_of_range_radii:1 msgid "Correction of out-of-range radii." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.correct_out_of_range_radii:3 msgid "See: https://www.w3.org/TR/SVG11/implnote.html#ArcCorrectionOutOfRangeRadii" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.elliptical_arc_to_cubic_bezier:1 msgid "Generate cubic bezier points to approximate SVG elliptical arc." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.elliptical_arc_to_cubic_bezier:3 msgid "See: http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.get_elliptical_arc_center_parameters:1 msgid "Conversion from endpoint to center parameterization." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.get_elliptical_arc_center_parameters:3 msgid "See: https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.grouped:1 msgid "Group iterable into arrays of n items." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:1 msgid "Parse the SVG string representing a sequence of numbers into an array of floats." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:3 msgid "String representing a sequence of numbers, separated by commas, spaces, etc." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:6 msgid "List of float values parsed out of the string." msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.vector_angle:1 msgid "Calculate the dot product angle between two vectors." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.BulletedList.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.MathTex.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.SingleStringMathTex.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.Tex.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.TexSymbol.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.Title.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.MarkupText.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.Paragraph.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.Text.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.DecimalTable.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:2 msgid "DecimalTable" msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:4 msgid "Qualified name: ``manim.mobject.table.DecimalTable``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:1 msgid "Bases: :py:class:`manim.mobject.table.Table`" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:19 msgid "Special case of :class:`~.Table` with ``element_to_mobject`` set to :class:`~.DecimalNumber`. By default, ``num_decimal_places`` is set to 1. Will round/truncate the decimal places based on the provided ``element_to_mobject_config``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:23 msgid "A 2D array, or a list of lists. Content of the table must be valid input for :class:`~.DecimalNumber`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:25 msgid "The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.DecimalNumber`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:26 msgid "Element to mobject config, here set as {\"num_decimal_places\": 1}." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:27 msgid "Additional arguments to be passed to :class:`~.Table`." msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.table.DecimalTable.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.IntegerTable.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:2 msgid "IntegerTable" msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:4 msgid "Qualified name: ``manim.mobject.table.IntegerTable``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:1 msgid "Bases: :py:class:`manim.mobject.table.Table`" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.Integer`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:24 msgid "Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.Integer`. Will round if there are decimal entries in the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:27 msgid "A 2d array or list of lists. Content of the table has to be valid input for :class:`~.Integer`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:29 msgid "The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.Integer`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:30 msgid "Additional arguments to be passed to :class:`~.Table`." msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.table.IntegerTable.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.MathTable.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.MathTable.rst:2 msgid "MathTable" msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:4 msgid "Qualified name: ``manim.mobject.table.MathTable``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:1 msgid "Bases: :py:class:`manim.mobject.table.Table`" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:1 msgid "A specialized :class:`~.Table` mobject for use with LaTeX." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:18 msgid "Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.MathTex`. Every entry in `table` is set in a Latex `align` environment." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:21 msgid "A 2d array or list of lists. Content of the table have to be valid input for :class:`~.MathTex`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:23 msgid "The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.MathTex`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:24 msgid "Additional arguments to be passed to :class:`~.Table`." msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.table.MathTable.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.MobjectTable.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:2 msgid "MobjectTable" msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:4 msgid "Qualified name: ``manim.mobject.table.MobjectTable``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:1 msgid "Bases: :py:class:`manim.mobject.table.Table`" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:26 msgid "Special case of :class:`~.Table` with ``element_to_mobject`` set to an identity function. Here, every item in ``table`` must already be of type :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:29 msgid "A 2D array or list of lists. Content of the table must be of type :class:`~.Mobject`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:30 msgid "The :class:`~.Mobject` class applied to the table entries. Set as ``lambda m : m`` to return itself." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:31 msgid "Additional arguments to be passed to :class:`~.Table`." msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.table.MobjectTable.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.Table.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.Table.rst:2 msgid "Table" msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:4 msgid "Qualified name: ``manim.mobject.table.Table``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:1 msgid "A mobject that displays a table on the screen." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:4 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:10 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:15 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:12 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:12 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:12 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:10 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:7 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:15 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:6 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:6 msgid "Examples" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:62 msgid "A 2D array or list of lists. Content of the table has to be a valid input for the callable set in ``element_to_mobject``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:64 msgid "List of :class:`~.VMobject` representing the labels of each row." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:65 msgid "List of :class:`~.VMobject` representing the labels of each column." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:66 msgid "The top-left entry of the table, can only be specified if row and column labels are given." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:68 msgid "Vertical buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 0.8." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:69 msgid "Horizontal buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 1.3." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:70 msgid "``True`` if the table should include outer lines, by default False." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:71 msgid "``True`` if background rectangles should be added to entries, by default ``False``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:72 msgid "Background color of entries if ``add_background_rectangles_to_entries`` is ``True``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:73 msgid "``True`` if the table should have a background rectangle, by default ``False``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:74 msgid "Background color of table if ``include_background_rectangle`` is ``True``." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:75 msgid "The :class:`~.Mobject` class applied to the table entries. by default :class:`~.Paragraph`. For common choices, see :mod:`~.text_mobject`/:mod:`~.tex_mobject`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:76 msgid "Custom configuration passed to :attr:`element_to_mobject`, by default {}." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:77 msgid "Dict passed to :meth:`~.Mobject.arrange_in_grid`, customizes the arrangement of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:78 msgid "Dict passed to :class:`~.Line`, customizes the lines of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:79 msgid "Additional arguments to be passed to :class:`~.VGroup`." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1 msgid "Adds a black :class:`~.BackgroundRectangle` to each entry of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:1 msgid "Highlights one cell at a specific position on the table by adding a :class:`~.BackgroundRectangle`." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:1 msgid "Customized create-type function for tables." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:1 msgid "Returns one specific cell as a rectangular :class:`~.Polygon` without the entry." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:1 msgid "Return the column labels of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:1 msgid "Return columns of the table as a :class:`~.VGroup` of :class:`~.VGroup`." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:1 msgid "Return the individual entries of the table (including labels) or one specific entry if the parameter, ``pos``, is set." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:1 msgid "Return the individual entries of the table (without labels) or one specific entry if the parameter, ``pos``, is set." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:1 msgid "Returns a :class:`~.BackgroundRectangle` of the cell at the given position." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:1 msgid "Return the horizontal lines of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:1 msgid "Returns the labels of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:1 msgid "Return the row labels of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:1 msgid "Return the rows of the table as a :class:`~.VGroup` of :class:`~.VGroup`." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:1 msgid "Return the vertical lines of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:1 msgid "Scale the size by a factor." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:1 msgid "Set individual colors for each column of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:36::1 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:1 msgid "Set individual colors for each row of the table." msgstr "" #: ../../source/reference/manim.mobject.table.Table.rst:38 msgid "Attributes" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:3 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:3 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:4 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:3 msgid "The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:5 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:5 msgid "The color used to highlight the cell." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:6 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:6 msgid "Additional arguments to be passed to :class:`~.BackgroundRectangle`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:3 msgid "The run time of the line creation and the writing of the elements." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:4 msgid "The lag ratio of the animation." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:5 msgid "The animation style of the table lines, see :mod:`~.creation` for examples." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:6 msgid "The animation style of the table labels, see :mod:`~.creation` for examples." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:7 msgid "The animation style of the table elements, see :mod:`~.creation` for examples." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:8 msgid "Further arguments passed to the creation animations." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:0 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:11 msgid "AnimationGroup containing creation of the lines and of the elements." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:5 msgid "Additional arguments to be passed to :class:`~.Polygon`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:8 msgid "Polygon mimicking one specific cell of the Table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:3 msgid "VGroup containing the column labels of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:3 msgid ":class:`~.VGroup` containing each column in a :class:`~.VGroup`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:7 msgid ":class:`~.VGroup` containing all entries of the table (including labels) or the :class:`~.VMobject` at the given position if ``pos`` is set." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:9 #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:9 msgid "Union[:class:`~.VMobject`, :class:`~.VGroup`]" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:4 msgid "The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table (without labels)." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:7 msgid ":class:`~.VGroup` containing all entries of the table (without labels) or the :class:`~.VMobject` at the given position if ``pos`` is set." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:3 msgid ":class:`~.VGroup` containing all the horizontal lines of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:3 msgid ":class:`~.VGroup` containing all the labels of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:3 msgid ":class:`~.VGroup` containing the row labels of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:3 msgid ":class:`~.VGroup` containing each row in a :class:`~.VGroup`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:3 msgid ":class:`~.VGroup` containing all the vertical lines of the table." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:3 msgid "Default behavior is to scale about the center of the mobject." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:5 msgid "The scaling factor :math:`\\alpha`. If :math:`0 < |\\alpha| < 1`, the mobject will shrink, and for :math:`|\\alpha| > 1` it will grow. Furthermore, if :math:`\\alpha < 0`, the mobject is also flipped." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:8 msgid "Additional keyword arguments passed to :meth:`apply_points_function_about_point`." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:11 msgid "``self``" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:3 msgid "An iterable of colors; each color corresponds to a column." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.table.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.table.rst:2 msgid "table" msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table:1 msgid "Mobjects representing tables." msgstr "" #: ../../../manim/mobject/table.py:docstring of manim.mobject.table:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.table.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.table.rst:28::1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries." msgstr "" #: ../../source/reference/manim.mobject.table.rst:28::1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.Integer`." msgstr "" #: ../../source/reference/manim.mobject.table.rst:28::1 msgid "A specialized :class:`~.Table` mobject for use with LaTeX." msgstr "" #: ../../source/reference/manim.mobject.table.rst:28::1 msgid "A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.code_mobject.Code.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:2 msgid "Code" msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:4 msgid "Qualified name: ``manim.mobject.text.code\\_mobject.Code``" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:1 msgid "A highlighted source code listing." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:3 msgid "An object ``listing`` of :class:`.Code` is a :class:`.VGroup` consisting of three objects:" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:6 msgid "The background, ``listing.background_mobject``. This is either a :class:`.Rectangle` (if the listing has been initialized with ``background=\"rectangle\"``, the default option) or a :class:`.VGroup` resembling a window (if ``background=\"window\"`` has been passed)." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:11 msgid "The line numbers, ``listing.line_numbers`` (a :class:`.Paragraph` object)." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:14 msgid "The highlighted code itself, ``listing.code`` (a :class:`.Paragraph` object)." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:19 msgid "Using a :class:`.Transform` on text with leading whitespace (and in this particular case: code) can look `weird `_. Consider using :meth:`remove_invisible_chars` to resolve this issue." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:25 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:26 msgid "Normal usage::" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:39 msgid "We can also render code passed as a string (but note that the language has to be specified in this case):" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:60 msgid "Name of the code file to display." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:62 msgid "If ``file_name`` is not specified, a code string can be passed directly." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:65 msgid "Number of space characters corresponding to a tab character. Defaults to 3." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:67 msgid "Amount of space between lines in relation to font size. Defaults to 0.3, which means 30% of font size." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:69 msgid "A number which scales displayed code. Defaults to 24." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:71 msgid "The name of the text font to be used. Defaults to ``\"Monospac821 BT\"``." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:73 msgid "Stroke width for text. 0 is recommended, and the default." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:75 msgid "Inner margin of text from the background. Defaults to 0.3." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:77 msgid "\"Indentation chars\" refers to the spaces/tabs at the beginning of a given code line. Defaults to ``\" \"`` (spaces)." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:79 msgid "Defines the background's type. Currently supports only ``\"rectangle\"`` (default) and ``\"window\"``." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:81 msgid "Defines the stroke width of the background. Defaults to 1." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:83 msgid "Defines the stroke color for the background. Defaults to ``WHITE``." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:85 msgid "Defines the corner radius for the background. Defaults to 0.2." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:87 msgid "Defines whether line numbers should be inserted in displayed code. Defaults to ``True``." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:89 msgid "Defines the first line's number in the line count. Defaults to 1." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:91 msgid "Defines the spacing between line numbers and displayed code. Defaults to 0.4." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:93 msgid "Defines the style type of displayed code. You can see possible names of styles in with :attr:`styles_list`. Defaults to ``\"vim\"``." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:95 msgid "Specifies the programming language the given code was written in. If ``None`` (the default), the language will be automatically detected. For the list of possible options, visit https://pygments.org/docs/lexers/ and look for 'aliases or short names'." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:100 msgid "Defines whether to generate highlighted html code to the folder `assets/codes/generated_html_files`. Defaults to `False`." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:105 msgid "The background of the code listing." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0 #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0 #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0 msgid "type" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:111 msgid "The line numbers for the code listing. Empty, if ``insert_line_no=False`` has been specified." msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:118 msgid "The highlighted code." msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.code_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.code_mobject.rst:2 msgid "code\\_mobject" msgstr "" #: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject:1 msgid "Mobject representing highlighted source code listings." msgstr "" #: ../../source/reference/manim.mobject.text.code_mobject.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.numbers.DecimalNumber.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:2 msgid "DecimalNumber" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:4 msgid "Qualified name: ``manim.mobject.text.numbers.DecimalNumber``" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:1 msgid "An mobject representing a decimal number." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:22::1 #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.set_value:1 msgid "Set the value of the :class:`~.DecimalNumber` to a new number." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1 msgid "The font size of the tex mobject." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:0 #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.set_value:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.numbers.Integer.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:2 msgid "Integer" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:4 msgid "Qualified name: ``manim.mobject.text.numbers.Integer``" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:1 msgid "Bases: :py:class:`manim.mobject.text.numbers.DecimalNumber`" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:1 msgid "A class for displaying Integers." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34::1 msgid "The font size of the tex mobject." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.numbers.Variable.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:2 msgid "Variable" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:4 msgid "Qualified name: ``manim.mobject.text.numbers.Variable``" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:1 msgid "A class for displaying text that shows \"label = value\" with the value continuously updated from a :class:`~.ValueTracker`." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:4 msgid "The initial value you need to keep track of and display." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:6 msgid "The label for your variable. Raw strings are convertex to :class:`~.MathTex` objects." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:8 msgid "The class used for displaying the number. Defaults to :class:`DecimalNumber`." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:10 msgid "The number of decimal places to display in your variable. Defaults to 2. If `var_type` is an :class:`Integer`, this parameter is ignored." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:13 msgid "Other arguments to be passed to `~.Mobject`." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:18 msgid "The label for your variable, for example ``x = ...``." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0 #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0 #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0 msgid "type" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:20 msgid "Union[:class:`str`, :class:`~.Tex`, :class:`~.MathTex`, :class:`~.Text`, :class:`~.TexSymbol`, :class:`~.SingleStringMathTex`]" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:24 msgid "Useful in updating the value of your variable on-screen." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:30 msgid "The tex for the value of your variable." msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:32 msgid "Union[:class:`DecimalNumber`, :class:`Integer`]" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:35 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:36 msgid "Normal usage::" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.numbers.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.numbers.rst:2 msgid "numbers" msgstr "" #: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers:1 msgid "Mobjects representing numbers." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.text.numbers.rst:24::1 msgid "An mobject representing a decimal number." msgstr "" #: ../../source/reference/manim.mobject.text.numbers.rst:24::1 msgid "A class for displaying Integers." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.rst:2 msgid "text" msgstr "" #: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:1 msgid "Mobjects used to display Text using Pango or LaTeX." msgstr "" #: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13::1 msgid "Mobject representing highlighted source code listings." msgstr "" #: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13::1 msgid "Mobjects representing numbers." msgstr "" #: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13::1 msgid "Mobjects representing text rendered using LaTeX." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.BulletedList.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:2 msgid "BulletedList" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.BulletedList``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.BulletedList:1 msgid "Bases: :py:class:`manim.mobject.text.tex_mobject.Tex`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.BulletedList:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34::1 msgid "The font size of the tex mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.MathTex.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:2 msgid "MathTex" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.MathTex``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:1 msgid "Bases: :py:class:`manim.mobject.text.tex_mobject.SingleStringMathTex`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:1 msgid "A string compiled with LaTeX in math mode." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:14 msgid "Tests" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:15 msgid "Check that creating a :class:`~.MathTex` works::" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:20 msgid "Check that double brace group splitting works correctly::" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:28 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "The font size of the tex mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "The height of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:2 msgid "SingleStringMathTex" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.SingleStringMathTex``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:1 msgid "Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:1 msgid "Elementary building block for rendering text with LaTeX." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:4 msgid "Tests" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:5 msgid "Check that creating a :class:`~.SingleStringMathTex` object works::" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:22::1 #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.init_colors:1 msgid "Initializes the colors." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1 msgid "The font size of the tex mobject." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.Tex.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:2 msgid "Tex" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.Tex``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:1 msgid "Bases: :py:class:`manim.mobject.text.tex_mobject.MathTex`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:1 msgid "A string compiled with LaTeX in normal mode." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:4 msgid "Tests" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:5 msgid "Check whether writing a LaTeX string works::" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33::1 msgid "The font size of the tex mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.TexSymbol.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:2 msgid "TexSymbol" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.TexSymbol``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.TexSymbol:1 msgid "Bases: :py:class:`manim.mobject.svg.svg_path.SVGPathMobject`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.TexSymbol:1 msgid "Purely a renaming of SVGPathMobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.Title.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:2 msgid "Title" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:4 msgid "Qualified name: ``manim.mobject.text.tex\\_mobject.Title``" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Title:1 msgid "Bases: :py:class:`manim.mobject.text.tex_mobject.Tex`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Title:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33::1 msgid "The font size of the tex mobject." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:2 msgid "tex\\_mobject" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:1 msgid "Mobjects representing text rendered using LaTeX." msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:5 msgid "See the corresponding tutorial :ref:`rendering-with-latex`" msgstr "" #: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:9 msgid "Just as you can use :class:`~.Text` (from the module :mod:`~.text_mobject`) to add text to your videos, you can use :class:`~.Tex` and :class:`~.MathTex` to insert LaTeX." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:0 #: ../../source/reference/manim.mobject.text.tex_mobject.rst:0 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:30::1 msgid "A string compiled with LaTeX in math mode." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:30::1 msgid "Elementary building block for rendering text with LaTeX." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:30::1 msgid "A string compiled with LaTeX in normal mode." msgstr "" #: ../../source/reference/manim.mobject.text.tex_mobject.rst:30::1 msgid "Purely a renaming of SVGPathMobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.text_mobject.MarkupText.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:2 msgid "MarkupText" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:4 msgid "Qualified name: ``manim.mobject.text.text\\_mobject.MarkupText``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:1 msgid "Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:1 msgid "Display (non-LaTeX) text rendered using `Pango `_." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:3 msgid "Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:6 msgid "**What is PangoMarkup?**" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:8 msgid "PangoMarkup is a small markup language like html and it helps you avoid using \"range of characters\" while coloring or styling a piece a Text. You can use this language with :class:`~.MarkupText`." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:12 msgid "A simple example of a marked-up string might be::" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:16 msgid "and it can be used with :class:`~.MarkupText` as" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:26 msgid "A more elaborate example would be:" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:42 msgid "PangoMarkup can also contain XML features such as numeric character entities such as ``©`` for © can be used too." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:45 msgid "The most general markup tag is ````, then there are some convenience tags." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:48 msgid "Here is a list of supported tags:" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:50 msgid "``bold``, ``italic`` and ``bold+italic``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:51 msgid "``
    underline
`` and ``strike through``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:52 msgid "``typewriter font``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:53 msgid "``bigger font`` and ``smaller font``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:54 msgid "``superscript`` and ``subscript``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:55 msgid "``double underline``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:56 msgid "``error underline``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:57 msgid "``overline``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:58 msgid "``strikethrough``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:59 msgid "``temporary change of font``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:60 msgid "``temporary change of color``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:61 msgid "``temporary change of color``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:62 msgid "``temporary gradient``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:64 msgid "For ```` markup, colors can be specified either as hex triples like ``#aabbcc`` or as named CSS colors like ``AliceBlue``. The ```` tag is handled by Manim rather than Pango, and supports hex triplets or Manim constants like ``RED`` or ``RED_A``. If you want to use Manim constants like ``RED_A`` together with ````, you will need to use Python's f-String syntax as follows::" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:76 msgid "If your text contains ligatures, the :class:`MarkupText` class may incorrectly determine the first and last letter when creating the gradient. This is due to the fact that ``fl`` are two separate characters, but might be set as one single glyph - a ligature. If your language does not depend on ligatures, consider setting ``disable_ligatures`` to ``True``. If you must use ligatures, the ``gradient`` tag supports an optional attribute ``offset`` which can be used to compensate for that error." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:84 msgid "For example:" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:86 msgid "``example`` to *start* the gradient one letter earlier" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:87 msgid "``example`` to *end* the gradient one letter earlier" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:88 msgid "``example`` to *start* the gradient two letters earlier and *end* it one letter earlier" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:90 msgid "Specifying a second offset may be necessary if the text to be colored does itself contain ligatures. The same can happen when using HTML entities for special chars." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:94 msgid "When using ``underline``, ``overline`` or ``strikethrough`` together with ```` tags, you will also need to use the offset, because underlines are additional paths in the final :class:`SVGMobject`. Check out the following example." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:99 msgid "Escaping of special characters: ``>`` **should** be written as ``>`` whereas ``<`` and ``&`` *must* be written as ``<`` and ``&``." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:103 msgid "You can find more information about Pango markup formatting at the corresponding documentation page: `Pango Markup `_. Please be aware that not all features are supported by this class and that the ```` tag mentioned above is not supported by Pango." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:109 msgid "The text that needs to be created as mobject." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:110 msgid "The fill opacity, with 1 meaning opaque and 0 meaning transparent." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:111 msgid "Stroke width." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:112 msgid "Font size." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:113 msgid "Line spacing." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:114 msgid "Global font setting for the entire text. Local overrides are possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:115 msgid "Global slant setting, e.g. `NORMAL` or `ITALIC`. Local overrides are possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:116 msgid "Global weight setting, e.g. `NORMAL` or `BOLD`. Local overrides are possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:117 msgid "Global gradient setting. Local overrides are possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:119 msgid "The text displayed in form of a :class:`.VGroup`-like mobject." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:123 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:224 msgid "As :class:`MarkupText` uses Pango to render text, rendering non-English characters is easily possible:" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:243 msgid "You can justify the text by passing :attr:`justify` parameter." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:278 msgid "Tests" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:279 msgid "Check that the creation of :class:`~.MarkupText` works::" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.text_mobject.Paragraph.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:2 msgid "Paragraph" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:4 msgid "Qualified name: ``manim.mobject.text.text\\_mobject.Paragraph``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:1 msgid "Display a paragraph of text." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:3 msgid "For a given :class:`.Paragraph` ``par``, the attribute ``par.chars`` is a :class:`.VGroup` containing all the lines. In this context, every line is constructed as a :class:`.VGroup` of characters contained in the line." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:8 msgid "Represents the spacing between lines. Defaults to -1, which means auto." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:9 msgid "Defines the alignment of paragraph. Defaults to None. Possible values are \"left\", \"right\" or \"center\"." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:12 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:13 msgid "Normal usage::" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:20 msgid "Remove unwanted invisible characters::" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.text_mobject.Text.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:2 msgid "Text" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:4 msgid "Qualified name: ``manim.mobject.text.text\\_mobject.Text``" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:1 msgid "Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:1 msgid "Display (non-LaTeX) text rendered using `Pango `_." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:3 msgid "Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:6 msgid "The text that needs to be created as a mobject." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:8 msgid "The mobject-like :class:`.VGroup`." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:12 msgid "Examples" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:61 msgid "As :class:`Text` uses Pango to render text, rendering non-English characters is easily possible:" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:94 msgid "Tests" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:95 msgid "Check that the creation of :class:`~.Text` works::" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:20::1 #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1 msgid "Initializes the colors." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.text.text_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.text.text_mobject.rst:2 msgid "text\\_mobject" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:1 msgid "Mobjects used for displaying (non-LaTeX) text." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:4 msgid "Just as you can use :class:`~.Tex` and :class:`~.MathTex` (from the module :mod:`~.tex_mobject`) to insert LaTeX to your videos, you can use :class:`~.Text` to to add normal text." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:9 msgid "See the corresponding tutorial :ref:`rendering-with-latex`" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:12 msgid "The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the Pango library to render text. With Pango, you are also able to render non-English alphabets like `你好` or `こんにちは` or `안녕하세요` or `مرحبا بالعالم`." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:16 #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.rst:30::1 #: ../../source/reference/manim.mobject.text.text_mobject.rst:30::1 msgid "Display (non-LaTeX) text rendered using `Pango `_." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.rst:30::1 msgid "Display a paragraph of text." msgstr "" #: ../../source/reference/manim.mobject.text.text_mobject.rst:33 msgid "Functions" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:1 msgid "Temporarily add a font file to Pango's search path." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:3 msgid "This searches for the font_file at various places. The order it searches it described below." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:5 msgid "Absolute path." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:6 msgid "In ``assets/fonts`` folder." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:7 msgid "In ``font/`` folder." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:8 msgid "In the same directory." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0 #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0 #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:10 msgid "The font file to add." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:14 msgid "Use ``with register_font(...)`` to add a font file to search path." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:22 msgid "If the font doesn't exists." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:23 msgid "If this method is used on macOS." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:24 msgid "This method is available for macOS for ``ManimPango>=v0.2.3``. Using this method with previous releases will raise an :class:`AttributeError` on macOS." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:1 msgid "Function to remove unwanted invisible characters from some mobjects." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:3 msgid "Any SVGMobject from which we want to remove unwanted invisible characters." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:5 msgid "The SVGMobject without unwanted invisible characters." msgstr "" #: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Dodecahedron.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:2 msgid "Dodecahedron" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.polyhedra.Dodecahedron``" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:1 msgid "Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:1 msgid "A dodecahedron, one of the five platonic solids. It has 12 faces, 30 edges and 20 vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:3 msgid "The length of an edge between any two vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Icosahedron.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:2 msgid "Icosahedron" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.polyhedra.Icosahedron``" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:1 msgid "Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:1 msgid "An icosahedron, one of the five platonic solids. It has 20 faces, 30 edges and 12 vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:3 msgid "The length of an edge between any two vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Octahedron.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:2 msgid "Octahedron" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.polyhedra.Octahedron``" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:1 msgid "Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:1 msgid "An octahedron, one of the five platonic solids. It has 8 faces, 12 edges and 6 vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:3 msgid "The length of an edge between any two vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Polyhedron.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:2 msgid "Polyhedron" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.polyhedra.Polyhedron``" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:1 msgid "An abstract polyhedra class." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:3 msgid "In this implementation, polyhedra are defined with a list of vertex coordinates in space, and a list of faces. This implementation mirrors that of a standard polyhedral data format (OFF, object file format)." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:0 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:0 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:6 msgid "A list of coordinates of the corresponding vertices in the polyhedron. Each coordinate will correspond to a vertex. The vertices are indexed with the usual indexing of Python." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:8 msgid "A list of faces. Each face is a sublist containing the indices of the vertices that form the corners of that face." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:9 msgid "Configuration for the polygons representing the faces of the polyhedron." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:10 msgid "Configuration for the graph containing the vertices and edges of the polyhedron." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:13 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:14 msgid "To understand how to create a custom polyhedra, let's use the example of a rather simple one - a square pyramid." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:39 msgid "In defining the polyhedron above, we first defined the coordinates of the vertices. These are the corners of the square base, given as the first four coordinates in the vertex list, and the apex, the last coordinate in the list." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:43 msgid "Next, we define the faces of the polyhedron. The triangular surfaces of the pyramid are polygons with two adjacent vertices in the base and the vertex at the apex as corners. We thus define these surfaces in the first four elements of our face list. The last element defines the base of the pyramid." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:47 msgid "The graph and faces of polyhedra can also be accessed and modified directly, after instantiation. They are stored in the `graph` and `faces` attributes respectively." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23::1 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1 msgid "Creates VGroup of faces from a list of face coordinates." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23::1 msgid "Extracts the coordinates of the vertices in the graph." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23::1 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:1 msgid "Creates list of cyclic pairwise tuples." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:0 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.extract_face_coords:0 #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Tetrahedron.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:2 msgid "Tetrahedron" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.polyhedra.Tetrahedron``" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:1 msgid "Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:1 msgid "A tetrahedron, one of the five platonic solids. It has 4 faces, 6 edges, and 4 vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:3 msgid "The length of an edge between any two vertices." msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:6 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:2 msgid "polyhedra" msgstr "" #: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra:1 msgid "General polyhedral class and platonic solids." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28::1 msgid "A dodecahedron, one of the five platonic solids." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28::1 msgid "An icosahedron, one of the five platonic solids." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28::1 msgid "An octahedron, one of the five platonic solids." msgstr "" #: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28::1 msgid "An abstract polyhedra class." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.rst:2 msgid "three\\_d" msgstr "" #: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:1 #: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12::1 msgid "Three-dimensional mobjects." msgstr "" #: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12::1 msgid "General polyhedral class and platonic solids." msgstr "" #: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12::1 msgid "Utility functions for three-dimensional mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_d_utils.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_d_utils.rst:2 msgid "three\\_d\\_utils" msgstr "" #: ../../../manim/mobject/three_d/three_d_utils.py:docstring of manim.mobject.three_d.three_d_utils:1 msgid "Utility functions for three-dimensional mobjects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Arrow3D.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:2 msgid "Arrow3D" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Arrow3D``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Line3D`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:1 msgid "An arrow made out of a cylindrical line and a conical tip." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:15 msgid "The start position of the arrow." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:17 msgid "The end position of the arrow." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:19 msgid "The thickness of the arrow." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:21 msgid "The height of the conical tip." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:23 msgid "The base radius of the conical tip." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cone.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:2 msgid "Cone" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Cone``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:1 msgid "A circular cone. Can be defined using 2 parameters: its height, and its base radius. The polar angle, theta, can be calculated using arctan(base_radius / height) The spherical radius, r, is calculated using the pythagorean theorem." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:8 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:6 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:19 msgid "The base radius from which the cone tapers." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:21 msgid "The height measured from the plane formed by the base_radius to the apex of the cone." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:23 msgid "The direction of the apex." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:25 msgid "Whether to show the base plane or not." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:27 msgid "The azimuthal angle to start and end at." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:29 msgid "The radius at the apex." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:31 msgid "Show checkerboard grid texture on the cone." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:22::1 msgid "Converts from spherical coordinates to cartesian." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:22::1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1 msgid "Converts from spherical coordinates to cartesian. :param u: The radius. :type u: :class:`float` :param v: The azimuthal angle. :type v: :class:`float`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:7 msgid "The default direction of a :class:`~.Circle` is counterclockwise::" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:13 msgid "Either ``\"CW\"`` or ``\"CCW\"``." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cube.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:2 msgid "Cube" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Cube``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:21::1 #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:21::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cylinder.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:2 msgid "Cylinder" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Cylinder``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:1 msgid "A cylinder, defined by its height, radius and direction," msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:15 msgid "The radius of the cylinder." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:17 msgid "The height of the cylinder." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:19 msgid "The direction of the central axis of the cylinder." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:21 msgid "The height along the height axis (given by direction) to start and end on." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:23 msgid "Whether to show the end caps or not." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1 msgid "Adds the end caps of the cylinder." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23::1 msgid "Converts from cylindrical coordinates to cartesian." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.get_direction:1 msgid "Returns the direction of the central axis of the cylinder." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Dot3D.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:2 msgid "Dot3D" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Dot3D``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Sphere`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:1 msgid "A spherical dot." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:3 msgid "The location of the dot." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:5 msgid "The radius of the dot." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:7 msgid "The color of the :class:`Dot3D`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:11 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Line3D.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:2 msgid "Line3D" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Line3D``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Cylinder`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:1 msgid "A cylindrical line, for use in ThreeDScene." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:4 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:9 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:9 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:0 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:0 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:15 msgid "The start position of the line." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:17 msgid "The end position of the line." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:19 msgid "The thickness of the line." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_start:1 msgid "Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:1 msgid "Returns a line parallel to another line going through a given point." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:1 msgid "Returns a line perpendicular to another line going through a given point." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.set_start_and_end_attrs:1 msgid "Sets the start and end points of the line." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:4 msgid "The line to be parallel to." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:5 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:5 msgid "The point to pass through." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:6 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:6 msgid "Additional parameters to be passed to the class." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:4 msgid "The line to be perpendicular to." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Prism.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:2 msgid "Prism" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Prism``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Cube`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:1 msgid "A cuboid." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:20::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Sphere.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:2 msgid "Sphere" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Sphere``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:1 msgid "A mobject representing a three-dimensional sphere." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Surface.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:2 msgid "Surface" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Surface``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:1 msgid "Creates a Parametric Surface using a checkerboard pattern." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:0 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:3 msgid "The function that defines the surface." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:4 msgid "The range of the ``u`` variable: ``(u_min, u_max)``." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:5 msgid "The range of the ``v`` variable: ``(v_min, v_max)``." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:6 msgid "The number of samples taken of the surface. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:0 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:11 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:12 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:21::1 #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1 msgid "Sets the color of each mobject of a parametric surface to a color relative to its axis-value" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:3 msgid "The axes for the parametric surface, which will be used to map axis-values to colors." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:4 msgid "A list of colors, ordered from lower axis-values to higher axis-values. If a list of tuples is passed containing colors paired with numbers, then those numbers will be used as the pivots." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:6 msgid "The chosen axis to use for the color mapping. (0 = x, 1 = y, 2 = z)" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:8 msgid "The parametric surface with a gradient applied by value. For chaining." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:2 msgid "ThreeDVMobject" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.ThreeDVMobject``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.ThreeDVMobject:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Torus.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:2 msgid "Torus" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:4 msgid "Qualified name: ``manim.mobject.three\\_d.three\\_dimensions.Torus``" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:1 msgid "Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:1 msgid "A torus." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:4 msgid "Examples" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:15 msgid "Distance from the center of the tube to the center of the torus." msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:17 msgid "Radius of the tube." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:2 msgid "three\\_dimensions" msgstr "" #: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions:1 msgid "Three-dimensional mobjects." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "An arrow made out of a cylindrical line and a conical tip." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A circular cone." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A cylinder, defined by its height, radius and direction," msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A spherical dot." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A cylindrical line, for use in ThreeDScene." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A cuboid." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "A mobject representing a three-dimensional sphere." msgstr "" #: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40::1 msgid "Creates a Parametric Surface using a checkerboard pattern." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_d_utils.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Arrow3D.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cone.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cube.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cylinder.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Dot3D.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Line3D.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.ParametricSurface.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Prism.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Sphere.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Surface.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.ThreeDVMobject.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.Torus.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.three_dimensions.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.image_mobject.AbstractImageMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:2 msgid "AbstractImageMobject" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:4 msgid "Qualified name: ``manim.mobject.types.image\\_mobject.AbstractImageMobject``" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:1 msgid "Bases: :py:class:`manim.mobject.mobject.Mobject`" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:1 msgid "Automatically filters out black pixels" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:0 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:3 msgid "At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23::1 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1 msgid "Sets :attr:`points` to be an empty array." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23::1 msgid "Condition is function which takes in one arguments, (x, y, z)." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23::1 msgid "Sets the interpolation method for upscaling the image." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_color:1 msgid "Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:1 msgid "Sets the interpolation method for upscaling the image. By default the image is interpolated using bicubic algorithm. This method lets you change it. Interpolation is done internally using Pillow, and the function besides the string constants describing the algorithm accepts the Pillow integer constants." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:11 msgid "* 'bicubic' or 'cubic' * 'nearest' or 'none' * 'box' * 'bilinear' or 'linear' * 'hamming' * 'lanczos' or 'antialias'" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:12 msgid "'bicubic' or 'cubic'" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:13 msgid "'nearest' or 'none'" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:14 msgid "'box'" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:15 msgid "'bilinear' or 'linear'" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:16 msgid "'hamming'" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.image_mobject.ImageMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:2 msgid "ImageMobject" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:4 msgid "Qualified name: ``manim.mobject.types.image\\_mobject.ImageMobject``" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:1 msgid "Bases: :py:class:`manim.mobject.types.image_mobject.AbstractImageMobject`" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:1 msgid "Displays an Image from a numpy array or a file." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:0 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:0 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:0 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_opacity:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:3 msgid "At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:11 msgid "Example" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:22 msgid "Changing interpolation style:" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25::1 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1 msgid "Sets the image's opacity using a 1 - alpha relationship." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25::1 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.get_pixel_array:1 msgid "A simple getter method." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25::1 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:1 msgid "Interpolates an array of pixel color values into another array of equal size." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25::1 msgid "Condition is function which takes in one arguments, (x, y, z)." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25::1 #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_opacity:1 msgid "Sets the image's opacity." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:27 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:3 msgid "The alpha value of the object, 1 being transparent and 0 being opaque." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:6 msgid "Whether the submobjects of the ImageMobject should be affected." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:4 msgid "The ImageMobject to transform from." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:6 msgid "The ImageMobject to transform into." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:8 msgid "Used to track the lerp relationship. Not opacity related." msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_color:1 msgid "Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:2 msgid "ImageMobjectFromCamera" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:4 msgid "Qualified name: ``manim.mobject.types.image\\_mobject.ImageMobjectFromCamera``" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobjectFromCamera:1 msgid "Bases: :py:class:`manim.mobject.types.image_mobject.AbstractImageMobject`" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:24 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.image_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.image_mobject.rst:2 msgid "image\\_mobject" msgstr "" #: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject:1 msgid "Mobjects representing raster images." msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.rst:24::1 msgid "Automatically filters out black pixels" msgstr "" #: ../../source/reference/manim.mobject.types.image_mobject.rst:24::1 msgid "Displays an Image from a numpy array or a file." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:2 msgid "Mobject1D" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.Mobject1D``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Mobject1D:1 msgid "Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:2 msgid "Mobject2D" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.Mobject2D``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Mobject2D:1 msgid "Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PGroup.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:2 msgid "PGroup" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.PGroup``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PGroup:1 msgid "Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PGroup:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:22 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:2 msgid "PMobject" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.PMobject``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:1 msgid "Bases: :py:class:`manim.mobject.mobject.Mobject`" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:1 msgid "A disc made of a cloud of Dots" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1 msgid "Add points." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.get_color:1 msgid "Returns the color of the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.reset_points:1 msgid "Sets :attr:`points` to be an empty array." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 msgid "Condition is function which takes in one arguments, (x, y, z)." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.sort_points:1 msgid "Function is any map from R^3 to R" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.thin_out:1 msgid "Removes all but every nth point for n = factor" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:42 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:3 msgid "Points must be a Nx3 numpy array. Rgbas must be a Nx4 numpy array if it is not None." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.get_point_mobject:1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Point.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:2 msgid "Point" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.Point``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point:1 msgid "Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point:2 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:21::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:2 msgid "PointCloudDot" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:4 msgid "Qualified name: ``manim.mobject.types.point\\_cloud\\_mobject.PointCloudDot``" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot:1 msgid "Bases: :py:class:`manim.mobject.types.point_cloud_mobject.Mobject1D`" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot:1 msgid "A disc made of a cloud of Dots .. rubric:: Examples" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:21::1 #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1 msgid "Initializes :attr:`points` and therefore the shape." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:2 msgid "point\\_cloud\\_mobject" msgstr "" #: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject:1 msgid "Mobjects representing point clouds." msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30::0 #: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30::0 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30::1 msgid "A disc made of a cloud of Dots" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.rst:2 msgid "types" msgstr "" #: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:1 msgid "Specialized mobject base classes." msgstr "" #: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:4 msgid "Modules" msgstr "" #: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:12::1 msgid "Mobjects representing raster images." msgstr "" #: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:12::1 msgid "Mobjects representing point clouds." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:2 msgid "CurvesAsSubmobjects" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.CurvesAsSubmobjects``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:1 msgid "Convert a curve's elements to submobjects." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:4 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:2 msgid "DashedVMobject" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.DashedVMobject``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:1 msgid "A :class:`VMobject` composed of dashes instead of lines." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:3 msgid "The object that will get dashed" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:4 msgid "Number of dashes to add." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:5 msgid "Ratio of dash to empty space." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:6 msgid "Shifts the starting point of dashes along the path. Value 1 shifts by one full dash length." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:8 msgid "If ``True``, dashes will be (approximately) equally long. If ``False``, dashes will be split evenly in the curve's input t variable (legacy behavior)." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:21 msgid "Attributes" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32::1 msgid "The depth of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32::1 msgid "The height of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VDict.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:2 msgid "VDict" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.VDict``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:1 msgid "A VGroup-like class, also offering submobject access by key, like a python dict" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:4 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:6 msgid "The parameter specifying the key-value mapping of keys and mobjects." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:6 msgid "Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. Defaults to False." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:11 msgid "Other arguments to be passed to `Mobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:16 msgid "Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. When displayed, the key is towards the left of the mobject. Defaults to False." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0 msgid "type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:27 msgid "Is the actual python dictionary that is used to bind the keys to the mobjects." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:33 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:13 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:14 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:7 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1 msgid "Adds the key-value pairs to the :class:`VDict` object." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23::1 msgid "A utility function used by :meth:`add` to add the key-value pair to :attr:`submob_dict`." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:1 msgid "To get all the submobjects associated with a particular :class:`VDict` object" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:1 msgid "Removes the mobject from the :class:`VDict` object having the key `key`" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:3 msgid "Also, it internally adds the value to the `submobjects` :class:`list` of :class:`~.Mobject`, which is responsible for actual on-screen display." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:9 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:9 msgid "Returns the :class:`VDict` object on which this method was called." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:14 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:15 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:8 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:14 msgid "Normal usage::" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:1 msgid "A utility function used by :meth:`add` to add the key-value pair to :attr:`submob_dict`. Not really meant to be used externally." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:4 msgid "The key of the submobject to be added." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:6 msgid "The mobject associated with the key" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:11 msgid "If the value is not an instance of VMobject" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:3 msgid "All the submobjects associated with the :class:`VDict` object" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:3 msgid "Also, it internally removes the mobject from the `submobjects` :class:`list` of :class:`~.Mobject`, (which is responsible for removing it from the screen)" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VGroup.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:2 msgid "VGroup" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.VGroup``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:1 msgid "A group of vectorized mobjects." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:3 msgid "This can be used to group multiple :class:`~.VMobject` instances together in order to scale, move, ... them together." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:7 msgid "Notes" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:8 msgid "When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:13 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:11 msgid "Examples" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:14 msgid "To add :class:`~.VMobject`s to a :class:`~.VGroup`, you can either use the :meth:`~.VGroup.add` method, or use the `+` and `+=` operators. Similarly, you can subtract elements of a VGroup via :meth:`~.VGroup.remove` method, or `-` and `-=` operators:" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:20::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1 msgid "Checks if all passed elements are an instance of VMobject and then add them to submobjects" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:3 msgid "List of VMobject to add" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0 msgid "Raises" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VMobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:2 msgid "VMobject" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.VMobject``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1 msgid "Bases: :py:class:`manim.mobject.mobject.Mobject`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1 msgid "A vectorized mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:3 msgid "The purpose of background stroke is to have something that won't overlap fill, e.g. For text against some textured background." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:6 msgid "When a color c is set, there will be a second color computed based on interpolating c to WHITE by with sheen_factor, and the display will gradient to this secondary color in the direction of sheen_direction." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:10 msgid "Indicates that it will not be displayed, but that it should count in parent mobject's path" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:12 msgid "This is within a pixel" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1 msgid "Add cubic bezier curve to the path." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:1 msgid "Add a straight line from the last point of VMobject to the given point." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:1 msgid "Add Quadratic bezier curve to the path." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Creates a smooth curve from given points and add it to the VMobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:1 msgid "Adds points to self and vmobject so that they both have the same number of subpaths, with corresponding subpaths each containing the same number of points." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Changes the anchor mode of the bezier curves." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:1 msgid "Determine if two points are close enough to be considered equal." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:1 msgid "Makes sure that points are either directed clockwise or counterclockwise." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:1 msgid "Returns the bezier tuples from an array of points." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "First arg can be either a color, or a tuple/list of colors." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:1 msgid "Returns the anchors of the curves forming the VMobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:1 msgid "Returns anchors1, handles1, handles2, anchors2, where (anchors1[i], handles1[i], handles2[i], anchors2[i]) will be four points defining a cubic bezier curve for any i in range(0, len(anchors1))" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:1 msgid "Return the approximated length of the whole curve." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_color:1 msgid "Returns the color of the :class:`~.Mobject`" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:1 msgid "Gets the functions for the curves of the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:1 msgid "Gets the functions and lengths of the curves for the mobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:1 msgid "Return the end anchors of the bezier curves." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.fill_color:1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_fill_color:1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_fill_opacity:1 msgid "If there are multiple opacities, this returns the first" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:1 msgid "Returns the expression of the nth curve." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:1 msgid "Returns the expression of the nth curve along with its (approximate) length." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:1 msgid "Returns the (approximate) length of the nth curve." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:1 msgid "Returns the array of short line lengths used for length approximation." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:1 msgid "Returns the points defining the nth curve of the vmobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:1 msgid "Returns the number of curves of the vmobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:1 msgid "Returns the start anchors of the bezier curves." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Returns the subcurve of the VMobject between the interval [a, b]." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:1 msgid "Returns subpaths formed by the curves of the VMobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.init_colors:1 msgid "Initializes the colors." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:1 msgid "Inserts n curves to the bezier curves of the vmobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:1 msgid "Given an array of k points defining a bezier curves (anchors and handles), returns points defining exactly k + n bezier curves." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:1 msgid "Gets the point at a proportion along the path of the :class:`VMobject`." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:1 msgid "Returns the proportion along the path of the :class:`VMobject` a particular given point is at." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:1 msgid "Reverts the point direction by inverting the point order." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate:1 msgid "Rotates the :class:`~.Mobject` about a certain point." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:1 msgid "Rotates the direction of the applied sheen." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d away from A, but so that the line from A to H doesn't change." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:1 msgid "Given two sets of anchors and handles, process them to set them as anchors and handles of the VMobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 msgid "Condition is function which takes in one arguments, (x, y, z)." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:1 msgid "Set the fill color and fill opacity of a :class:`VMobject`." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:1 msgid "Given an array of points, set them as corner of the vmobject." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:1 msgid "Applies a color gradient from a direction." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:1 msgid "Sets the direction of the applied sheen." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:116 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:3 msgid "NOTE : the first anchor is not a parameter as by default the end of the last sub-path!" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:5 msgid "first handle" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:7 msgid "second handle" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:9 msgid "anchor" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:12 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:6 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:3 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:7 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:9 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:5 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:5 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:11 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:11 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:9 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:7 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:9 msgid "``self``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:3 msgid "end of the straight line." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:1 msgid "Creates a smooth curve from given points and add it to the VMobject. If two points are passed in, the first is interpreted as a handle, the second as an anchor." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:4 msgid "Points (anchor and handle, or just anchor) to add a smooth curve from" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:10 msgid "If 0 or more than 2 points are given." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:4 msgid "Points are added either by subdividing curves evenly along the subpath, or by creating new subpaths consisting of a single point repeated." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:7 msgid "The object to align points with." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:1 msgid "Changes the anchor mode of the bezier curves. This will modify the handles." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:3 msgid "There can be only two modes, \"jagged\", and \"smooth\"." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:3 msgid "This uses the algorithm from np.isclose(), but expanded here for the 2D point case. NumPy is overkill for such a small question. :param p0: first point :type p0: np.ndarray :param p1: second point :type p1: np.ndarray" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:10 msgid "whether two points considered close." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:4 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:13 msgid "Either ``\"CW\"`` or ``\"CCW\"``." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:3 msgid "self.points is a list of the anchors and handles of the bezier curves of the mobject (ie [anchor1, handle1, handle2, anchor2, anchor3 ..]) This algorithm basically retrieve them by taking an element every n, where n is the number of control points of the bezier curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:8 msgid "Points from which control points will be extracted." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:11 msgid "Bezier control points." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.generate_rgbas_array:1 msgid "First arg can be either a color, or a tuple/list of colors. Likewise, opacity can either be a float, or a tuple of floats. If self.sheen_factor is not zero, and only one color was passed in, a second slightly light color will automatically be added for the gradient" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:3 msgid "The anchors." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:6 msgid "Iterable of the anchors and handles." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:3 msgid "Number of sample points per curve used to approximate the length. More points result in a better approximation." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:5 msgid "The length of the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:3 msgid "The functions for the curves." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:3 msgid "The keyword arguments passed to :meth:`get_nth_curve_function_with_length`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:5 msgid "The functions and lengths of the curves." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:1 msgid "Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:6 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:7 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:9 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:11 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:11 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:7 msgid "Examples" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:7 msgid "The default direction of a :class:`~.Circle` is counterclockwise::" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:3 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:3 msgid "Starting anchors" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:3 msgid "index of the desired curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:6 msgid "expression of the nth bezier curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:3 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:3 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:3 msgid "The index of the desired curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:4 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:4 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:4 msgid "The number of points to sample to find the length." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:6 msgid "* **curve** (*typing.Callable[[float], np.ndarray]*) -- The function for the nth curve. * **length** (:class:`float`) -- The length of the nth curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:6 msgid "**curve** (*typing.Callable[[float], np.ndarray]*) -- The function for the nth curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:7 msgid "**length** (:class:`float`) -- The length of the nth curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:6 msgid "**length** -- The length of the nth curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:6 msgid "The short length-pieces of the nth curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:3 msgid "index of the desired bezier curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:6 msgid "points defininf the nth bezier curve (anchors, handles)" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:3 msgid "number of curves. of the vmobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_point_mobject:1 msgid "The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:1 msgid "Returns the subcurve of the VMobject between the interval [a, b]. The curve is a VMobject itself." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:4 msgid "The lower bound." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:5 msgid "The upper bound." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:7 msgid "The subcurve between of [a, b]" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:3 msgid "Subpaths are ranges of curves with each pair of consecutive curves having their end/start points coincident." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:5 msgid "subpaths." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.init_colors:3 msgid "Gets called upon creation. This is an empty method that can be implemented by subclasses." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:3 msgid "Number of curves to insert." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:3 msgid "Number of desired curves." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:5 msgid "Starting points." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:8 msgid "Points generated." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:3 msgid "The proportion along the the path of the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:5 msgid "The point on the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:8 msgid "If ``alpha`` is not between 0 and 1." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:9 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:10 msgid "If the :class:`VMobject` has no points." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:1 msgid "Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles)" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:4 msgid "The vmobject that will serve as a model." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:6 msgid "upper-bound." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:8 msgid "lower-bound" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:4 msgid "The Cartesian coordinates of the point which may or may not lie on the :class:`VMobject`" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:6 msgid "The proportion along the path of the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:9 msgid "If ``point`` does not lie on the curve." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:3 msgid "Returns self." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:3 msgid "Angle by which the direction of sheen is rotated." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:5 msgid "Axis of rotation." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:10 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:8 msgid "Normal usage::" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:1 msgid "If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d away from A, but so that the line from A to H doesn't change. This is mostly useful in the context of applying a (differentiable) function, to preserve tangency properties. One would pull all the handles closer to their anchors, apply the function then push them out again." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:9 msgid "The factor used for scaling." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:4 msgid "anchors1[i], handles1[i], handles2[i] and anchors2[i] define the i-th bezier curve of the vmobject. There are four hardcoded parameters and this is a problem as it makes the number of points per cubic curve unchangeable from 4 (two anchors and two handles)." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_color:1 msgid "Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:3 msgid "Fill color of the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:4 msgid "Fill opacity of the :class:`VMobject`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:5 msgid "If ``True``, the fill color of all submobjects is also set." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:3 msgid "To achieve that, this algorithm sets handles aligned with the anchors such that the resultant bezier curve will be the segment between the two anchors." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:6 msgid "Array of points that will be set as corners." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:3 msgid "The extent of lustre/gradient to apply. If negative, the gradient starts from black, if positive the gradient starts from white and changes to the current color." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:7 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:3 msgid "Direction from where the gradient is applied." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:2 msgid "VectorizedPoint" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:4 msgid "Qualified name: ``manim.mobject.types.vectorized\\_mobject.VectorizedPoint``" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1::1 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:0 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:6 #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:6 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:2 msgid "vectorized\\_mobject" msgstr "" #: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject:1 msgid "Mobjects that use vector graphics." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30::1 msgid "Convert a curve's elements to submobjects." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30::1 msgid "A :class:`VMobject` composed of dashes instead of lines." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30::1 msgid "A VGroup-like class, also offering submobject access by key, like a python dict" msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30::1 msgid "A group of vectorized mobjects." msgstr "" #: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30::1 msgid "A vectorized mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.value_tracker.ComplexValueTracker.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:2 msgid "ComplexValueTracker" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:4 msgid "Qualified name: ``manim.mobject.value\\_tracker.ComplexValueTracker``" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:1 msgid "Bases: :py:class:`manim.mobject.value_tracker.ValueTracker`" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:1 msgid "Tracks a complex-valued parameter." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:3 msgid "When the value is set through :attr:`animate`, the value will take a straight path from the source point to the destination point." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:7 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:21::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1 msgid "Get the current value of this value tracker as a complex number." msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:21::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.set_value:1 msgid "Sets a new complex value to the ComplexValueTracker" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1::1 msgid "The width of the mobject." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.value_tracker.ValueTracker.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:2 msgid "ValueTracker" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:4 msgid "Qualified name: ``manim.mobject.value\\_tracker.ValueTracker``" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:1 msgid "Bases: :py:class:`manim.mobject.mobject.Mobject`" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:1 msgid "A mobject that can be used for tracking (real-valued) parameters. Useful for animating parameter changes." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:4 msgid "Not meant to be displayed. Instead the position encodes some number, often one which another animation or continual_animation uses for its update function, and by treating it as a mobject it can still be animated and manipulated just like anything else." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:9 msgid "This value changes continuously when animated using the :attr:`animate` syntax." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:12 msgid "Examples" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:41 msgid "You can also link ValueTrackers to updaters. In this case, you have to make sure that the ValueTracker is added to the scene by ``add``" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1 msgid "Get the current value of this ValueTracker." msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.increment_value:1 msgid "Increments (adds) a scalar value to the ValueTracker" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.interpolate:1 msgid "Turns self into an interpolation between mobject1 and mobject2." msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23::1 #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.set_value:1 msgid "Sets a new scalar value to the ValueTracker" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.value_tracker.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.value_tracker.rst:2 msgid "value\\_tracker" msgstr "" #: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker:1 msgid "Simple mobjects that can be used for storing (and updating) a value." msgstr "" #: ../../source/reference/manim.mobject.value_tracker.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.value_tracker.rst:22::1 msgid "Tracks a complex-valued parameter." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.vector_field.ArrowVectorField.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:2 msgid "ArrowVectorField" msgstr "" #: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:4 msgid "Qualified name: ``manim.mobject.vector\\_field.ArrowVectorField``" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:1 msgid "Bases: :py:class:`manim.mobject.vector_field.VectorField`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:1 msgid "A :class:`VectorField` represented by a set of change vectors." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:3 msgid "Vector fields are always based on a function defining the :class:`~.Vector` at every position. The values of this functions is displayed as a grid of vectors. By default the color of each vector is determined by it's magnitude. Other color schemes can be used however." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:8 msgid "The function defining the rate of change at every position of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:9 msgid "The color of the vector field. If set, position-specific coloring is disabled." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:10 msgid "A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:11 msgid "The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:12 msgid "The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:13 msgid "The colors defining the color gradient of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:14 msgid "A sequence of x_min, x_max, delta_x" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:15 msgid "A sequence of y_min, y_max, delta_y" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:16 msgid "A sequence of z_min, z_max, delta_z" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:17 msgid "Enables three_dimensions. Default set to False, automatically turns True if z_range is not None." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:19 msgid "The function determining the displayed size of the vectors. The actual size of the vector is passed, the returned value will be used as display size for the vector. By default this is used to cap the displayed size of vectors to reduce the clutter." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:22 msgid "The opacity of the arrows." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:23 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:8 msgid "Additional arguments to be passed to the :class:`~.Vector` constructor" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:24 msgid "Additional arguments to be passed to the :class:`~.VGroup` constructor" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:28 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:20::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1 msgid "Creates a vector in the vector field." msgstr "" #: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:3 msgid "The created vector is based on the function of the vector field and is rooted in the given point. Color and length fit the specifications of this vector field." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.vector_field.StreamLines.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:2 msgid "StreamLines" msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:4 msgid "Qualified name: ``manim.mobject.vector\\_field.StreamLines``" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:1 msgid "Bases: :py:class:`manim.mobject.vector_field.VectorField`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:1 msgid "StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:3 msgid "Vector fields are always based on a function defining the vector at every position. The values of this functions is displayed by moving many agents along the vector field and showing their trace." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:7 msgid "The function defining the rate of change at every position of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:8 msgid "The color of the vector field. If set, position-specific coloring is disabled." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:9 msgid "A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:10 msgid "The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:11 msgid "The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:12 msgid "The colors defining the color gradient of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:13 msgid "A sequence of x_min, x_max, delta_x" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:14 msgid "A sequence of y_min, y_max, delta_y" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:15 msgid "A sequence of z_min, z_max, delta_z" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:16 msgid "Enables three_dimensions. Default set to False, automatically turns True if z_range is not None." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:18 msgid "The amount by which the starting position of each agent is altered along each axis. Defaults to :code:`delta_y / 2` if not defined." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:19 msgid "The number of agents generated at each starting point." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:20 msgid "The factor by which the distance an agent moves per step is stretched. Lower values result in a better approximation of the trajectories in the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:21 msgid "The time the agents get to move in the vector field. Higher values therefore result in longer stream lines. However, this whole time gets simulated upon creation." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:22 msgid "The maximum number of anchors per line. Lines with more anchors get reduced in complexity, not in length." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:23 msgid "The distance agents can move out of the generation area before being terminated." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:24 msgid "The stroke with of the stream lines." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:25 msgid "The opacity of the stream lines." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:28 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:14 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:11 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:13 msgid "Examples" msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:10 msgid "The creation animation of the stream lines." msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:1 msgid "End the stream line animation smoothly." msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:1 msgid "Animates the stream lines using an updater." msgstr "" #: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:3 msgid "The stream lines appear in random order." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:5 msgid "The lag ratio of the animation. If undefined, it will be selected so that the total animation length is 1.5 times the run time of each stream line creation." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:7 msgid "The run time of every single stream line creation. The runtime of the whole animation might be longer due to the `lag_ratio`. If undefined, the virtual time of the stream lines is used as run time." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:3 msgid "Returns an animation resulting in fully displayed stream lines without a noticeable cut." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:5 msgid "The animation fading out the running stream animation." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0 msgid "Raises" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:8 msgid "if no stream line animation is running" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:3 msgid "The stream lines will continuously flow" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:5 msgid "If `True` the animation is initialized line by line. Otherwise it starts with all lines shown." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:7 msgid "At `flow_speed=1` the distance the flow moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of this flow." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:8 msgid "The proportion of the stream line shown while being animated" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:9 msgid "The rate function of each stream line flashing" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.vector_field.VectorField.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:2 msgid "VectorField" msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:4 msgid "Qualified name: ``manim.mobject.vector\\_field.VectorField``" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:1 msgid "Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:1 msgid "A vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:3 msgid "Vector fields are based on a function defining a vector at every position. This class does by default not include any visible elements but provides methods to move other :class:`~.Mobject` s along the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0 msgid "Parameters" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:7 msgid "The function defining the rate of change at every position of the `VectorField`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:8 msgid "The color of the vector field. If set, position-specific coloring is disabled." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:9 msgid "A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:10 msgid "The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:11 msgid "The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:12 msgid "The colors defining the color gradient of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:13 msgid "Additional arguments to be passed to the :class:`~.VGroup` constructor" msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1 msgid "Scale the vector field to fit a coordinate system." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:1 msgid "Generate an image that displays the vector field." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:1 msgid "Get an update function to move a :class:`~.Mobject` along the vector field." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:1 msgid "Generates a gradient of rgbas as a numpy array" msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:1 msgid "Nudge a :class:`~.Mobject` along the vector field." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:1 msgid "Apply a nudge along the vector field to all submobjects." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:1 msgid "Scale a vector field function." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:1 msgid "Shift a vector field function." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:1 msgid "Start continuously moving all submobjects along the vector field." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29::1 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:1 msgid "Stops the continuous movement started using :meth:`start_submobject_movement`." msgstr "" #: ../../source/reference/manim.mobject.vector_field.VectorField.rst:31 msgid "Attributes" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1::1 msgid "Used to animate the application of any method of :code:`self`." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1::1 msgid "The depth of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1::1 msgid "If there are multiple colors (for gradient) this returns the first one" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1::1 msgid "The height of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1::1 msgid "The width of the mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:3 msgid "This method is useful when the vector field is defined in a coordinate system different from the one used to display the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:6 msgid "This method can only be used once because it transforms the origin of each vector." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:8 msgid "The coordinate system to fit the vector field to." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:3 msgid "The color at each position is calculated by passing the positing through a series of steps: Calculate the vector field function at that position, map that vector to a single value using `self.color_scheme` and finally generate a color from that value using the color gradient." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:9 msgid "The stepsize at which pixels get included in the image. Lower values give more accurate results, but may take a long time to compute." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:0 msgid "Returns" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:12 msgid "The vector field image." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:0 msgid "Return type" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:3 msgid "When used with :meth:`~.Mobject.add_updater`, the mobject will move along the vector field, where its speed is determined by the magnitude of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:5 msgid "At `speed=1` the distance a mobject moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of such a mobject." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:6 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:7 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:6 msgid "Whether to move the mobject along the vector field. See :meth:`nudge` for details." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:8 msgid "The update function." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:3 msgid "start value used for inverse interpolation at :func:`~.inverse_interpolate`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:4 msgid "end value used for inverse interpolation at :func:`~.inverse_interpolate`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:5 msgid "list of colors to generate the gradient" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:3 msgid "The mobject to move along the vector field" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:4 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:3 msgid "A scalar to the amount the mobject is moved along the vector field. The actual distance is based on the magnitude of the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:6 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:5 msgid "The amount of steps the whole nudge is divided into. Higher values give more accurate approximations." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:8 msgid "Whether to move the mobject along the vector field. If `False` the vector field takes effect on the center of the given :class:`~.Mobject`. If `True` the vector field takes effect on the points of the individual points of the :class:`~.Mobject`, potentially distorting it." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:14 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:9 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:8 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:3 msgid "This vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:18 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:7 msgid "Examples" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:3 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:3 msgid "The function defining a vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:4 msgid "The scalar to be applied to the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:21 msgid "The scaled vector field function." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:22 #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:7 msgid "`Callable[[np.ndarray], np.ndarray]`" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:4 msgid "The shift to be applied to the vector field." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:6 msgid "The shifted vector field function." msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:3 msgid "Calling this method multiple times will result in removing the previous updater created by this method." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.mobject.vector_field.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.mobject.vector_field.rst:2 msgid "vector\\_field" msgstr "" #: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field:1 msgid "Mobjects representing vector fields." msgstr "" #: ../../source/reference/manim.mobject.vector_field.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.mobject.vector_field.rst:24::1 msgid "A :class:`VectorField` represented by a set of change vectors." msgstr "" #: ../../source/reference/manim.mobject.vector_field.rst:24::1 msgid "StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.moving_camera_scene.MovingCameraScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:2 msgid "MovingCameraScene" msgstr "" #: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:4 msgid "Qualified name: ``manim.scene.moving\\_camera\\_scene.MovingCameraScene``" msgstr "" #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene:1 msgid "Bases: :py:class:`manim.scene.scene.Scene`" msgstr "" #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene:1 msgid "This is a Scene, with special configurations and properties that make it suitable for cases where the camera must be moved around." msgstr "" #: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:20::1 #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene.get_moving_mobjects:1 msgid "This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed." msgstr "" #: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:22 msgid "Attributes" msgstr "" #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene.get_moving_mobjects:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.moving_camera_scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.moving_camera_scene.rst:2 msgid "moving\\_camera\\_scene" msgstr "" #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene:1 msgid "A scene whose camera can be moved around." msgstr "" #: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene:9 msgid "Examples" msgstr "" #: ../../source/reference/manim.scene.moving_camera_scene.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.reconfigurable_scene.ReconfigurableScene.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.scene.reconfigurable_scene.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.scene.sample_space_scene.SampleSpaceScene.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.scene.sample_space_scene.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.scene.scene.RerunSceneHandler.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:2 msgid "RerunSceneHandler" msgstr "" #: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:4 msgid "Qualified name: ``manim.scene.scene.RerunSceneHandler``" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler:1 msgid "Bases: :py:class:`watchdog.events.FileSystemEventHandler`" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler:1 msgid "A class to handle rerunning a Scene after the input file is modified." msgstr "" #: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:14 msgid "Methods" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:1::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:1 msgid "Called when a file or directory is modified." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.scene.Scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.scene.Scene.rst:2 msgid "Scene" msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:4 msgid "Qualified name: ``manim.scene.scene.Scene``" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:1 msgid "A Scene is the canvas of your animation." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:3 msgid "The primary role of :class:`Scene` is to provide the user with tools to manage mobjects and animations. Generally speaking, a manim script consists of a class that derives from :class:`Scene` whose :meth:`Scene.construct` method is overridden by the user's code." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:8 msgid "Mobjects are displayed on screen by calling :meth:`Scene.add` and removed from screen by calling :meth:`Scene.remove`. All mobjects currently on screen are kept in :attr:`Scene.mobjects`. Animations are played by calling :meth:`Scene.play`." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:12 msgid "A :class:`Scene` is rendered internally by calling :meth:`Scene.render`. This in turn calls :meth:`Scene.setup`, :meth:`Scene.construct`, and :meth:`Scene.tear_down`, in that order." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:16 msgid "It is not recommended to override the ``__init__`` method in user Scenes. For code that should be ran before a Scene is rendered, use :meth:`Scene.setup` instead." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:20 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:12 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:12 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:14 msgid "Examples" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:21 msgid "Override the :meth:`Scene.construct` method with your code." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:1 msgid "Mobjects will be displayed, from background to foreground in the order with which they are added." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:1 msgid "Adds a single mobject to the foreground, and internally to the list foreground_mobjects, and mobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:1 msgid "Adds mobjects to the foreground, and internally to the list foreground_mobjects, and mobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:1 msgid "This method is used to add a sound to the animation." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:1 msgid "Adds an entry in the corresponding subcaption file at the current time stamp." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:1 msgid "Add an update function to the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.begin_animations:1 msgid "Start the animations of the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:1 msgid "Removes the mobject from the scene and adds them to the back of the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:1 msgid "Adds the passed mobjects to the scene again, pushing them to he front of the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:1 msgid "Removes all mobjects present in self.mobjects and self.foreground_mobjects from the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:1 msgid "Given a list of animations, compile the corresponding static and moving mobjects, and gather the animation durations." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:1 msgid "Creates _MethodAnimations from any _AnimationBuilders and updates animation kwargs with kwargs passed to play()." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:1 msgid "Add content to the Scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:1 msgid "Gets attributes of a scene given the attribute's identifier/name." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 msgid "Returns list of family-members of all mobjects in scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:1 msgid "Gets all moving mobjects in the passed animation(s)." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:1 msgid "Given a list of mobjects and a list of mobjects to be removed, this filters out the removable mobjects from the list of mobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:1 msgid "Gets the total run time for a list of animations." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 msgid "You will hardly use this when making your own animations." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:1 msgid "Returns all mobjects which are not submobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.interactive_embed:1 msgid "Like embed(), but allows for screen interaction." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.is_current_animation_frozen_frame:1 msgid "Returns whether the current animation produces a static frame (generally a Wait)." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 msgid "Create separation here; the last section gets finished and a new one gets created." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:1 msgid "Pauses the scene (i.e., displays a frozen frame)." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:1 msgid "Plays an animation in this scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:1 msgid "This method is used to prep the animations for rendering, apply the arguments and parameters required to them, render them, and write them to the video file." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:1 msgid "Removes mobjects in the passed list of mobjects from the scene and the foreground, by removing them from \"mobjects\" and \"foreground_mobjects\"" msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:1 msgid "Removes a single mobject from the foreground, and internally from the list foreground_mobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:1 msgid "Removes mobjects from the foreground, and internally from the list foreground_mobjects." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:1 msgid "Remove an update function from the scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:1 msgid "Renders this Scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:4 msgid "tl:wr" msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.setup:1 msgid "This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup involved before the construct method is called." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:1 msgid "Returns True if the mobjects of this scene should be updated." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.tear_down:1 msgid "This is meant to be implemented by any scenes which are commonly subclassed, and have some common method to be invoked before the scene ends." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:1 msgid "Begins updating all mobjects in the Scene." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:1 msgid "Run all scene updater functions." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:1 msgid "Plays a \"no operation\" animation." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:74::1 msgid "Like a wrapper for wait()." msgstr "" #: ../../source/reference/manim.scene.scene.Scene.rst:76 msgid "Attributes" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:4 msgid "Mobjects to add." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0 msgid "Returns" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:7 msgid "The same scene after adding the Mobjects in." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.begin_animations:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.is_current_animation_frozen_frame:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:0 msgid "Return type" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:4 msgid "The Mobject to add to the foreground." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:7 msgid "The Scene, with the foreground mobject added." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:4 msgid "The Mobjects to add to the foreground." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:7 msgid "The Scene, with the foreground mobjects added." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:3 msgid "The path to the sound file." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:5 msgid "The offset in the sound file after which the sound can be played." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:8 msgid "Amplification of the sound." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:29 msgid "Download the resource for the previous example `here `_ ." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:4 msgid "The current time stamp is obtained from ``Scene.renderer.time``." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:6 msgid "The subcaption content." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:7 msgid "The duration (in seconds) for which the subcaption is shown." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:8 msgid "This offset (in seconds) is added to the starting time stamp of the subcaption." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:13 msgid "This example illustrates both possibilities for adding subcaptions to Manimations::" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:3 msgid "The scene updater functions are run every frame, and they are the last type of updaters to run." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:8 msgid "When using the Cairo renderer, scene updaters that modify mobjects are not detected in the same way that mobject updaters are. To be more concrete, a mobject only modified via a scene updater will not necessarily be added to the list of *moving mobjects* and thus might not be updated every frame." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:15 msgid "TL;DR: Use mobject updaters to update mobjects." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:17 msgid "The updater function. It takes a float, which is the time difference since the last update (usually equal to the frame rate)." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:4 msgid "The mobject(s) to push to the back of the scene." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:7 msgid "The Scene, with the mobjects pushed to the back of the scene." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:4 msgid "The mobject(s) to bring to the front of the scene." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:7 msgid "The Scene, with the mobjects brought to the front of the scene." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:4 msgid "The Scene, with all of its mobjects in self.mobjects and self.foreground_mobjects removed." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:4 msgid "This also begins the animations." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:6 msgid "Whether the rendering should be skipped, by default False" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:9 msgid "None if there is nothing to play, or self otherwise." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:4 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:8 #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:3 msgid "Animations to be played." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:6 msgid "Configuration for the call to play()." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:9 msgid "Tuple[:class:`Animation`]" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:3 msgid "From within :meth:`Scene.construct`, display mobjects on screen by calling :meth:`Scene.add` and remove them from screen by calling :meth:`Scene.remove`. All mobjects currently on screen are kept in :attr:`Scene.mobjects`. Play animations by calling :meth:`Scene.play`." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:9 msgid "Notes" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:10 msgid "Initialization code should go in :meth:`Scene.setup`. Termination code should go in :meth:`Scene.tear_down`." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:15 msgid "A typical manim script includes a class derived from :class:`Scene` with an overridden :meth:`Scene.contruct` method:" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:3 msgid "Name(s) of the argument(s) to return the attribute of." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:6 msgid "List of attributes of the passed identifiers." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:1 msgid "Returns list of family-members of all mobjects in scene. If a Circle() and a VGroup(Rectangle(),Triangle()) were added, it returns not only the Circle(), Rectangle() and Triangle(), but also the VGroup() object." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:6 msgid "List of mobject family members." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:3 msgid "The animations to check for moving mobjects." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:6 msgid "The list of mobjects that could be moving in the Animation(s)" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:4 msgid "The Mobjects to check." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:6 msgid "The list of mobjects to remove." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:9 msgid "The list of mobjects with the mobjects to remove removed." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:3 msgid "A list of the animations whose total ``run_time`` is to be calculated." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:7 msgid "The total ``run_time`` of all of the animations in the list." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:1 msgid "You will hardly use this when making your own animations. This method is for Manim's internal use." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:4 msgid "Returns a CommandLine ProgressBar whose ``fill_time`` is dependent on the ``run_time`` of an animation, the iterations to perform in that animation and a bool saying whether or not to consider the skipped animations." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:10 msgid "The ``run_time`` of the animation." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:12 msgid "The number of iterations in the animation." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:14 msgid "Whether or not to show skipped animations in the progress bar." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:17 msgid "The CommandLine Progress Bar." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:3 msgid "List of top level mobjects." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:1 msgid "Create separation here; the last section gets finished and a new one gets created. ``skip_animations`` skips the rendering of all animations in this section. Refer to :doc:`the documentation
` on how to use sections." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:3 msgid "This is an alias for :meth:`.wait` with ``frozen_frame`` set to ``True``." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:6 msgid "The duration of the pause." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:4 msgid "The content of the external subcaption that should be added during the animation." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:6 msgid "The duration for which the specified subcaption is added. If ``None`` (the default), the run time of the animation is taken." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:9 msgid "An offset (in seconds) for the start time of the added subcaption." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:11 msgid "All other keywords are passed to the renderer." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:5 msgid "Animation or mobject with mobject method and params" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:6 msgid "named parameters affecting what was passed in ``args``, e.g. ``run_time``, ``lag_ratio`` and so on." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:5 msgid "The mobjects to remove." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:4 msgid "The mobject to remove from the foreground." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:7 msgid "The Scene, with the foreground mobject removed." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:4 msgid "The mobject(s) to remove from the foreground." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:7 msgid "The Scene, with the foreground mobjects removed." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:3 msgid "The updater function to be removed." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:3 msgid "If true, opens scene in a file viewer." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:2 msgid "If your scene has a Group(), and you removed a mobject from the Group, this dissolves the group and puts the rest of the mobjects directly in self.mobjects or self.foreground_mobjects." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:6 msgid "In cases where the scene contains a group, e.g. Group(m1, m2, m3), but one of its submobjects is removed, e.g. scene.remove(m1), the list of mobjects will be edited to contain other submobjects, but not m1, e.g. it will now insert m2 and m3 to where the group once was." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:11 msgid "The Mobject to remove." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:13 msgid "The list of mobjects (\"mobjects\", \"foreground_mobjects\" etc) to remove from." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:15 msgid "Whether the mobject's families should be recursively extracted." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:18 msgid "The Scene mobject with restructured Mobjects." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:3 msgid "In particular, this checks whether" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:5 msgid "the :attr:`always_update_mobjects` attribute of :class:`.Scene` is set to ``True``," msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:7 msgid "the :class:`.Scene` itself has time-based updaters attached," msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:8 msgid "any mobject in this :class:`.Scene` has time-based updaters attached." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:10 msgid "This is only called when a single Wait animation is played." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:3 msgid "Change in time between updates. Defaults (mostly) to 1/frames_per_second" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:3 msgid "Among all types of update functions (mobject updaters, mesh updaters, scene updaters), scene update functions are called last." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:6 msgid "Scene time since last update." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:3 msgid "The run time of the animation." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:4 msgid "A function without positional arguments that is evaluated every time a frame is rendered. The animation only stops when the return value of the function is truthy. Overrides any value passed to ``duration``." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:7 msgid "If True, updater functions are not evaluated, and the animation outputs a frozen frame. If False, updater functions are called and frames are rendered as usual. If None (the default), the scene tries to determine whether or not the frame is frozen on its own." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:1 msgid "Like a wrapper for wait(). You pass a function that determines whether to continue waiting, and a max wait time if that is never fulfilled." msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:5 msgid "The function whose boolean return value determines whether to continue waiting" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.scene.rst:2 msgid "scene" msgstr "" #: ../../../manim/scene/scene.py:docstring of manim.scene.scene:1 msgid "Basic canvas for animations." msgstr "" #: ../../source/reference/manim.scene.scene.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.scene.scene.rst:22::1 msgid "A class to handle rerunning a Scene after the input file is modified." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.scene_file_writer.SceneFileWriter.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:2 msgid "SceneFileWriter" msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:4 msgid "Qualified name: ``manim.scene.scene\\_file\\_writer.SceneFileWriter``" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:1 msgid "SceneFileWriter is the object that actually writes the animations played, into video files, using FFMPEG. This is mostly for Manim's internal use. You will rarely, if ever, have to use the methods for this class, unless tinkering with the very fabric of Manim's reality." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:9 msgid "used to segment scene" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0 msgid "type" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:11 msgid "list of :class:`.Section`" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:15 msgid "where are section videos stored" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:17 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:23 msgid "str" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:21 msgid "name of movie without extension and basis for section video names" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:32 msgid "Some useful attributes are:" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:26 msgid "\"write_to_movie\" (bool=False)" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:27 msgid "Whether or not to write the animations into a video file." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:28 msgid "\"movie_file_extension\" (str=\".mp4\")" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:29 msgid "The file-type extension of the outputted video." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:32 msgid "\"partial_movie_files\"" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:31 msgid "List of all the partial-movie files." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:1 msgid "This method adds an audio segment from an AudioSegment type object and suitable parameters." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 msgid "Adds a new partial movie file path to `scene.partial_movie_files` and current section from a hash." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:1 msgid "This method adds an audio segment from a sound file." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:1 msgid "Used internally by manim to stream the animation to FFMPEG for displaying or writing to a file." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.clean_cache:1 msgid "Will clean the cache by removing the oldest partial_movie_files." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.close_movie_pipe:1 msgid "Used internally by Manim to gracefully stop writing to FFMPEG's input buffer" msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_movie:1 msgid "Used internally by Manim to combine the separate partial movie files that make up a Scene into a single video file for that Scene." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_section_videos:1 msgid "Concatenate partial movie files for each section." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.create_audio_segment:1 msgid "Creates an empty, silent, Audio Segment." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:1 msgid "Internally used by Manim to stop streaming to FFMPEG gracefully." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 msgid "Finishes writing to the FFMPEG buffer or writing images to output directory." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish_last_section:1 msgid "Delete current section if it is empty." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.flush_cache_directory:1 msgid "Delete all the cached partial movie files" msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:1 msgid "Get the name of the resolution directory directly containing the video file." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_audio:1 msgid "Preps the writer for adding audio to the movie." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:1 msgid "Initialise output directories." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:1 msgid "Will check if a file named with `hash_invocation` exists." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:1 msgid "Create segmentation cut here." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.open_movie_pipe:1 msgid "Used internally by Manim to initialise FFMPEG and begin writing to FFMPEG's input buffer." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.print_file_ready_message:1 msgid "Prints the \"File Ready\" message to STDOUT." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 msgid "The name is a misnomer." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_frame:1 msgid "Used internally by Manim to write a frame to the FFMPEG input buffer." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46::1 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_subcaption_file:1 msgid "Writes the subcaption file." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:48 msgid "Attributes" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_frame:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:4 msgid "The audio segment to add" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:6 msgid "the timestamp at which the sound should be added." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:9 msgid "The gain of the segment from the background." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:1 msgid "Adds a new partial movie file path to `scene.partial_movie_files` and current section from a hash. This method will compute the path from the hash. In addition to that it adds the new animation to the current section." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:4 msgid "Hash of the animation." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:3 msgid "The path to the sound file." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:5 msgid "The timestamp at which the audio should be added." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:7 msgid "The gain of the given audio segment." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:9 msgid "This method uses add_audio_segment, so any keyword arguments used there can be referenced here." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:4 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:4 msgid "Whether or not to write to a video file." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_section_videos:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish_last_section:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:0 msgid "Return type" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish:1 msgid "Finishes writing to the FFMPEG buffer or writing images to output directory. Combines the partial movie files into the whole scene. If save_last_frame is True, saves the last frame in the default image directory." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:4 msgid "This method gets the name of the directory that immediately contains the video file. This name is ``p``. For example, if you are rendering an 854x480 px animation at 15fps, the name of the directory that immediately contains the video, file will be ``480p15``." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:10 msgid "The file structure should look something like::" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:0 #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0 msgid "Returns" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:20 msgid "The name of the directory." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:4 msgid "Notes" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:5 msgid "The directories are read from ``config``, for example ``config['media_dir']``. If the target directories don't already exist, they will be created." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:3 msgid "The hash corresponding to an invocation to either `scene.play` or `scene.wait`." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:6 msgid "Whether the file exists." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:1 msgid "The name is a misnomer. This method saves the image passed to it as an in the default image directory." msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:4 msgid "The pixel array of the image to save." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.scene_file_writer.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.scene_file_writer.rst:2 msgid "scene\\_file\\_writer" msgstr "" #: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer:1 msgid "The interface between scenes and ffmpeg." msgstr "" #: ../../source/reference/manim.scene.scene_file_writer.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.section.DefaultSectionType.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.section.DefaultSectionType.rst:2 msgid "DefaultSectionType" msgstr "" #: ../../source/reference/manim.scene.section.DefaultSectionType.rst:4 msgid "Qualified name: ``manim.scene.section.DefaultSectionType``" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:1 msgid "Bases: :py:class:`str`, :py:class:`enum.Enum`" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:1 msgid "The type of a section can be used for third party applications. A presentation system could for example use the types to created loops." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:5 msgid "Examples" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:6 msgid "This class can be reimplemented for more types::" msgstr "" #: ../../source/reference/manim.scene.section.DefaultSectionType.rst:16 msgid "Attributes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.section.Section.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.section.Section.rst:2 msgid "Section" msgstr "" #: ../../source/reference/manim.scene.section.Section.rst:4 msgid "Qualified name: ``manim.scene.section.Section``" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:1 msgid "A :class:`.Scene` can be segmented into multiple Sections. Refer to :doc:`the documentation
` for more info. It consists of multiple animations." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:0 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:7 msgid "Can be used by a third party applications to classify different types of sections." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:11 msgid "Path to video file with animations belonging to section relative to sections directory. If ``None``, then the section will not be saved." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:16 msgid "Human readable, non-unique name for this section." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:20 msgid "Skip rendering the animations in this section when ``True``." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:24 msgid "Animations belonging to this section." msgstr "" #: ../../source/reference/manim.scene.section.Section.rst:14 msgid "Methods" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1::1 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1 msgid "Return all partial movie files that are not ``None``." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1::1 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:1 msgid "Get dictionary representation with metadata of output video." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1::1 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.is_empty:1 msgid "Check whether this section is empty." msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:0 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:0 #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.is_empty:0 msgid "Return type" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:3 msgid "The output from this function is used from every section to build the sections index file. The output video must have been created in the ``sections_dir`` before executing this method. This is the main part of the Segmented Video API." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.section.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.section.rst:2 msgid "section" msgstr "" #: ../../../manim/scene/section.py:docstring of manim.scene.section:1 msgid "building blocks of segmented video API" msgstr "" #: ../../source/reference/manim.scene.section.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.scene.section.rst:22::1 msgid "The type of a section can be used for third party applications." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.three_d_scene.SpecialThreeDScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:2 msgid "SpecialThreeDScene" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:4 msgid "Qualified name: ``manim.scene.three\\_d\\_scene.SpecialThreeDScene``" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:1 msgid "Bases: :py:class:`manim.scene.three_d_scene.ThreeDScene`" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:1 msgid "An extension of :class:`ThreeDScene` with more settings." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:3 msgid "It has some extra configuration for axes, spheres, and an override for low quality rendering. Further key differences are:" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:7 msgid "The camera shades applicable 3DMobjects by default, except if rendering in low quality." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:9 msgid "Some default params for Spheres and Axes have been added." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:1 msgid "Return a set of 3D axes." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:1 msgid "Returns the default_angled_camera position." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:1 msgid "Returns a sphere with the passed keyword arguments as properties." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.set_camera_to_default_position:1 msgid "Sets the camera to its default position." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:25 msgid "Attributes" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0 msgid "Returns" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:3 msgid "A set of 3D axes." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0 msgid "Return type" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:3 msgid "Dictionary of phi, theta, focal_distance, and gamma." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:3 msgid "Any valid parameter of :class:`~.Sphere` or :class:`~.Surface`." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:5 msgid "The sphere object." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.three_d_scene.ThreeDScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:2 msgid "ThreeDScene" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:4 msgid "Qualified name: ``manim.scene.three\\_d\\_scene.ThreeDScene``" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene:1 msgid "Bases: :py:class:`manim.scene.scene.Scene`" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene:1 msgid "This is a Scene, with special configurations and properties that make it suitable for Three Dimensional Scenes." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 msgid "This method is used to prevent the rotation and movement of mobjects as the camera moves around." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 msgid "This method is used to prevent the rotation and tilting of mobjects as the camera moves around." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:1 msgid "This method creates a 3D camera rotation illusion around the current camera orientation." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:1 msgid "This method begins an ambient rotation of the camera about the Z_AXIS, in the anticlockwise direction" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:1 msgid "This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:1 msgid "This method animates the movement of the camera to the given spherical coordinates." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 msgid "This method undoes what add_fixed_in_frame_mobjects does." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 msgid "This method \"unfixes\" the orientation of the mobjects passed, meaning they will no longer be at the same angle relative to the camera." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:1 msgid "This method sets the orientation of the camera in the scene." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_to_default_angled_camera_orientation:1 msgid "This method sets the default_angled_camera_orientation to the keyword arguments passed, and sets the camera to that orientation." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.stop_3dillusion_camera_rotation:1 msgid "This method stops all illusion camera rotations." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31::1 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.stop_ambient_camera_rotation:1 msgid "This method stops all ambient camera rotation." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:33 msgid "Attributes" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:1 msgid "This method is used to prevent the rotation and movement of mobjects as the camera moves around. The mobject is essentially overlaid, and is not impacted by the camera's movement in any way." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:0 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_to_default_angled_camera_orientation:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:6 msgid "The Mobjects whose orientation must be fixed." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:1 msgid "This method is used to prevent the rotation and tilting of mobjects as the camera moves around. The mobject can still move in the x,y,z directions, but will always be at the angle (relative to the camera) that it was at when it was passed through this method.)" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:7 msgid "The Mobject(s) whose orientation must be fixed." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:9 msgid "Some valid kwargs are use_static_center_func : bool center_func : function" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:11 msgid "Some valid kwargs are" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:11 msgid "use_static_center_func : bool center_func : function" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:4 msgid "The rate at which the camera rotation illusion should operate." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:5 msgid "The polar angle the camera should move around. Defaults to the current phi angle." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:7 msgid "The azimutal angle the camera should move around. Defaults to the current theta angle." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:4 msgid "The rate at which the camera should rotate about the Z_AXIS. Negative rate means clockwise rotation." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:7 msgid "one of 3 options: [\"theta\", \"phi\", \"gamma\"]. defaults to theta." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:4 msgid "The animations whose mobjects will be checked." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:4 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:3 msgid "The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:6 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:5 msgid "The azimuthal angle i.e the angle that spins the camera around the Z_AXIS." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:8 msgid "The radial focal_distance between ORIGIN and Camera." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:10 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:9 msgid "The rotation of the camera about the vector from the ORIGIN to the Camera." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:12 msgid "The zoom factor of the camera." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:14 #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:13 msgid "The new center of the camera frame in cartesian coordinates." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:16 msgid "Any other animations to be played at the same time." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:1 msgid "This method undoes what add_fixed_in_frame_mobjects does. It allows the mobject to be affected by the movement of the camera." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:5 msgid "The Mobjects whose position and orientation must be unfixed." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:1 msgid "This method \"unfixes\" the orientation of the mobjects passed, meaning they will no longer be at the same angle relative to the camera. This only makes sense if the mobject was passed through add_fixed_orientation_mobjects first." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:6 msgid "The Mobjects whose orientation must be unfixed." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:7 msgid "The focal_distance of the Camera." msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:11 msgid "The zoom factor of the scene." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.three_d_scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.three_d_scene.rst:2 msgid "three\\_d\\_scene" msgstr "" #: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene:1 msgid "A scene suitable for rendering three-dimensional objects and animations." msgstr "" #: ../../source/reference/manim.scene.three_d_scene.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.scene.three_d_scene.rst:22::1 msgid "An extension of :class:`ThreeDScene` with more settings." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.vector_space_scene.LinearTransformationScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:2 msgid "LinearTransformationScene" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:4 msgid "Qualified name: ``manim.scene.vector\\_space\\_scene.LinearTransformationScene``" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:1 msgid "Bases: :py:class:`manim.scene.vector_space_scene.VectorScene`" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:1 msgid "This scene contains special methods that make it especially suitable for showing linear transformations." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:4 msgid "Whether or not to include the background plane in the scene." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:5 msgid "Whether or not to include the foreground plane in the scene." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:6 msgid "Parameters to be passed to :class:`NumberPlane` to adjust the background plane." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:7 msgid "Parameters to be passed to :class:`NumberPlane` to adjust the foreground plane." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:8 msgid "Whether or not to include the coordinates for the background plane." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:9 msgid "Whether to show the basis x_axis -> ``i_hat`` and y_axis -> ``j_hat`` vectors." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:10 msgid "The ``stroke_width`` of the basis vectors." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:11 msgid "The color of the ``i_hat`` vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:12 msgid "The color of the ``j_hat`` vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:13 msgid "Indicates the previous position of the basis vectors following a transformation." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:16 msgid "Examples" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:1 msgid "Adds the mobjects to the special list self.background_mobjects." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:1 msgid "Adds the mobjects to the special list self.foreground_mobjects." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:1 msgid "Adds the mobject to the special list self.moving_mobject, and adds a property to the mobject called mobject.target, which keeps track of what the mobject will move to or become etc." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:1 msgid "Adds mobjects to a separate list that can be tracked, if these mobjects have some extra importance." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 msgid "Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding it as a local variable of self." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:1 msgid "Method for creating, and animating the addition of a transformable label for the vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:1 msgid "Adds the mobjects to the special list self.transformable_mobjects." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:1 msgid "Adds a unit square to the scene via self.get_unit_square." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:1 msgid "Adds a vector to the scene, and puts it in the special list self.moving_vectors." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:1 msgid "Applies the given function to each of the mobjects in self.transformable_mobjects, and plays the animation showing this." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:1 msgid "This method applies the linear transformation represented by the inverse of the passed matrix to the number plane, and each vector/similar mobject on it." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:1 msgid "Applies the inverse of the transformation represented by the given transposed matrix to the number plane and each vector/similar mobject on it." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:1 msgid "Applies the transformation represented by the given matrix to the number plane, and each vector/similar mobject on it." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:1 msgid "Applies the non-linear transformation represented by the given function to the number plane and each vector/similar mobject on it." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:1 msgid "Applies the transformation represented by the given transposed matrix to the number plane, and each vector/similar mobject on it." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:1 msgid "Returns a function corresponding to the linear transformation represented by the matrix passed." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 msgid "This method returns an animation that moves a mobject in \"self.moving_mobjects\" to its corresponding .target value." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 msgid "This method returns an animation that moves an arbitrary mobject in \"pieces\" to its corresponding .target value." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:1 msgid "This method returns an animation that moves all labels in \"self.transformable_labels\" to its corresponding .target ." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:1 msgid "Returns a function corresponding to the linear transformation represented by the transposed matrix passed." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:1 msgid "Returns a unit square for the current NumberPlane." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 msgid "This method returns an animation that moves a mobject in \"self.moving_vectors\" to its corresponding .target value." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.setup:1 msgid "This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup involved before the construct method is called." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:1 msgid "Returns a column matrix indicating the vector coordinates, after writing them to the screen, and adding them to the special list self.foreground_mobjects" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:46 msgid "Attributes" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:4 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:4 msgid "The mobjects to add to the list." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:4 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:7 msgid "The mobjects to add to the list" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:9 msgid "What the moving_mobject goes to, etc." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:4 msgid "The special list to which you want to add these mobjects." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:7 msgid "The mobjects to add." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:1 msgid "Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding it as a local variable of self. Returns the Scene." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:5 msgid "What the title should be." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:7 msgid "How much the title should be scaled by." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:9 msgid "Whether or not to animate the addition." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0 msgid "Returns" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:12 msgid "The scene with the title added to it." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0 msgid "Return type" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:4 msgid "The vector for which the label must be added." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:6 msgid "The MathTex/string of the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:8 msgid "The name to give the transformation as a label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:10 msgid "What the label should display after a Linear Transformation" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:12 msgid "Any valid keyword argument of get_vector_label" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:14 msgid "The MathTex of the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:4 msgid "Whether or not to animate the addition with DrawBorderThenFill." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:6 msgid "Any valid keyword arguments of self.get_unit_square()" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:9 msgid "The unit square." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:4 msgid "It can be a pre-made graphical vector, or the coordinates of one." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:7 msgid "The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:11 msgid "Any valid keyword argument of VectorScene.add_vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:13 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:5 msgid "The arrow representing the vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:5 msgid "The function that affects each point of each mobject in self.transformable_mobjects." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:8 msgid "Any other animations that need to be played simultaneously with this." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:11 msgid "Any valid keyword argument of a self.play() call." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:5 msgid "The matrix whose inverse is to be applied." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:7 msgid "Any valid keyword argument of self.apply_matrix()" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:5 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:5 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:5 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:4 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:5 msgid "The matrix." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:7 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:7 msgid "Any valid keyword argument of self.apply_transposed_matrix()" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:5 msgid "The function." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:7 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:7 msgid "Any valid keyword argument of self.apply_function()" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:1 msgid "This method returns an animation that moves a mobject in \"self.moving_mobjects\" to its corresponding .target value. func is a function that determines where the .target goes." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:5 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:5 msgid "The function that determines where the .target of the moving mobject goes." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:9 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:9 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:4 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:9 msgid "The animation of the movement." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:1 msgid "This method returns an animation that moves an arbitrary mobject in \"pieces\" to its corresponding .target value. If self.leave_ghost_vectors is True, ghosts of the original positions/mobjects are left on screen" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:6 msgid "The pieces for which the movement must be shown." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:3 msgid "The string of the hex color code of the color wanted." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:5 msgid "The opacity of the square" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:7 msgid "The stroke_width in pixels of the border of the square" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:1 msgid "This method returns an animation that moves a mobject in \"self.moving_vectors\" to its corresponding .target value. func is a function that determines where the .target goes." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:7 msgid "Any valid keyword arguments of VectorScene.write_vector_coordinates" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.vector_space_scene.VectorScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:2 msgid "VectorScene" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:4 msgid "Qualified name: ``manim.scene.vector\\_space\\_scene.VectorScene``" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene:1 msgid "Bases: :py:class:`manim.scene.scene.Scene`" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:1 msgid "Adds a pair of Axes to the Scene." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:1 msgid "Adds a NumberPlane object to the background." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:1 msgid "Returns the Vector after adding it to the Plane." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 msgid "This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding lines that make up the x and y components of the vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:1 msgid "Returns naming labels for the basis vectors." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:1 msgid "Returns a VGroup of the Basis Vectors (1,0) and (0,1)" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:1 msgid "Returns an arrow on the Plane given an input numerical vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:1 msgid "Returns naming labels for the passed vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:1 msgid "Shortcut method for creating, and animating the addition of a label for the vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:1 msgid "This method freezes the NumberPlane and Axes that were already in the background, and adds new, manipulatable ones to the foreground." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 msgid "This method plays an animation that partially shows the entire plane moving in the direction of a particular vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 msgid "This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34::1 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:1 msgid "Returns a column matrix indicating the vector coordinates, after writing them to the screen." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:36 msgid "Attributes" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:3 msgid "Whether or not to animate the addition of the axes through Create." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:5 msgid "The color of the axes. Defaults to WHITE." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:3 msgid "Whether or not to animate the addition of the plane via Create." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:5 msgid "Any valid keyword arguments accepted by NumberPlane." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0 msgid "Returns" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:7 msgid "The NumberPlane object." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0 msgid "Return type" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:3 msgid "It can be a pre-made graphical vector, or the coordinates of one." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:6 msgid "The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:10 msgid "Whether or not to animate the addition of the vector by using GrowArrow" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:13 msgid "Any valid keyword argument of Arrow. These are only considered if vector is not an Arrow." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:17 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:4 msgid "The arrow representing the vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:1 msgid "This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding lines that make up the x and y components of the vector. Then, an Vector() based vector is created between the lines on the Screen." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:6 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:6 msgid "The vector to show." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:8 msgid "The starting point of the location of the label of the vector that shows it numerically. Defaults to 2 * RIGHT + 2 * UP or (2,2)" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:13 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:11 msgid "Whether or not to remove whatever this method did after it's done." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:3 msgid "Any valid keyword arguments of get_vector_label: vector, label (str,MathTex) at_tip (bool=False), direction (str=\"left\"), rotate (bool), color (str), label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float)," msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:10 msgid "Any valid keyword arguments of get_vector_label:" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:5 msgid "vector, label (str,MathTex) at_tip (bool=False), direction (str=\"left\"), rotate (bool), color (str), label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float)," msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:3 msgid "The hex colour to use for the basis vector in the x direction" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:5 msgid "The hex colour to use for the basis vector in the y direction" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:8 msgid "VGroup of the Vector Mobjects representing the basis vectors." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:3 msgid "The Vector to plot." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:5 msgid "Any valid keyword argument of Arrow." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:7 msgid "The Arrow representing the Vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:3 msgid "Vector Object for which to get the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:5 msgid "Whether or not to place the label at the tip of the vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:7 msgid "If the label should be on the \"left\" or right of the vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:9 msgid "Whether or not to rotate it to align it with the vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:11 msgid "The color to give the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:13 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:14 msgid "How much to scale the label by." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:16 #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:12 msgid "The MathTex of the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:4 msgid "The vector for which the label must be added." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:6 msgid "The MathTex/string of the label." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:8 msgid "Whether or not to animate the labelling w/ Write" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:10 msgid "Any valid keyword argument of get_vector_label" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:4 msgid "The required dimness of the NumberPlane" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:6 msgid "The required dimness of the Axes." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:1 msgid "This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to convey the idea of mentally moving the entire plane in a direction, without actually moving the plane." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:6 msgid "The vector which indicates the direction of movement." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:1 msgid "This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector. Then, a column matrix (henceforth called the label) is created near the head of the Vector." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:8 msgid "Whether or not to round the value displayed. in the vector's label to the nearest integer" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:6 msgid "Any valid keyword arguments of :meth:`~.geometry.Vector.coordinate_label`: integer_labels : :class:`bool` Whether or not to round the coordinates to integers. Default: ``True``. n_dim : :class:`int` The number of dimensions of the vector. Default: ``2``. color The color of the label. Default: ``WHITE``." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:6 msgid "Any valid keyword arguments of :meth:`~.geometry.Vector.coordinate_label`:" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:8 msgid "integer_labels : :class:`bool`" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:7 msgid "bool" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:9 msgid "Whether or not to round the coordinates to integers. Default: ``True``." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:10 msgid "n_dim : :class:`int`" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:9 msgid "int" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:11 msgid "The number of dimensions of the vector. Default: ``2``." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:13 msgid "color" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:13 msgid "The color of the label. Default: ``WHITE``." msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:15 msgid "The column matrix representing the vector." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.vector_space_scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.vector_space_scene.rst:2 msgid "vector\\_space\\_scene" msgstr "" #: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene:1 msgid "A scene suitable for vector spaces." msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.scene.vector_space_scene.rst:22::1 msgid "This scene contains special methods that make it especially suitable for showing linear transformations." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.zoomed_scene.ZoomedScene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:2 msgid "ZoomedScene" msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:4 msgid "Qualified name: ``manim.scene.zoomed\\_scene.ZoomedScene``" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene:1 msgid "Bases: :py:class:`manim.scene.moving_camera_scene.MovingCameraScene`" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene:1 msgid "This is a Scene with special configurations made for when a particular part of the scene must be zoomed in on and displayed separately." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24::1 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:1 msgid "This method is used to activate the zooming for the zoomed_camera." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24::1 msgid "Returns the Zoom factor of the Zoomed camera." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24::1 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:1 msgid "Returns the animation of camera zooming in." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24::1 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:1 msgid "This is the animation of the popping out of the mini-display that shows the content of the zoomed camera." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24::1 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.setup:1 msgid "This method is used internally by Manim to setup the scene for proper use." msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:0 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0 msgid "Parameters" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:4 msgid "Whether or not to animate the activation of the zoomed camera." msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_factor:1 msgid "Returns the Zoom factor of the Zoomed camera. Defined as the ratio between the height of the zoomed camera and the height of the zoomed mini display. :returns: The zoom factor. :rtype: float" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:3 msgid "The run_time of the animation of the camera zooming in." msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:5 msgid "Any valid keyword arguments of ApplyMethod()" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:0 msgid "Returns" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:7 msgid "The animation of the camera zooming in." msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0 #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.scene.zoomed_scene.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.scene.zoomed_scene.rst:2 msgid "zoomed\\_scene" msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene:1 msgid "A scene supporting zooming in on a specified section." msgstr "" #: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene:5 msgid "Examples" msgstr "" #: ../../source/reference/manim.scene.zoomed_scene.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.bezier.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.bezier.rst:2 msgid "bezier" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier:1 msgid "Utility functions related to Bézier curves." msgstr "" #: ../../source/reference/manim.utils.bezier.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:1 msgid "Classic implementation of a bezier curve." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.inverse_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.is_closed:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.match_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.mid:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:3 msgid "points defining the desired bezier curve." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0 msgid "Returns" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:6 msgid "function describing the bezier curve." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.inverse_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.is_closed:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.match_interpolate:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.mid:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0 #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:0 msgid "Return type" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:1 msgid "Converts array whose rows represent diagonal entries of a matrix into the matrix itself. See scipy.linalg.solve_banded" msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:1 msgid "Given some anchors (points), compute handles so the resulting bezier curve is smooth." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:3 msgid "Anchors." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:6 msgid "Computed handles." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:1 msgid "Alpha is a float between 0 and 1. This returns an integer between start and end (inclusive) representing appropriate interpolation between them, along with a \"residue\" representing a new proportion between the returned integer and the next one of the list." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:8 msgid "For example, if start=0, end=10, alpha=0.46, This would return (4, 0.6)." msgstr "" #: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:1 msgid "Given an array of points which define bezier curve, and two numbers 0<=a:1 msgid "A list of pre-defined colors." msgstr "" #: ../../source/reference/manim.utils.color.rst:29 msgid "Functions" msgstr "" #: ../../../manim/utils/color.py:docstring of manim.utils.color.average_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_gradient:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgba:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgba:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.get_shaded_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.hex_to_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.interpolate_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.invert_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_hex:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgba_to_color:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/color.py:docstring of manim.utils.color.average_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_gradient:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgba:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgba:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.get_shaded_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.hex_to_rgb:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.interpolate_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.invert_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.random_bright_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.random_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_color:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_hex:0 #: ../../../manim/utils/color.py:docstring of manim.utils.color.rgba_to_color:0 msgid "Return type" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.commands.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.commands.rst:2 msgid "commands" msgstr "" #: ../../source/reference/manim.utils.commands.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_dir_layout:1 msgid "Get list of paths relative to dirpath of all files in dir and subdirs recursively." msgstr "" #: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_dir_layout:0 #: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_video_metadata:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.config_ops.DictAsObject.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.config_ops.DictAsObject.rst:2 msgid "DictAsObject" msgstr "" #: ../../source/reference/manim.utils.config_ops.DictAsObject.rst:4 msgid "Qualified name: ``manim.utils.config\\_ops.DictAsObject``" msgstr "" #: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.DictAsObject:1 msgid "Bases: :py:class:`object`" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.config_ops.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.config_ops.rst:2 msgid "config\\_ops" msgstr "" #: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops:1 msgid "Utilities that might be useful for configuration dictionaries." msgstr "" #: ../../source/reference/manim.utils.config_ops.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.utils.config_ops.rst:29 msgid "Functions" msgstr "" #: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.merge_dicts_recursively:1 msgid "Creates a dict whose keyset is the union of all the input dictionaries. The value for each key is based on the first dict in the list with that key." msgstr "" #: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.merge_dicts_recursively:5 msgid "dicts later in the list have higher priority" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.debug.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.debug.rst:2 msgid "debug" msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug:1 msgid "Debugging utilities." msgstr "" #: ../../source/reference/manim.utils.debug.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:1 msgid "Returns a :class:`~.VGroup` of :class:`~.Integer` mobjects that shows the index of each submobject." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:4 msgid "Useful for working with parts of complicated mobjects." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:6 msgid "The mobject that will have its submobjects labelled." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:7 msgid "The height of the labels, by default 0.15." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:8 msgid "The stroke width of the outline of the labels, by default 5." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:9 msgid "The stroke color of the outline of labels." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:10 msgid "Additional parameters to be passed into the :class`~.Integer` mobjects used to construct the labels." msgstr "" #: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:14 msgid "Examples" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.deprecation.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.deprecation.rst:2 msgid "deprecation" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation:1 msgid "Decorators for deprecating classes, functions and function parameters." msgstr "" #: ../../source/reference/manim.utils.deprecation.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:1 msgid "Decorator to mark a callable as deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:3 msgid "The decorated callable will cause a warning when used. The docstring of the deprecated callable is adjusted to indicate that this callable is deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:6 msgid "The function to be decorated. Should not be set by the user." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:7 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:10 msgid "The version or date since deprecation." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:8 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:11 msgid "The version or date until removal of the deprecated callable." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:9 msgid "The identifier of the callable replacing the deprecated one." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:10 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:12 msgid "The reason for why the callable has been deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0 msgid "Returns" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:12 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:25 msgid "The decorated callable." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0 msgid "Return type" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:16 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:32 msgid "Examples" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:17 #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:33 msgid "Basic usage::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:43 msgid "You can specify additional information for a more precise warning::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:59 msgid "You may also use dates instead of versions::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:1 msgid "Decorator to mark parameters of a callable as deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:3 msgid "It can also be used to automatically redirect deprecated parameter values to their replacements." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:6 msgid "The parameters to be deprecated. Can consist of: * An iterable of strings, with each element representing a parameter to deprecate * A single string, with parameter names separated by commas or spaces." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:6 msgid "The parameters to be deprecated. Can consist of:" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:8 msgid "An iterable of strings, with each element representing a parameter to deprecate" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:9 msgid "A single string, with parameter names separated by commas or spaces." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:13 msgid "A list of parameter redirections. Each redirection can be one of the following: * A tuple of two strings. The first string defines the name of the deprecated parameter; the second string defines the name of the parameter to redirect to, when attempting to use the first string. * A function performing the mapping operation. The parameter names of the function determine which parameters are used as input. The function must return a dictionary which contains the redirected arguments. Redirected parameters are also implicitly deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:13 msgid "A list of parameter redirections. Each redirection can be one of the following:" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:15 msgid "A tuple of two strings. The first string defines the name of the deprecated parameter; the second string defines the name of the parameter to redirect to, when attempting to use the first string." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:19 msgid "A function performing the mapping operation. The parameter names of the function determine which parameters are used as input. The function must return a dictionary which contains the redirected arguments." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:23 msgid "Redirected parameters are also implicitly deprecated." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0 msgid "Raises" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:28 msgid "If no parameters are defined (neither explicitly nor implicitly)." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:29 msgid "If defined parameters are invalid python identifiers." msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:47 msgid "You can also specify additional information for a more precise warning::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:63 msgid "Basic parameter redirection::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:79 msgid "Redirecting using a calculated value::" msgstr "" #: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:93 msgid "Redirecting multiple parameter values to one::" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.ManimDirective.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.skip_manim_node.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.docbuild.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.hashing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.hashing.rst:2 msgid "hashing" msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing:1 msgid "Utilities for scene caching." msgstr "" #: ../../source/reference/manim.utils.hashing.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:1 msgid "Take the list of animations and a list of mobjects and output their hashes. This is meant to be used for `scene.play` function." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0 #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:3 msgid "The scene object." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:5 msgid "The camera object used in the scene." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:7 msgid "The list of animations." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:9 msgid "The list of mobjects." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0 #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0 msgid "Returns" msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:12 msgid "A string concatenation of the respective hashes of `camera_object`, `animations_list` and `current_mobjects_list`, separated by `_`." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0 #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0 msgid "Return type" msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:1 msgid "Recursively serialize `object` to JSON using the :class:`CustomEncoder` class." msgstr "" #: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:3 msgid "The dict to flatten" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.images.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.images.rst:2 msgid "images" msgstr "" #: ../../../manim/utils/images.py:docstring of manim.utils.images:1 msgid "Image manipulation utilities." msgstr "" #: ../../source/reference/manim.utils.images.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/images.py:docstring of manim.utils.images.change_to_rgba_array:1 msgid "Converts an RGB array into RGBA with the alpha value opacity maxed." msgstr "" #: ../../../manim/utils/images.py:docstring of manim.utils.images.drag_pixels:0 #: ../../../manim/utils/images.py:docstring of manim.utils.images.get_full_raster_image_path:0 #: ../../../manim/utils/images.py:docstring of manim.utils.images.invert_image:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.ipython_magic.ManimMagic.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:2 msgid "ManimMagic" msgstr "" #: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:4 msgid "Qualified name: ``manim.utils.ipython\\_magic.ManimMagic``" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:1 msgid "Bases: :py:class:`IPython.core.magic.Magics`" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:1 msgid "Create a configurable given a config config." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:0 #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:3 msgid "If this is empty, default values are used. If config is a :class:`Config` instance, it will be used to configure the instance." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:7 msgid "The parent Configurable instance of this object." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:11 msgid "Notes" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:12 msgid "Subclasses of Configurable must call the :meth:`__init__` method of :class:`Configurable` *before* doing anything else and using :func:`super`::" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:21 msgid "This ensures that instances will be configured properly." msgstr "" #: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:21::1 msgid "Render Manim scenes contained in IPython cells." msgstr "" #: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:23 msgid "Attributes" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1::1 #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1::1 msgid "A trait whose value must be an instance of a specified class." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1::1 msgid "A contextmanager for running a block with our cross validation lock set to True." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1 msgid "Render Manim scenes contained in IPython cells. Works as a line or cell magic." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:6 msgid "This line and cell magic works best when used in a JupyterLab environment: while all of the functionality is available for classic Jupyter notebooks as well, it is possible that videos sometimes don't update on repeated execution of the same cell if the scene name stays the same." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:12 msgid "This problem does not occur when using JupyterLab." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:14 msgid "Please refer to ``_ for more information about JupyterLab and Jupyter notebooks." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:17 msgid "Usage in line mode::" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:21 msgid "Usage in cell mode::" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:29 msgid "Run ``%manim --help`` and ``%manim render --help`` for possible command line interface options." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:33 msgid "The maximal width of the rendered videos that are displayed in the notebook can be configured via the ``media_width`` configuration option. The default is set to ``25vw``, which is 25% of your current viewport width. To allow the output to become as large as possible, set ``config.media_width = \"100%\"``." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:38 msgid "The ``media_embed`` option will embed the image/video output in the notebook. This is generally undesirable as it makes the notebooks very large, but is required on some platforms (notably Google's CoLab, where it is automatically enabled unless suppressed by ``config.embed = False``) and needed in cases when the notebook (or converted HTML file) will be moved relative to the video locations. Use-cases include building documentation with Sphinx and JupyterBook. See also the :mod:`manim directive for Sphinx `." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:47 msgid "Examples" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:48 msgid "First make sure to put ``import manim``, or even ``from manim import *`` in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim could look as follows::" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:64 msgid "Evaluating this cell will render and display the ``BannerExample`` scene defined in the body of the cell." msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:68 msgid "In case you want to hide the red box containing the output progress bar, the ``progress_bar`` config option should be set to ``None``. This can also be done by passing ``--progress_bar None`` as a CLI flag." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.ipython_magic.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.ipython_magic.rst:2 msgid "ipython\\_magic" msgstr "" #: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic:1 msgid "Utilities for using Manim with IPython (in particular: Jupyter notebooks)" msgstr "" #: ../../source/reference/manim.utils.ipython_magic.rst:15 msgid "Classes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.iterables.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.iterables.rst:2 msgid "iterables" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables:1 msgid "Operations on iterables." msgstr "" #: ../../source/reference/manim.utils.iterables.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:1 msgid "Returns the Sequence objects cyclically split into n length tuples." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:6 msgid "alias with n=2" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:9 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:6 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:8 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:4 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:4 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:6 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:4 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:10 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:10 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:4 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:13 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:16 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:16 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:4 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:5 msgid "Examples" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:10 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:7 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:9 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:7 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:11 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:11 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:14 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:17 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:17 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:6 msgid "Normal usage::" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.stretch_array_to_length:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.stretch_array_to_length:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:0 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:0 msgid "Return type" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:1 msgid "Alias for ``adjacent_n_tuples(objects, 2)``." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:1 msgid "Returns ``True`` if all elements of iterable are instances of Class. False otherwise." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:1 msgid "Takes in a Sequence, and returns a list of tuples, (batch, prop) such that all items in a batch have the same output when put into the Callable property_func, and such that chaining all these batches together would give the original Sequence (i.e. order is preserved)." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:1 msgid "Combines the Iterables provided as arguments into one list." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:1 msgid "Returns a list containing all the elements of l1 not in l2." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:3 msgid "Used instead of ``set.update()`` to maintain order," msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:2 msgid "making sure duplicates are removed from l1, not l2. Removes overlap of l1 and l2 and then concatenates l2 unchanged." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:1 msgid "Converts obj to a list intelligently." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:2 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:2 msgid "Extends the shorter of the two iterables with duplicate values until its" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:2 msgid "length is equal to the longer iterable (favours earlier elements)." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:7 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:10 msgid "cycles elements instead of favouring earlier ones" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:2 msgid "length is equal to the longer iterable (cycles over shorter iterable)." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:7 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:7 msgid "favours earlier elements instead of cycling them" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:1 msgid "Used instead of ``list(set(l))`` to maintain order. Keeps the last occurrence of each element." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:1 msgid "Removes elements where bool(x) evaluates to False." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:2 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:5 #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:5 msgid "Extends/truncates nparray so that ``len(result) == length``." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:2 msgid "The elements of nparray are cycled to achieve the desired length." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:10 msgid "similar cycling behaviour for balancing 2 iterables" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:2 msgid "The elements of nparray are duplicated to achieve the desired length (favours earlier elements)." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:5 msgid "Constructs a zeroes array of length if nparray is empty." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:13 msgid "similar earlier-favouring behaviour for balancing 2 iterables" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:2 msgid "New elements are interpolated to achieve the desired length." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:4 msgid "Note that if nparray's length changes, its dtype may too (e.g. int -> float: see Examples)" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:10 msgid "cycles elements instead of interpolating" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:13 msgid "favours earlier elements instead of interpolating" msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:1 msgid "Converts obj to a tuple intelligently." msgstr "" #: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:2 msgid "Returns a generator that yields all unique elements of the Iterables" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.paths.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.paths.rst:2 msgid "paths" msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths:1 msgid "Functions determining transformation paths between sets of points." msgstr "" #: ../../source/reference/manim.utils.paths.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:1 msgid "This function transforms each point by moving clockwise around a half circle." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:4 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:4 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:7 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:10 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:7 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.straight_path:4 msgid "Examples" msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.straight_path:0 msgid "Return type" msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:1 msgid "This function transforms each point by moving counterclockwise around a half circle." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:1 msgid "This function transforms each point by moving it along a circular arc." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:0 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:3 msgid "The angle each point traverses around a circular arc." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:4 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:7 #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:4 msgid "The axis of rotation." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:1 msgid "This function transforms each point by moving it roughly along a circle, each with its own specified center." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:3 msgid "The path may be seen as each point smoothly changing its orbit from its starting position to its destination." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:5 msgid "The angle each point traverses around the quasicircle." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:6 msgid "The centers of each point's quasicircle to rotate around." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:1 msgid "This function transforms each point by moving along a spiral to its destination." msgstr "" #: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:3 msgid "The angle each point traverses around a spiral." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.rate_functions.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.rate_functions.rst:2 msgid "rate\\_functions" msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:1 msgid "A selection of rate functions, i.e., *speed curves* for animations. Please find a standard list at https://easings.net/. Here is a picture for the non-standard ones" msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:46 msgid "There are primarily 3 kinds of standard easing functions:" msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:48 msgid "Ease In - The animation has a smooth start." msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:49 msgid "Ease Out - The animation has a smooth end." msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:50 msgid "Ease In Out - The animation has a smooth start as well as smooth end." msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:52 msgid "The standard functions are not exported, so to use them you do something like this: rate_func=rate_functions.ease_in_sine On the other hand, the non-standard functions, which are used more commonly, are exported and can be used directly." msgstr "" #: ../../source/reference/manim.utils.rate_functions.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.double_smooth:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_back:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_bounce:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_circ:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_cubic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_elastic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_expo:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_back:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_bounce:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_circ:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_cubic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_elastic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_expo:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quad:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quart:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quint:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_sine:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quad:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quart:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quint:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_sine:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_back:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_bounce:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_circ:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_cubic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_elastic:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_expo:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quad:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quart:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quint:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_sine:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.exponential_decay:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.linear:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.lingering:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.not_quite_there:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.running_start:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.rush_from:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.rush_into:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.slow_into:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.smooth:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.squish_rate_func:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.there_and_back:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.there_and_back_with_pause:0 #: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.wiggle:0 msgid "Parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.scale.LinearBase.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.scale.LogBase.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.scale.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.simple_functions.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.simple_functions.rst:2 msgid "simple\\_functions" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions:1 msgid "A collection of simple functions." msgstr "" #: ../../source/reference/manim.utils.simple_functions.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:1 msgid "Searches for a value in a range by repeatedly dividing the range in half." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:3 msgid "To be more precise, performs numerical binary search to determine the input to ``function``, between the bounds given, that outputs ``target`` to within ``tolerance`` (default of 0.0001). Returns ``None`` if no input can be found within the bounds." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:9 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:8 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:5 msgid "Examples" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:10 msgid "Consider the polynomial :math:`x^2 + 3x + 1` where we search for a target value of :math:`11`. An exact solution is :math:`x = 2`." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:22 msgid "Searching in the interval :math:`[0, 5]` for a target value of :math:`71` does not yield a solution::" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:0 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:0 msgid "Return type" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:1 msgid "The binomial coefficient n choose k." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:3 msgid ":math:`\\binom{n}{k}` describes the number of possible choices of :math:`k` elements from a set of :math:`n` elements." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:7 #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:7 msgid "References" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:8 msgid "https://en.wikipedia.org/wiki/Combination" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:9 msgid "https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.comb.html" msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:1 msgid "Clips ``a`` to the interval [``min_a``, ``max_a``]." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:3 msgid "Accepts any comparable objects (i.e. those that support <, >). Returns ``a`` if it is between ``min_a`` and ``max_a``. Otherwise, whichever of ``min_a`` and ``max_a`` is closest." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:1 msgid "Return the parameters of ``function`` as an ordered mapping of parameters' names to their corresponding ``Parameter`` objects." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:1 msgid "Returns the output of the logistic function." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:3 msgid "The logistic function, a common example of a sigmoid function, is defined as :math:`\\frac{1}{1 + e^{-x}}`." msgstr "" #: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:8 msgid "https://en.wikipedia.org/wiki/Sigmoid_function" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.sounds.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.sounds.rst:2 msgid "sounds" msgstr "" #: ../../../manim/utils/sounds.py:docstring of manim.utils.sounds:1 msgid "Sound-related utility functions." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.space_ops.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.space_ops.rst:2 msgid "space\\_ops" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops:1 msgid "Utility functions for two- and three-dimensional vectors." msgstr "" #: ../../source/reference/manim.utils.space_ops.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.R3_to_complex:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.complex_to_R3:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_winding_number:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.norm_squared:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.thick_diagonal:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.z_to_vector:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.R3_to_complex:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.complex_to_R3:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_winding_number:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.norm_squared:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.thick_diagonal:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.z_to_vector:0 msgid "Return type" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:1 msgid "Gets angle and axis from a quaternion." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:3 msgid "The quaternion from which we get the angle and axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0 msgid "Returns" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:5 msgid "Gives the angle and axis" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:1 msgid "Returns the angle between two vectors. This angle will always be between 0 and pi" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:4 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:3 msgid "The first vector." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:5 msgid "The second vector." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:7 msgid "The angle between the vectors." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:1 msgid "Returns polar coordinate theta when vector is projected on xy plane." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:3 msgid "The vector to find the angle for." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:5 msgid "The angle of the vector projected." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:1 msgid "Returns an array of numbers corresponding to each polar coordinate value (distance, phi, theta)." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:4 msgid "A numpy array ``[x, y, z]``." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:1 msgid "Gets the center of mass of the points in space." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:3 msgid "The points to find the center of mass from." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:5 msgid "The center of mass of the points." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:1 msgid "Finds the cardinal directions using tau." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:3 msgid "The amount to be rotated, by default 4" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:4 msgid "The direction for the angle to start with, by default RIGHT" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:6 msgid "The angle which has been rotated." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:1 msgid "Returns a list of indices giving a triangulation of a polygon, potentially with holes." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:4 msgid "verts is a numpy array of points." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:5 msgid "ring_ends is a list of indices indicating where" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:8 msgid "A list of indices giving a triangulation of a polygon." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:1 msgid "Return the intersection of a line passing through p0 in direction v0 with one passing through p1 in direction v1 (or array of intersections from arrays of such points/directions). For 3d values, it returns the point on the ray p0 + v0 * t closest to the ray p1 + v1 * t" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:1 msgid "Gets the unit normal of the vectors." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:4 msgid "The second vector" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:5 msgid "[description], by default 1e-6" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:7 msgid "The normal of the two vectors." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:1 msgid "Returns the intersection point of two lines, each defined by a pair of distinct points lying on the line." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:4 msgid "A list of two points that determine the first line." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:5 msgid "A list of two points that determine the second line." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:7 msgid "The intersection points of the two lines which are intersecting." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0 #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0 msgid "Raises" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:10 msgid "Error is produced if the two lines don't intersect with each other or if the coordinates don't lie on the xy-plane." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:1 msgid "Gets the midpoint of two points." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:3 msgid "The first point." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:4 msgid "The second point." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:6 msgid "The midpoint of the points" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:1 msgid "Normalizes an array with the provided axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:3 msgid "The array which has to be normalized." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:4 msgid "The axis to be normalized to." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:6 msgid "Array which has been normalized according to the axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:1 msgid "Returns a list of two points that correspond to the ends of the perpendicular bisector of the two points given." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:5 msgid "a list of two numpy array points (corresponding to the ends of a line)." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:7 msgid "the vector perpendicular to both the line given and the perpendicular bisector." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:10 msgid "A list of two numpy array points that correspond to the ends of the perpendicular bisector" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:1 msgid "Used for finding the conjugate of the quaternion" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:3 msgid "The quaternion for which you want to find the conjugate for." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:5 msgid "The conjugate of the quaternion." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:1 msgid "Gets a quaternion from an angle and an axis. For more information, check `this Wikipedia page `__." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:5 msgid "The angle for the quaternion." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:6 msgid "The axis for the quaternion" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:7 msgid "Checks whether the axis is normalized, by default False" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:10 msgid "Gives back a quaternion from the angle and axis" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:1 msgid "Gets the Hamilton product of the quaternions provided. For more information, check `this Wikipedia page `__." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:5 msgid "Returns a list of product of two quaternions." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:1 msgid "Generates regularly spaced vertices around a circle centered at the origin." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:3 msgid "The number of vertices" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:4 msgid "The radius of the circle that the vertices are placed on." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:5 msgid "The angle the vertices start at. If unspecified, for even ``n`` values, ``0`` will be used. For odd ``n`` values, 90 degrees is used." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:5 msgid "The angle the vertices start at." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:7 msgid "If unspecified, for even ``n`` values, ``0`` will be used. For odd ``n`` values, 90 degrees is used." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:10 msgid "* **vertices** (:class:`numpy.ndarray`) -- The regularly spaced vertices. * **start_angle** (:class:`float`) -- The angle the vertices start at." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:10 msgid "**vertices** (:class:`numpy.ndarray`) -- The regularly spaced vertices." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:11 msgid "**start_angle** (:class:`float`) -- The angle the vertices start at." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:1 msgid "Function for rotating a vector." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:3 msgid "The vector to be rotated." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:4 msgid "The angle to be rotated by." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:5 msgid "The axis to be rotated, by default OUT" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:7 msgid "The rotated vector with provided angle and axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:10 msgid "If vector is not of dimension 2 or 3." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:1 msgid "Returns a rotation matrix for a given angle." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:3 msgid "Angle for the rotation matrix." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:6 msgid "Gives back the rotated matrix." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:1 msgid "Rotation in R^3 about a specified axis of rotation." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:1 msgid "Converts the quaternion, quat, to an equivalent rotation matrix representation. For more information, check `this page `_." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:5 msgid "The quaternion which is to be converted." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:7 msgid "Gives back the Rotation matrix representation, returned as a 3-by-3 matrix or 3-by-3-by-N multidimensional array." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:1 msgid "2D implementation of the shoelace formula." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:3 msgid "Returns signed area." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:1 msgid "Uses the area determined by the shoelace method to determine whether the input set of points is directed clockwise or counterclockwise." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:4 msgid "Either ``\"CW\"`` or ``\"CCW\"``." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:1 msgid "Returns a numpy array ``[x, y, z]`` based on the spherical coordinates given." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:4 msgid "A list of three floats that correspond to the following: r - The distance between the point and the origin. theta - The azimuthal angle of the point to the positive x-axis. phi - The vertical angle of the point to the positive z-axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:4 msgid "A list of three floats that correspond to the following:" msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:6 msgid "r - The distance between the point and the origin." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:8 msgid "theta - The azimuthal angle of the point to the positive x-axis." msgstr "" #: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:10 msgid "phi - The vertical angle of the point to the positive z-axis." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.strings.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex.TexTemplate.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:2 msgid "TexTemplate" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:4 msgid "Qualified name: ``manim.utils.tex.TexTemplate``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:1 msgid "TeX templates are used for creating Tex() and MathTex() objects." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:3 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:18 msgid "The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:5 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:24 msgid "The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:7 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:30 msgid "The command defining the documentclass, e.g. ``\\documentclass[preview]{standalone}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:9 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:36 msgid "The document's preamble, i.e. the part between ``\\documentclass`` and ``\\begin{document}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:11 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:42 msgid "Text in the document that will be replaced by the expression to be rendered" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:13 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:48 msgid "Text (definitions, commands) to be inserted at right after ``\\begin{document}``, e.g. ``\\boldmath``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0 msgid "type" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:24::1 msgid "Adds txt to the TeX template just after \\begin{document}, e.g." msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:24::1 msgid "Adds stuff to the TeX template's preamble (e.g." msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:24::1 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:1 msgid "Inserts expression verbatim into TeX template." msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:24::1 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:1 msgid "Inserts expression into TeX template wrapped in \\begin{environment} and \\end{environment}" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplate.rst:26 msgid "Attributes" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:1 msgid "Adds txt to the TeX template just after \\begin{document}, e.g. ``\\boldmath``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:3 msgid "String containing the text to be added." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:1 msgid "Adds stuff to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:3 msgid "String containing the text to be added, e.g. ``\\usepackage{hyperref}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:5 msgid "Whether the text should be added at the beginning of the preamble, i.e. right after ``\\documentclass``. Default is to add it at the end of the preamble, i.e. right before ``\\begin{document}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:3 msgid "The string containing the expression to be typeset, e.g. ``$\\sqrt{2}$``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0 msgid "Returns" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:6 msgid "LaTeX code based on current template, containing the given ``expression`` and ready for typesetting" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0 msgid "Return type" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:3 msgid "The string containing the expression to be typeset, e.g. ``$\\\\sqrt{2}$``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:5 msgid "The string containing the environment in which the expression should be typeset, e.g. ``align*``" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex.TexTemplateFromFile.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:2 msgid "TexTemplateFromFile" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:4 msgid "Qualified name: ``manim.utils.tex.TexTemplateFromFile``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:1 msgid "Bases: :py:class:`manim.utils.tex.TexTemplate`" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:1 msgid "A TexTemplate object created from a template file (default: tex_template.tex)" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:3 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:35 msgid "The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:5 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:41 msgid "The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:7 msgid "The command defining the documentclass, e.g. ``\\documentclass[preview]{standalone}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:9 msgid "The document's preamble, i.e. the part between ``\\documentclass`` and ``\\begin{document}``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:11 msgid "Text in the document that will be replaced by the expression to be rendered" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:13 msgid "Text (definitions, commands) to be inserted at right after ``\\begin{document}``, e.g. ``\\boldmath``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:15 msgid "The kwargs specified can only be strings." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:18 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:23 msgid "Path to a valid TeX template file" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0 #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0 msgid "type" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:29 msgid "Content of the TeX template file" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:22::1 msgid "Adds txt to the TeX template just after \\begin{document}, e.g." msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:22::1 msgid "Adds stuff to the TeX template's preamble (e.g." msgstr "" #: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:24 msgid "Attributes" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:1 msgid "Adds txt to the TeX template just after \\begin{document}, e.g. ``\\boldmath``" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:3 msgid "String containing the text to be added." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:1 msgid "Adds stuff to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble." msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:3 msgid "String containing the text to be added, e.g. ``\\usepackage{hyperref}``" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex.rst:2 msgid "tex" msgstr "" #: ../../../manim/utils/tex.py:docstring of manim.utils.tex:1 msgid "Utilities for processing LaTeX templates." msgstr "" #: ../../source/reference/manim.utils.tex.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.utils.tex.rst:22::1 msgid "TeX templates are used for creating Tex() and MathTex() objects." msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex_file_writing.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex_file_writing.rst:2 msgid "tex\\_file\\_writing" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing:1 msgid "Interface for writing, compiling, and converting ``.tex`` files." msgstr "" #: ../../source/reference/manim.utils.tex_file_writing.rst:20 msgid "Functions" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:1 msgid "Compiles a tex_file into a .dvi or a .xdv or a .pdf" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0 msgid "Parameters" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:3 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:7 msgid "File name of TeX file to be typeset." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:5 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:3 msgid "String containing the compiler to be used, e.g. ``pdflatex`` or ``lualatex``" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:7 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:5 msgid "String containing the output format generated by the compiler, e.g. ``.dvi`` or ``.pdf``" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0 msgid "Returns" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:10 msgid "Path to generated output file in desired format (DVI, XDV or PDF)." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0 msgid "Return type" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:1 msgid "Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:3 msgid "File name of the input file to be converted." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:5 msgid "String containing the file extension and thus indicating the file type, e.g. ``.dvi`` or ``.pdf``" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:7 msgid "Page to be converted if input file is multi-page." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:10 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:10 msgid "Path to generated SVG file." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:1 msgid "Takes a tex expression (and an optional tex environment), and returns a fully formed tex file ready for compilation." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:4 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:3 msgid "String containing the TeX expression to be rendered, e.g. ``\\sqrt{2}`` or ``foo``" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:6 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:5 msgid "The string containing the environment in which the expression should be typeset, e.g. ``align*``" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:8 #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:7 msgid "Template class used to typesetting. If not set, use default template set via `config[\"tex_template\"]`" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:11 msgid "Path to generated TeX file" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:1 msgid "Prepares the tex compilation command with all necessary cli flags" msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:9 msgid "Path to the directory where compiler output will be stored." msgstr "" #: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:12 msgid "Compilation command according to given parameters" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex_templates.TexFontTemplates.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:2 msgid "TexFontTemplates" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:4 msgid "Qualified name: ``manim.utils.tex\\_templates.TexFontTemplates``" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:1 msgid "A collection of TeX templates for the fonts described at http://jf.burnol.free.fr/showcase.html" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:3 msgid "These templates are specifically designed to allow you to typeset formulae and mathematics using different fonts. They are based on the mathastext LaTeX package." msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:7 msgid "Examples" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:8 msgid "Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:13 msgid "Notes" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:14 msgid "Many of these templates require that specific fonts are installed on your local machine. For example, choosing the template TexFontTemplates.comic_sans will not compile if the Comic Sans Microsoft font is not installed." msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:20 msgid "To experiment, try to render the TexFontTemplateLibrary example scene:" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:20 msgid "``manim path/to/manim/example_scenes/advanced_tex_fonts.py TexFontTemplateLibrary -p -ql``" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:21 msgid "Attributes" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1 msgid "American Typewriter" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.antykwa:1 msgid "Antykwa Półtawskiego (TX Fonts for Greek and math symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.apple_chancery:1 msgid "Apple Chancery" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.auriocus_kalligraphicus:1 msgid "Auriocus Kalligraphicus (Symbol Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.baskervald_adf_fourier:1 msgid "Baskervald ADF with Fourier" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.baskerville_it:1 msgid "Baskerville (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.biolinum:1 msgid "Biolinum" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.brushscriptx:1 msgid "BrushScriptX-Italic (PX math and Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.chalkboard_se:1 msgid "Chalkboard SE" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.chalkduster:1 msgid "Chalkduster" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.comfortaa:1 msgid "Comfortaa" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.comic_sans:1 msgid "Comic Sans MS" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_sans:1 msgid "Droid Sans" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_sans_it:1 msgid "Droid Sans (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_serif:1 msgid "Droid Serif" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_serif_px_it:1 msgid "Droid Serif (PX math symbols) (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_augie:1 msgid "ECF Augie (Euler Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_jd:1 msgid "ECF JD (with TX fonts)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_skeetch:1 msgid "ECF Skeetch (CM Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_tall_paul:1 msgid "ECF Tall Paul (with Symbol font)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_webster:1 msgid "ECF Webster (with TX fonts)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.electrum_adf:1 msgid "Electrum ADF (CM Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.epigrafica:1 msgid "Epigrafica" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.fourier_utopia:1 msgid "Fourier Utopia (Fourier upright Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.french_cursive:1 msgid "French Cursive (Euler Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_bodoni:1 msgid "GFS Bodoni" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_didot:1 msgid "GFS Didot (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_neoHellenic:1 msgid "GFS NeoHellenic" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gnu_freesans_tx:1 msgid "GNU FreeSerif (and TX fonts symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gnu_freeserif_freesans:1 msgid "GNU FreeSerif and FreeSans" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.helvetica_fourier_it:1 msgid "Helvetica with Fourier (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.latin_modern_tw:1 msgid "Latin Modern Typewriter Proportional" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.latin_modern_tw_it:1 msgid "Latin Modern Typewriter Proportional (CM Greek) (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.libertine:1 msgid "Libertine" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.libris_adf_fourier:1 msgid "Libris ADF with Fourier" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.minion_pro_myriad_pro:1 msgid "Minion Pro and Myriad Pro (and TX fonts symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.minion_pro_tx:1 msgid "Minion Pro (and TX fonts symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.new_century_schoolbook:1 msgid "New Century Schoolbook (Symbol Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.new_century_schoolbook_px:1 msgid "New Century Schoolbook (Symbol Greek, PX math symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.noteworthy_light:1 msgid "Noteworthy Light" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.palatino:1 msgid "Palatino (Symbol Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.papyrus:1 msgid "Papyrus" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.romande_adf_fourier_it:1 msgid "Romande ADF with Fourier (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.slitex:1 msgid "SliTeX (Euler Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.times_fourier_it:1 msgid "Times with Fourier (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.urw_avant_garde:1 msgid "URW Avant Garde (Symbol Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.urw_zapf_chancery:1 msgid "URW Zapf Chancery (CM Greek)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.venturis_adf_fourier_it:1 msgid "Venturis ADF with Fourier (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.verdana_it:1 msgid "Verdana (Italic)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.vollkorn:1 msgid "Vollkorn (TX fonts for Greek and math symbols)" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.vollkorn_fourier_it:1 msgid "Vollkorn with Fourier (Italic)" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex_templates.TexTemplateLibrary.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:2 msgid "TexTemplateLibrary" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:4 msgid "Qualified name: ``manim.utils.tex\\_templates.TexTemplateLibrary``" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:1 msgid "Bases: :py:class:`object`" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:1 msgid "A collection of basic TeX template objects" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:4 msgid "Examples" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:5 msgid "Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:14 msgid "Methods" msgstr "" #: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:21 msgid "Attributes" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1 msgid "An instance of the TeX template used by 3b1b when using the use_ctex flag" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.default:1 msgid "An instance of the default TeX template in manim" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1::1 #: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.simple:1 msgid "An instance of a simple TeX template with only basic AMS packages loaded" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim.utils.tex_templates.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference/manim.utils.tex_templates.rst:2 msgid "tex\\_templates" msgstr "" #: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates:1 msgid "A library of LaTeX templates." msgstr "" #: ../../source/reference/manim.utils.tex_templates.rst:15 msgid "Classes" msgstr "" #: ../../source/reference/manim.utils.tex_templates.rst:22::1 msgid "A collection of TeX templates for the fonts described at http://jf.burnol.free.fr/showcase.html" msgstr "" ================================================ FILE: docs/i18n/gettext/reference/manim_directive.ManimDirective.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim_directive.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference/manim_directive.skip_manim_node.pot ================================================ ================================================ FILE: docs/i18n/gettext/reference.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference.rst:2 msgid "Reference Manual" msgstr "" #: ../../source/reference.rst:4 msgid "This reference manual details modules, functions, and variables included in Manim, describing what they are and what they do. For learning how to use Manim, see :doc:`tutorials/index`. For a list of changes since the last release, see the :doc:`changelog`." msgstr "" #: ../../source/reference.rst:9 msgid "The pages linked to here are currently a work in progress." msgstr "" #: ../../source/reference.rst:12 msgid "Inheritance Graphs" msgstr "" #: ../../source/reference.rst:15 msgid "Animations" msgstr "" #: ../../source/reference.rst:38 msgid "Cameras" msgstr "" #: ../../source/reference.rst:50 msgid "Mobjects" msgstr "" #: ../../source/reference.rst:88 msgid "Scenes" msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/animations.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/animations.rst:2 msgid "Animations" msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animate mobjects." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animation of a mobject boundary and tracing of points." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Tools for displaying multiple animations at once." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animate the display or removal of a mobject from a scene." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Fading in and out of view." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations that introduce mobjects to scene by growing them from points." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations drawing attention to particular mobjects." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations related to movement." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations for changing numbers." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations related to rotation." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Utilities for modifying the speed at which animations are played." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations transforming one mobject into another." msgstr "" #: ../../source/reference_index/animations.rst:23::1 msgid "Animations that try to transform Mobjects while keeping track of identical parts." msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/cameras.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/cameras.rst:2 msgid "Cameras" msgstr "" #: ../../source/reference_index/cameras.rst:13::1 msgid "A camera converts the mobjects contained in a Scene into an array of pixels." msgstr "" #: ../../source/reference_index/cameras.rst:13::1 msgid "A camera that allows mapping between objects." msgstr "" #: ../../source/reference_index/cameras.rst:13::1 msgid "A camera able to move through a scene." msgstr "" #: ../../source/reference_index/cameras.rst:13::1 msgid "A camera supporting multiple perspectives." msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/configuration.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/configuration.rst:2 msgid "Configuration" msgstr "" #: ../../source/reference_index/configuration.rst:5 msgid "Module Index" msgstr "" #: ../../source/reference_index/configuration.rst:14::1 msgid "Set the global config and logger." msgstr "" #: ../../source/reference_index/configuration.rst:14::1 msgid "Utilities to create and set the config." msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/mobjects.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/mobjects.rst:2 msgid "Mobjects" msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Special rectangles." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Various geometric Mobjects." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Mobjects used to represent mathematical graphs (think graph theory, not plotting)." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Coordinate systems and function graphing related mobjects." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Utilities for Manim's logo and banner." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Mobjects representing matrices." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Base classes for objects that can be displayed." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Mobjects related to SVG images." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Mobjects representing tables." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Mobjects used to display Text using Pango or LaTeX." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Three-dimensional mobjects." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Specialized mobject base classes." msgstr "" #: ../../source/reference_index/mobjects.rst:22::1 msgid "Simple mobjects that can be used for storing (and updating) a value." msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/scenes.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/scenes.rst:2 msgid "Scenes" msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "A scene whose camera can be moved around." msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "building blocks of segmented video API" msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "Basic canvas for animations." msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "The interface between scenes and ffmpeg." msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "A scene suitable for rendering three-dimensional objects and animations." msgstr "" #: ../../source/reference_index/scenes.rst:15::1 msgid "A scene suitable for vector spaces." msgstr "" ================================================ FILE: docs/i18n/gettext/reference_index/utilities_misc.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/reference_index/utilities_misc.rst:2 msgid "Utilities and other modules" msgstr "" #: ../../source/reference_index/utilities_misc.rst:5 msgid "Module Index" msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Constant definitions." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utility functions related to Bézier curves." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Colors and utility functions for conversion between different color models." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utilities that might be useful for configuration dictionaries." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Decorators for deprecating classes, functions and function parameters." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Debugging utilities." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utilities for scene caching." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utilities for using Manim with IPython (in particular: Jupyter notebooks)" msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Image manipulation utilities." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Operations on iterables." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Functions determining transformation paths between sets of points." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "A selection of rate functions, i.e., *speed curves* for animations." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "A collection of simple functions." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Sound-related utility functions." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utility functions for two- and three-dimensional vectors." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "Utilities for processing LaTeX templates." msgstr "" #: ../../source/reference_index/utilities_misc.rst:31::1 msgid "A library of LaTeX templates." msgstr "" ================================================ FILE: docs/i18n/gettext/reporting_bugs.pot ================================================ ================================================ FILE: docs/i18n/gettext/tutorials/a_deeper_look.pot ================================================ ================================================ FILE: docs/i18n/gettext/tutorials/building_blocks.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/tutorials/building_blocks.rst:3 msgid "Manim's building blocks" msgstr "" #: ../../source/tutorials/building_blocks.rst:5 msgid "This document explains the building blocks of manim and will give you all the necessary tools to start producing your own videos." msgstr "" #: ../../source/tutorials/building_blocks.rst:8 msgid "Essentially, manim puts at your disposal three different concepts that you can orchestrate together to produce mathematical animations: the **mathematical object** (or **mobject** for short), the **animation**, and the **scene**. As we will see in the following sections, each of these three concepts is implemented in manim as a separate class: the :class:`.Mobject`, :class:`.Animation`, and :class:`.Scene` classes." msgstr "" #: ../../source/tutorials/building_blocks.rst:15 msgid "It is recommended that you read the tutorials :doc:`quickstart` and :doc:`output_and_config` before reading this page." msgstr "" #: ../../source/tutorials/building_blocks.rst:21 msgid "Mobjects" msgstr "" #: ../../source/tutorials/building_blocks.rst:23 msgid "Mobjects are the basic building blocks for all manim animations. Each class that derives from :class:`.Mobject` represents an object that can be displayed on the screen. For example, simple shapes such as :class:`.Circle`, :class:`.Arrow`, and :class:`.Rectangle` are all mobjects. More complicated constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or :class:`.BarChart` are mobjects as well." msgstr "" #: ../../source/tutorials/building_blocks.rst:30 msgid "If you try to display an instance of :class:`.Mobject` on the screen, you will only see an empty frame. The reason is that the :class:`.Mobject` class is an abstract base class of all other mobjects, i.e. it does not have any pre-determined visual shape that can be displayed on the screen. It is only the skeleton of a thing that *could* be displayed. Therefore, you will rarely need to use plain instances of :class:`.Mobject`; instead, you will most likely create instances of its derived classes. One of these derived classes is :class:`.VMobject`. The ``V`` stands for Vectorized Mobject. In essence, a vmobject is a mobject that uses `vector graphics `_ to be displayed. Most of the time, you will be dealing with vmobjects, though we will continue to use the term \"mobject\" to refer to the class of shapes that can be displayed on the screen, as it is more general." msgstr "" #: ../../source/tutorials/building_blocks.rst:44 msgid "Any object that can be displayed on the screen is a ``mobject``, even if it is not necessarily *mathematical* in nature." msgstr "" #: ../../source/tutorials/building_blocks.rst:47 msgid "To see examples of classes derived from :class:`.Mobject`, see the :mod:`.geometry` module. Most of these are in fact derived from :class:`.VMobject` as well." msgstr "" #: ../../source/tutorials/building_blocks.rst:53 msgid "Creating and displaying mobjects" msgstr "" #: ../../source/tutorials/building_blocks.rst:55 msgid "As explained in :doc:`quickstart`, usually all of the code in a manim script is put inside the :meth:`.construct` method of a :class:`.Scene` class. To display a mobject on the screen, call the :meth:`~.Scene.add` method of the containing :class:`.Scene`. This is the principal way of displaying a mobject on the screen when it is not being animated. To remove a mobject from the screen, simply call the :meth:`~.Scene.remove` method from the containing :class:`.Scene`." msgstr "" #: ../../source/tutorials/building_blocks.rst:75 msgid "Placing mobjects" msgstr "" #: ../../source/tutorials/building_blocks.rst:77 msgid "Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add` some mobjects to it. This script generates a static picture that displays a circle, a square, and a triangle:" msgstr "" #: ../../source/tutorials/building_blocks.rst:96 msgid "By default, mobjects are placed at the center of coordinates, or *origin*, when they are first created. They are also given some default colors. Further, the ``Shapes`` scene places the mobjects by using the :meth:`.shift` method. The square is shifted one unit in the ``UP`` direction from the origin, while the circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively." msgstr "" #: ../../source/tutorials/building_blocks.rst:102 msgid "Unlike other graphics software, manim places the center of coordinates at the center of the screen. The positive vertical direction is up, and the positive horizontal direction is right. See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT``, and others, defined in the :mod:`.constants` module." msgstr "" #: ../../source/tutorials/building_blocks.rst:108 msgid "There are many other possible ways to place mobjects on the screen, for example :meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`. The next scene ``MobjectPlacement`` uses all three." msgstr "" #: ../../source/tutorials/building_blocks.rst:130 msgid "The :meth:`.move_to` method uses absolute units (measured relative to the ``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the mobject passed as the first argument). :meth:`align_to` uses ``LEFT`` not as measuring units but as a way to determine the border to use for alignment. The coordinates of the borders of a mobject are determined using an imaginary bounding box around it." msgstr "" #: ../../source/tutorials/building_blocks.rst:137 msgid "Many methods in manim can be chained together. For example the two lines" msgstr "" #: ../../source/tutorials/building_blocks.rst:145 msgid "can be replaced by" msgstr "" #: ../../source/tutorials/building_blocks.rst:151 msgid "Technically, this is possible because most methods calls return the modified mobject." msgstr "" #: ../../source/tutorials/building_blocks.rst:155 msgid "Styling mobjects" msgstr "" #: ../../source/tutorials/building_blocks.rst:157 msgid "The following scene changes the default aesthetics of the mobjects." msgstr "" #: ../../source/tutorials/building_blocks.rst:174 msgid "This scene uses two of the main functions that change the visual style of a mobject: :meth:`.set_stroke` and :meth:`.set_fill`. The former changes the visual style of the mobject's border while the latter changes the style of the interior. By default, most mobjects have a fully transparent interior so you must specify the ``opacity`` parameter to display the color. An opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent." msgstr "" #: ../../source/tutorials/building_blocks.rst:181 msgid "Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and :meth:`.set_fill`. Instances of :class:`.Mobject` implement :meth:`.~Mobject.set_color` instead. The vast majority of pre-defined classes are derived from :class:`.VMobject` so it is usually safe to assume that you have access to :meth:`.set_stroke` and :meth:`.set_fill`." msgstr "" #: ../../source/tutorials/building_blocks.rst:189 msgid "Mobject on-screen order" msgstr "" #: ../../source/tutorials/building_blocks.rst:191 msgid "The next scene is exactly the same as the ``MobjectStyling`` scene from the previous section, except for exactly one line." msgstr "" #: ../../source/tutorials/building_blocks.rst:209 msgid "The only difference here (besides the scene name) is the order in which the mobjects are added to the scene. In ``MobjectStyling``, we added them as ``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as ``add(triangle, square, circle)``." msgstr "" #: ../../source/tutorials/building_blocks.rst:214 msgid "As you can see, the order of the arguments of :meth:`~.Scene.add` determines the order that the mobjects are displayed on the screen, with the left-most arguments being put in the back." msgstr "" #: ../../source/tutorials/building_blocks.rst:221 msgid "Animations" msgstr "" #: ../../source/tutorials/building_blocks.rst:223 msgid "At the heart of manim is animation. Generally, you can add an animation to your scene by calling the :meth:`~.Scene.play` method." msgstr "" #: ../../source/tutorials/building_blocks.rst:243 msgid "Put simply, animations are procedures that interpolate between two mobjects. For example, :code:`FadeIn(square)` starts with a fully transparent version of :code:`square` and ends with a fully opaque version, interpolating between them by gradually increasing the opacity. :class:`.FadeOut` works in the opposite way: it interpolates from fully opaque to fully transparent. As another example, :class:`.Rotate` starts with the mobject passed to it as argument, and ends with the same object but rotated by a certain amount, this time interpolating the mobject's angle instead of its opacity." msgstr "" #: ../../source/tutorials/building_blocks.rst:254 msgid "Animating methods" msgstr "" #: ../../source/tutorials/building_blocks.rst:256 msgid "Any property of a mobject that can be changed can be animated. In fact, any method that changes a mobject's property can be used as an animation, through the use of :meth:`.animate`." msgstr "" #: ../../source/tutorials/building_blocks.rst:276 msgid ":meth:`.animate` is a property of all mobjects that animates the methods that come afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of the square, while :code:`square.animate.set_fill(WHITE)` animates this action." msgstr "" #: ../../source/tutorials/building_blocks.rst:281 msgid "Animation run time" msgstr "" #: ../../source/tutorials/building_blocks.rst:283 msgid "By default, any animation passed to :meth:`play` lasts for exactly one second. Use the :code:`run_time` argument to control the duration." msgstr "" #: ../../source/tutorials/building_blocks.rst:296 msgid "Creating a custom animation" msgstr "" #: ../../source/tutorials/building_blocks.rst:298 msgid "Even though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another. If you find yourself in that situation, then you can define your own custom animation. You start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`. The :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation. So, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method. Then you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions." msgstr "" #: ../../source/tutorials/building_blocks.rst:305 msgid "Let's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number. You can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number. But when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly. Manim has a feature that allows you to customize this behavior by defining your own custom animation." msgstr "" #: ../../source/tutorials/building_blocks.rst:310 msgid "You can start by creating your own ``Count`` class that extends :class:`~.Animation`. The class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end. The constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end." msgstr "" #: ../../source/tutorials/building_blocks.rst:314 msgid "The only thing that you need to do is to define how you want it to look at every step of the animation. Manim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played. The alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation. For example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation." msgstr "" #: ../../source/tutorials/building_blocks.rst:319 msgid "In the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation. Suppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation." msgstr "" #: ../../source/tutorials/building_blocks.rst:322 msgid "If alpha is 0, you want the value to be 50." msgstr "" #: ../../source/tutorials/building_blocks.rst:323 msgid "If alpha is 0.5, you want the value to be 75." msgstr "" #: ../../source/tutorials/building_blocks.rst:324 msgid "If alpha is 1, you want the value to be 100." msgstr "" #: ../../source/tutorials/building_blocks.rst:326 msgid "Generally, you start with the starting number and add only some part of the value to be increment according to the alpha value. So, the logic of calculating the number to display at each step will be ``50 + alpha * (100 - 50)``. Once you set the calculated value for the :class:`~.DecimalNumber`, you are done." msgstr "" #: ../../source/tutorials/building_blocks.rst:330 msgid "Once you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function." msgstr "" #: ../../source/tutorials/building_blocks.rst:367 msgid "Using coordinates of a mobject" msgstr "" #: ../../source/tutorials/building_blocks.rst:369 msgid "Mobjects contain points that define their boundaries. These points can be used to add other mobjects respectively to each other, e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:" msgstr "" #: ../../source/tutorials/building_blocks.rst:401 msgid "Transforming mobjects into other mobjects" msgstr "" #: ../../source/tutorials/building_blocks.rst:402 msgid "It is also possible to transform a mobject into another mobject like this:" msgstr "" #: ../../source/tutorials/building_blocks.rst:413 msgid "The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the `flip` function and reposition the points via the `roll `_ function of numpy:" msgstr "" #: ../../source/tutorials/building_blocks.rst:439 msgid "Scenes" msgstr "" ================================================ FILE: docs/i18n/gettext/tutorials/configuration.pot ================================================ ================================================ FILE: docs/i18n/gettext/tutorials/index.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/tutorials/index.rst:4 #: ../../source/tutorials/index.rst:4 msgid "Table of Contents" msgstr "" ================================================ FILE: docs/i18n/gettext/tutorials/output_and_config.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/tutorials/output_and_config.rst:2 msgid "Manim's Output Settings" msgstr "" #: ../../source/tutorials/output_and_config.rst:4 msgid "This document will focus on understanding manim's output files and some of the main command-line flags available." msgstr "" #: ../../source/tutorials/output_and_config.rst:7 msgid "This tutorial picks up where :doc:`quickstart` left off, so please read that document before starting this one." msgstr "" #: ../../source/tutorials/output_and_config.rst:11 msgid "Manim output folders" msgstr "" #: ../../source/tutorials/output_and_config.rst:13 msgid "At this point, you have just executed the following command." msgstr "" #: ../../source/tutorials/output_and_config.rst:19 msgid "Let's dissect what just happened step by step. First, this command executes manim on the file ``scene.py``, which contains our animation code. Further, this command tells manim exactly which ``Scene`` is to be rendered, in this case, it is ``SquareToCircle``. This is necessary because a single scene file may contain more than one scene. Next, the flag `-p` tells manim to play the scene once it's rendered, and the `-ql` flag tells manim to render the scene in low quality." msgstr "" #: ../../source/tutorials/output_and_config.rst:27 msgid "After the video is rendered, you will see that manim has generated some new files and the project folder will look as follows." msgstr "" #: ../../source/tutorials/output_and_config.rst:44 msgid "There are quite a few new files. The main output is in ``media/videos/scene/480p15/SquareToCircle.mp4``. By default, the ``media`` folder will contain all of manim's output files. The ``media/videos`` subfolder contains the rendered videos. Inside of it, you will find one folder for each different video quality. In our case, since we used the ``-l`` flag, the video was generated at 480 resolution at 15 frames per second from the ``scene.py`` file. Therefore, the output can be found inside ``media/videos/scene/480p15``. The additional folders ``media/videos/scene/480p15/partial_movie_files`` as well as ``media/text`` and ``media/Tex`` contain files that are used by manim internally." msgstr "" #: ../../source/tutorials/output_and_config.rst:55 msgid "You can see how manim makes use of the generated folder structure by executing the following command," msgstr "" #: ../../source/tutorials/output_and_config.rst:62 msgid "The ``-ql`` flag (for low quality) has been replaced by the ``-qh`` flag, for high quality. Manim will take considerably longer to render this file, and it will play it once it's done since we are using the ``-p`` flag. The output should look like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:84 msgid "And the folder structure should look as follows." msgstr "" #: ../../source/tutorials/output_and_config.rst:102 msgid "Manim has created a new folder ``media/videos/1080p60``, which corresponds to the high resolution and the 60 frames per second. Inside of it, you can find the new ``SquareToCircle.mp4``, as well as the corresponding ``partial_movie_files``." msgstr "" #: ../../source/tutorials/output_and_config.rst:107 msgid "When working on a project with multiple scenes, and trying out multiple resolutions, the structure of the output directories will keep all your videos organized." msgstr "" #: ../../source/tutorials/output_and_config.rst:111 msgid "Further, manim has the option to output the last frame of a scene, when adding the flag ``-s``. This is the fastest option to quickly get a preview of a scene. The corresponding folder structure looks like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:134 msgid "Saving the last frame with ``-s`` can be combined with the flags for different resolutions, e.g. ``-s -ql``, ``-s -qh``" msgstr "" #: ../../source/tutorials/output_and_config.rst:141 msgid "Sections" msgstr "" #: ../../source/tutorials/output_and_config.rst:143 msgid "In addition to the movie output file one can use sections. Each section produces its own output video. The cuts between two sections can be set like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:157 msgid "All the animations between two of these cuts get concatenated into a single output video file. Be aware that you need at least one animation in each section. For example this wouldn't create an output video:" msgstr "" #: ../../source/tutorials/output_and_config.rst:171 msgid "One way of fixing this is to wait a little:" msgstr "" #: ../../source/tutorials/output_and_config.rst:182 msgid "For videos to be created for each section you have to add the ``--save_sections`` flag to the Manim call like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:188 msgid "If you do this, the ``media`` folder will look like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:214 msgid "As you can see each section receives their own output video in the ``sections`` directory. The JSON file in here contains some useful information for each section:" msgstr "" #: ../../source/tutorials/output_and_config.rst:255 msgid "This data can be used by third party applications, like a presentation system or automated video editing tool." msgstr "" #: ../../source/tutorials/output_and_config.rst:257 msgid "You can also skip rendering all animations belonging to a section like this:" msgstr "" #: ../../source/tutorials/output_and_config.rst:271 msgid "Some command line flags" msgstr "" #: ../../source/tutorials/output_and_config.rst:273 msgid "When executing the command" msgstr "" #: ../../source/tutorials/output_and_config.rst:279 msgid "it was necessary to specify which ``Scene`` class to render. This is because a single file can contain more than one ``Scene`` class. If your file contains multiple ``Scene`` classes, and you want to render them all, you can use the ``-a`` flag." msgstr "" #: ../../source/tutorials/output_and_config.rst:284 msgid "As discussed previously, the ``-ql`` specifies low render quality. This does not look very good, but is very useful for rapid prototyping and testing. The other options that specify render quality are ``-qm``, ``-qh``, and ``-qk`` for medium, high, and 4k quality, respectively." msgstr "" #: ../../source/tutorials/output_and_config.rst:289 msgid "The ``-p`` flag plays the animation once it is rendered. If you want to open the file browser at the location of the animation instead of playing it, you can use the ``-f`` flag. You can also omit these two flags." msgstr "" #: ../../source/tutorials/output_and_config.rst:293 msgid "Finally, by default manim will output .mp4 files. If you want your animations in .gif format instead, use the ``-i`` flag. The output files will be in the same folder as the .mp4 files, and with the same name, but a different file extension." msgstr "" ================================================ FILE: docs/i18n/gettext/tutorials/quickstart.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/tutorials/quickstart.rst:3 msgid "Quickstart" msgstr "" #: ../../source/tutorials/quickstart.rst:6 msgid "Before proceeding, install Manim and make sure it's running properly by following the steps in :doc:`../installation`. For information on using Manim with Jupyterlab or Jupyter notebook, go to the documentation for the :meth:`IPython magic command `, ``%%manim``." msgstr "" #: ../../source/tutorials/quickstart.rst:14 msgid "Overview" msgstr "" #: ../../source/tutorials/quickstart.rst:16 msgid "This quickstart guide will lead you through creating a sample project using Manim: an animation engine for precise programmatic animations." msgstr "" #: ../../source/tutorials/quickstart.rst:19 msgid "First, you will use a command line interface to create a ``Scene``, the class through which Manim generates videos. In the ``Scene`` you will animate a circle. Then you will add another ``Scene`` showing a square transforming into a circle. This will be your introduction to Manim's animation ability. Afterwards, you will position multiple mathematical objects (``Mobject``\\s). Finally, you will learn the ``.animate`` syntax, a powerful feature that animates the methods you use to modify ``Mobject``\\s." msgstr "" #: ../../source/tutorials/quickstart.rst:29 msgid "Starting a new project" msgstr "" #: ../../source/tutorials/quickstart.rst:31 msgid "Start by creating a new folder. For the purposes of this guide, name the folder ``project``:" msgstr "" #: ../../source/tutorials/quickstart.rst:37 msgid "This folder is the root folder for your project. It contains all the files that Manim needs to function, as well as any output that your project produces." msgstr "" #: ../../source/tutorials/quickstart.rst:42 msgid "Animating a circle" msgstr "" #: ../../source/tutorials/quickstart.rst:44 msgid "Open a text editor, such as Notepad. Copy the following code snippet into the window:" msgstr "" #: ../../source/tutorials/quickstart.rst:57 msgid "Save the code snippet into your project folder with the name ``scene.py``." msgstr "" #: ../../source/tutorials/quickstart.rst:64 msgid "3. Open the command line, navigate to your project folder, and execute the following command:" msgstr "" #: ../../source/tutorials/quickstart.rst:71 msgid "Manim will output rendering information, then create an MP4 file. Your default movie player will play the MP4 file, displaying the following animation." msgstr "" #: ../../source/tutorials/quickstart.rst:83 msgid "If you see an animation of a pink circle being drawn, congratulations! You just wrote your first Manim scene from scratch." msgstr "" #: ../../source/tutorials/quickstart.rst:86 msgid "If you get an error message instead, you do not see a video, or if the video output does not look like the preceding animation, it is likely that Manim has not been installed correctly. Please refer to our :doc:`FAQ section ` for help with the most common issues." msgstr "" #: ../../source/tutorials/quickstart.rst:95 msgid "Explanation" msgstr "" #: ../../source/tutorials/quickstart.rst:97 msgid "Let's go over the script you just executed line by line to see how Manim was able to draw the circle." msgstr "" #: ../../source/tutorials/quickstart.rst:100 msgid "The first line imports all of the contents of the library:" msgstr "" #: ../../source/tutorials/quickstart.rst:106 msgid "This is the recommended way of using Manim, as a single script often uses multiple names from the Manim namespace. In your script, you imported and used ``Scene``, ``Circle``, ``PINK`` and ``Create``." msgstr "" #: ../../source/tutorials/quickstart.rst:110 msgid "Now let's look at the next two lines:" msgstr "" #: ../../source/tutorials/quickstart.rst:118 msgid "Most of the time, the code for scripting an animation is entirely contained within the :meth:`~.Scene.construct` method of a :class:`.Scene` class. Inside :meth:`~.Scene.construct`, you can create objects, display them on screen, and animate them." msgstr "" #: ../../source/tutorials/quickstart.rst:122 msgid "The next two lines create a circle and set its color and opacity:" msgstr "" #: ../../source/tutorials/quickstart.rst:129 msgid "Finally, the last line uses the animation :class:`.Create` to display the circle on your screen:" msgstr "" #: ../../source/tutorials/quickstart.rst:136 msgid "All animations must reside within the :meth:`~.Scene.construct` method of a class derived from :class:`.Scene`. Other code, such as auxiliary or mathematical functions, may reside outside the class." msgstr "" #: ../../source/tutorials/quickstart.rst:142 msgid "Transforming a square into a circle" msgstr "" #: ../../source/tutorials/quickstart.rst:144 msgid "With our circle animation complete, let's move on to something a little more complicated." msgstr "" #: ../../source/tutorials/quickstart.rst:146 msgid "Open ``scene.py``, and add the following code snippet below the ``CreateCircle`` class:" msgstr "" #: ../../source/tutorials/quickstart.rst:162 msgid "Render ``SquareToCircle`` by running the following command in the command line:" msgstr "" #: ../../source/tutorials/quickstart.rst:168 #: ../../source/tutorials/quickstart.rst:216 #: ../../source/tutorials/quickstart.rst:284 #: ../../source/tutorials/quickstart.rst:326 msgid "The following animation will render:" msgstr "" #: ../../source/tutorials/quickstart.rst:185 msgid "This example shows one of the primary features of Manim: the ability to implement complicated and mathematically intensive animations (such as cleanly interpolating between two geometric shapes) with just a few lines of code." msgstr "" #: ../../source/tutorials/quickstart.rst:191 msgid "Positioning ``Mobject``\\s" msgstr "" #: ../../source/tutorials/quickstart.rst:193 msgid "Next, let's go over some basic techniques for positioning ``Mobject``\\s." msgstr "" #: ../../source/tutorials/quickstart.rst:195 msgid "Open ``scene.py``, and add the following code snippet below the ``SquareToCircle`` method:" msgstr "" #: ../../source/tutorials/quickstart.rst:210 msgid "Render ``SquareAndCircle`` by running the following command in the command line:" msgstr "" #: ../../source/tutorials/quickstart.rst:232 msgid "``next_to`` is a ``Mobject`` method for positioning ``Mobject``\\s." msgstr "" #: ../../source/tutorials/quickstart.rst:234 msgid "We first specified the pink circle as the square's reference point by passing ``circle`` as the method's first argument. The second argument is used to specify the direction the ``Mobject`` is placed relative to the reference point. In this case, we set the direction to ``RIGHT``, telling Manim to position the square to the right of the circle. Finally, ``buff=0.5`` applied a small distance buffer between the two objects." msgstr "" #: ../../source/tutorials/quickstart.rst:240 msgid "Try changing ``RIGHT`` to ``LEFT``, ``UP``, or ``DOWN`` instead, and see how that changes the position of the square." msgstr "" #: ../../source/tutorials/quickstart.rst:242 msgid "Using positioning methods, you can render a scene with multiple ``Mobject``\\s, setting their locations in the scene using coordinates or positioning them relative to each other." msgstr "" #: ../../source/tutorials/quickstart.rst:246 msgid "For more information on ``next_to`` and other positioning methods, check out the list of :class:`.Mobject` methods in our reference manual." msgstr "" #: ../../source/tutorials/quickstart.rst:251 msgid "Using ``.animate`` syntax to animate methods" msgstr "" #: ../../source/tutorials/quickstart.rst:253 msgid "The final lesson in this tutorial is using ``.animate``, a ``Mobject`` method which animates changes you make to a ``Mobject``. When you prepend ``.animate`` to any method call that modifies a ``Mobject``, the method becomes an animation which can be played using ``self.play``. Let's return to ``SquareToCircle`` to see the differences between using methods when creating a ``Mobject``, and animating those method calls with ``.animate``." msgstr "" #: ../../source/tutorials/quickstart.rst:260 msgid "Open ``scene.py``, and add the following code snippet below the ``SquareAndCircle`` class:" msgstr "" #: ../../source/tutorials/quickstart.rst:278 msgid "Render ``AnimatedSquareToCircle`` by running the following command in the command line:" msgstr "" #: ../../source/tutorials/quickstart.rst:299 msgid "The first ``self.play`` creates the square. The second animates rotating it 45 degrees. The third transforms the square into a circle, and the last colors the circle pink. Although the end result is the same as that of ``SquareToCircle``, ``.animate`` shows ``rotate`` and ``set_fill`` being applied to the ``Mobject`` dynamically, instead of creating them with the changes already applied." msgstr "" #: ../../source/tutorials/quickstart.rst:305 msgid "Try other methods, like ``flip`` or ``shift``, and see what happens." msgstr "" #: ../../source/tutorials/quickstart.rst:307 msgid "Open ``scene.py``, and add the following code snippet below the ``AnimatedSquareToCircle`` class:" msgstr "" #: ../../source/tutorials/quickstart.rst:320 msgid "Render ``DifferentRotations`` by running the following command in the command line:" msgstr "" #: ../../source/tutorials/quickstart.rst:338 msgid "This ``Scene`` illustrates the quirks of ``.animate``. When using ``.animate``, Manim actually takes a ``Mobject``'s starting state and its ending state and interpolates the two. In the ``AnimatedSquareToCircle`` class, you can observe this when the square rotates: the corners of the square appear to contract slightly as they move into the positions required for the first square to transform into the second one." msgstr "" #: ../../source/tutorials/quickstart.rst:344 msgid "In ``DifferentRotations``, the difference between ``.animate``'s interpretation of rotation and the ``Rotate`` method is far more apparent. The starting and ending states of a ``Mobject`` rotated 180 degrees are the same, so ``.animate`` tries to interpolate two identical objects and the result is the left square. If you find that your own usage of ``.animate`` is causing similar unwanted behavior, consider using conventional animation methods like the right square, which uses ``Rotate``." msgstr "" #: ../../source/tutorials/quickstart.rst:353 msgid "You're done!" msgstr "" ================================================ FILE: docs/i18n/gettext/tutorials/using_text.pot ================================================ ================================================ FILE: docs/i18n/gettext/tutorials.pot ================================================ ================================================ FILE: docs/i18n/gettext/tutorials_guides.pot ================================================ msgid "" msgstr "" "Project-Id-Version: Manim \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../source/tutorials_guides.rst:4 #: ../../source/tutorials_guides.rst:4 msgid "Table of Contents" msgstr "" ================================================ FILE: docs/i18n/hi/LC_MESSAGES/index.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: hi\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\n" "X-Crowdin-File-ID: 5163\n" "Language-Team: Hindi\n" "Language: hi_IN\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/index.rst:7 msgid "Manim Community Overview" msgstr "Manim Community की समीक्षा" #: ../../source/index.rst:9 msgid "Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run." msgstr "पारंपरिक तौर पर तकनीकी विषयों को अनुप्राणित करना अत्यंत जटिल होता है क्योंकि अनुप्राणनों को इतना सटीक बनाना कि उन्हें सही रूप में दर्शाया जाए, यह कठिन हो सकता है। ``Manim`` Python का उपयोग करके अनुप्राणन क्रमादेशित रूप में उत्पादित करता है, जिससे हर एक किस प्रकार चलना चाहिए, यह स्पष्ट करना संभव हो जाता है।" #: ../../source/index.rst:14 msgid "This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``." msgstr "इस परियोजना पर कार्य अभी भी काफ़ी हद तक प्रगति पर है, पर हमें आशा है की यहाँ दी गई जानकारी नए उपयोगकर्ताओं के लिए ``Manim`` का प्रयोग आरंभ करना सरल बनाएगी।" #: ../../source/index.rst:20 msgid "All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!" msgstr "प्रलेखन का सभी विषय-वस्तु MIT अनुज्ञापत्र के तहत अनुज्ञापित किया गया है। विशेष रूप से वह सभी उदाहरण जिनका आप सामना करेंगे: अपने कार्यों एवं परियोजनाओं में इस कोड का उपयोग निसंकोच कीजिए!" #: ../../source/index.rst:23 msgid "We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter `_, `Reddit `_, or via `Discord `_." msgstr "हम आपके द्वारा इस संग्रह का प्रयोग करके बनाए गए अद्भुत परियोजनाओं को देखने के लिए उत्सुक हैं, निसंकोच हमारे साथ `Twitter पर `_, `Reddit पर `_, अन्यथा `Discord `_ द्वारा अपनी परियोजनाएँ हमारे साथ साझा करें।" #: ../../source/index.rst:27 msgid "In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage `_ or `our GitHub repository `_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_." msgstr "यदि आप अपना Manim द्वारा बनाए गए कार्य को प्रकाशित करते हैं, हमें प्रसन्नता होगी यदि आप `हमारे मुखपृष्ट `_ या `हमारे GitHub कोष (रिपाॅज़िटोरी)`_ की कड़ी जोड़ें। अगर आप Manim का प्रयोग वैज्ञानिक संदर्भ में करते हैं, किसी विशेष अवतरण को उद्धृत करने के निर्देश `हमारे README `_ में पाए जा सकते हैं।" #: ../../source/index.rst:36 msgid "As a quick reference, here are some often used modules, classes and methods:" msgstr "तत्काल संगर्भ के रूप में, कुछ प्रायः उपयोग किए जाने वाले प्रतिरूपक (माॅड्यूल), वर्ग (क्लासेस) एवं प्रणालियाँ प्रस्तुत हैं:" #: ../../source/index.rst:38 msgid "Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," msgstr "प्रतिरूपक: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," #: ../../source/index.rst:43 msgid "Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," msgstr "वर्ग: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," ================================================ FILE: docs/i18n/pt/LC_MESSAGES/index.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\n" "X-Crowdin-File-ID: 5163\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/index.rst:7 msgid "Manim Community Overview" msgstr "Visão geral da comunidade" #: ../../source/index.rst:9 msgid "Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run." msgstr "Animar conceitos técnicos é tradicionalmente bastante tedioso, já que pode ser difícil tornar as animações suficientemente precisas para transmiti-las com precisão. ``Manim`` usa Python para gerar animações programáticas, tornando possível especificar exatamente como cada uma deve ser executada." #: ../../source/index.rst:14 msgid "This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``." msgstr "Este projecto continua a ser, em grande medida, um trabalho em progresso. mas esperamos que a informação aqui torne mais fácil para iniciantes começarem a usar ``Manim``." #: ../../source/index.rst:20 msgid "All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!" msgstr "Todo o conteúdo da documentação está licenciado sob a licença MIT. Especialmente para os exemplos que você encontrou: Sinta-se à vontade para usar esse código em seus próprios projetos!" #: ../../source/index.rst:23 msgid "We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter `_, `Reddit `_, or via `Discord `_." msgstr "Estamos curiosos para ver os projetos incríveis que você cria usando esta biblioteca, sinta-se livre para compartilhar seus projetos conosco `no Twitter `_, `Reddit `_, ou via `Discord `_." #: ../../source/index.rst:27 msgid "In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage `_ or `our GitHub repository `_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_." msgstr "No caso de publicar seu trabalho feito com Manim, Gostaríamos que você adicionasse um link `nossa página inicial `_ ou `nosso repositório no GitHub `_. Se você usar Manim em um contexto científico, instruções sobre como citar uma versão em particular podem ser encontradas `em nosso README `_." #: ../../source/index.rst:36 msgid "As a quick reference, here are some often used modules, classes and methods:" msgstr "Como referência rápida, aqui estão alguns módulos, classes e métodos frequentemente usados:" #: ../../source/index.rst:38 msgid "Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," msgstr "Módulos: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," #: ../../source/index.rst:43 msgid "Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," msgstr "Classe: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," ================================================ FILE: docs/i18n/readyForTranslation ================================================ changelog.po index.po contributing.po installation/linux.po installation/troubleshooting.po reporting_bugs.po installation.po examples.po reference.po tutorials.po tutorials/building_blocks.po tutorials/quickstart.po guides/output_and_config.po guides/configuration.po guides/deep_dive.po guides/using_text.po faq/general.po faq/help.po faq/installation.po faq/opengl.po ================================================ FILE: docs/i18n/stripUntranslatable.awk ================================================ BEGIN { # The current state of the parser: # -1 -> haven't read the first line of the new block # 0 -> reading the pre-comment # 1 -> reading the msgid # 2 -> reading the msgstr state=-1 # The comment preceding the block precomment="" # The same string, but with a space after the sharp to avoid a comment sharpedprecomment="" # The msgid section, containing the string to be translated msgidstr="" # The same string, but with a sharp before every newline (commented out) sharpedmsgidstr="" # The msgstr section, containing the destination string msgstrstr="" # The same string, but with a sharp before every newline (commented out) sharpedmsgstrstr="" # Whether the block being read should be kept # -1 -> should keep, overridable # 0 -> should not keep, overridable # 1 -> should keep, not overridable acceptable=1 # The file location of where to put everything # that has been stripped out untranslatablefile="./untranslatable.po" # Whether we are still reading the licence text licencetext=1 } # Detecting the end of licence $0~/^#, fuzzy$/ {licencetext=0; next; next} # If we are reading the licence, skip text and dont print it. $0~// {if (licencetext==1) {next}} # We pass on the wrong metadata $0~/"Report-Msgid-Bugs-To:/ {next} $0~/"PO-Revision-Date:/ {next} $0~/"Last-Translator:/ {next} $0~/"Language-Team:/ {next} # This pattern matches empty lines # The code flushes the data stored, and save # it only if acceptable!=1 $0~/^$/ { if (state<=0){ if(acceptable!=1){ print precomment }else{ #print "# Detected untranslatable text:" #print sharpedprecomment } precomment="" }else{ if(acceptable==1){ print precomment print msgidstr print msgstrstr print "" }else{ #print "# Detected untranslatable text:" #print sharpedprecomment #print sharpedmsgidstr #print sharpedmsgstrstr print precomment>>untranslatablefile print msgidstr>>untranslatablefile print msgstrstr>>untranslatablefile } # Add the newline currently parsed # Re-initialisation of the variables. state=-1 acceptable=-1 precomment="" msgidstr="" msgstrstr="" } } # If the line is commented out $0~/^#/ { precomment=(state==-1)?$0:precomment"\n"$0 sharpedprecomment=(state==-1)?"# "$0:sharpedprecomment"\n# "$0 state=0 } # If the line starts with "msgid" $0~/^msgid/ { state=1 msgidstr=$0 sharpedmsgidstr="# "$0 } # If the line starts with msgstr $0~/^msgstr/ { state=2 msgstrstr=$0 sharpedmsgstrstr="# "$0 } # If the line starts with a '"' $0~/^\"/ { if(state==1){ msgidstr=msgidstr"\n"$0 sharpedmsgidstr=sharpedmsgidstr"\n# "$0 }else{ msgstrstr=msgstrstr"\n"$0 sharpedmsgstrstr=sharpedmsgstrstr"\n# "$0 } } # ---------------------------------------------------------------- # This code is now the part that actually selects lines to be stripped out. state==1 { acceptable=1 } $0~/^msgid ":ref:`[a-zA-Z]*`"/ { acceptable=0 } $0~/^msgid ":obj:/ { acceptable=0 } $0~/^msgid "manim.([a-z._\\]+)"$/ { acceptable=0 } $0~/^(msgid )?"((:(mod|class|func):`~\.[a-zA-Z0-9.]+)`| )+"/ { acceptable=0 } $0~/^msgid ":py:obj:`[a-zA-Z0-9_.<> ]+`(\\\\)?"/ { acceptable=0 } $0~/^msgid "(:(mod|class|meth|func|attr):`[~A-Za-z_.()]+`(, )?)+"/ { acceptable=0 } # When the parsing is ended, print the last missing endline END { print "" } ================================================ FILE: docs/i18n/stripUntranslatable.sh ================================================ #!/bin/bash rm -f translatable.po rm -f untranslatable.po pot_dir_prefix="gettext/" echo "" for srcFile in `find $pot_dir_prefix -name "*.pot" -type f` do printf "\r\033[KCleaning file \e[32m$srcFile\e[0m" dstFile="$srcFile.bld" awk -f stripUntranslatable.awk $srcFile | sed '/POT-Creation-Date/d'> $dstFile cat $dstFile >> translatable.po mv $dstFile $srcFile done echo "" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/contributing.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/contributing.pot\n" "X-Crowdin-File-ID: 5143\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/contributing.rst:3 msgid "Contributing" msgstr "Bidragande" #: ../../source/contributing.rst:5 msgid "Thank you for your interest in contributing to Manim! However you have decided to contribute or interact with the community, please always be civil and respect other members of the community. If you haven't read our :doc:`code of conduct`, do so here. Manim is Free and Open Source Software (FOSS) for mathematical animations. As such, **we welcome everyone** who is interested in mathematics, pedagogy, computer animations, open-source, software development, and beyond. Manim accepts many kinds of contributions, some are detailed below:" msgstr "Tack för ditt intresse för att bidra till Manim! Oavsett hur du bestämt dig för att bidra eller interagera med communityn, kom ihåg att alltid vara civiliserad och respektera andra medlemmar i communityn. Om du inte redan har gjort det, läs vår :doc:`uppförandekod`. Manim är en gratis programvara med öppen källkod (FOSS) för matematiska animationer. På grund av detta, **välkomnar vi alla** som är intresserade av matematik, pedagogik, datoranimationer, öppen källkod, mjukvaruutveckling och vidare. Manim tar emot många typer av bidrag, några exempel beskrivs nedan:" #: ../../source/contributing.rst:14 msgid "Code maintenance and development" msgstr "Underhåll och utveckling av kod" #: ../../source/contributing.rst:15 msgid "DevOps" msgstr "DevOps" #: ../../source/contributing.rst:16 msgid "Documentation" msgstr "Dokumentation" #: ../../source/contributing.rst:17 msgid "Developing educational content & narrative documentation" msgstr "Utveckla pedagogiskt innehåll & berättande dokumentation" #: ../../source/contributing.rst:18 msgid "Plugins to extend Manim functionality" msgstr "Plugins för att utöka Manims funktionalitet" #: ../../source/contributing.rst:19 msgid "Testing (graphical, unit & video)" msgstr "Testning (grafik, enhetstester & video)" #: ../../source/contributing.rst:20 msgid "Website design and development" msgstr "Webbplatsdesign och -utveckling" #: ../../source/contributing.rst:21 msgid "Translating documentation and docstrings" msgstr "Översätta dokumentation och docsträngar" #: ../../source/contributing.rst:24 msgid "Please ensure that you are reading the latest version of this guide by ensuring that \"latest\" is selected in the version switcher." msgstr "Se till att du läser den senaste versionen av denna guide genom att se till att \"senaste\" väljs i versionshanteraren." ================================================ FILE: docs/i18n/sv/LC_MESSAGES/examples.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/examples.pot\n" "X-Crowdin-File-ID: 5161\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/examples.rst:3 msgid "Example Gallery" msgstr "Exempelgalleri" #: ../../source/examples.rst:5 msgid "This gallery contains a collection of best practice code snippets together with their corresponding video/image output, illustrating different functionalities all across the library. These are all under the MIT license, so feel free to copy & paste them to your projects. Enjoy this taste of Manim!" msgstr "Detta galleri innehåller en samling av kodstycken och de motsvarande videor/bilder som de producerar. Dessa kodstycken ses som exempel på bästa praxis och illustrerar flera olika funktioner som finns tillgängliga inom programbiblioteket. De är alla utgivna med MIT licens så varsågod att kopiera och klistra in dem i olika projekt. Vi hoppas ni njuter av denna försmak av Manims funktioner!" #: ../../source/examples.rst:13 msgid "This gallery is not the only place in our documentation where you can see explicit code and video examples: there are many more in our :doc:`reference manual ` -- see, for example, our documentation for the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`, and many more." msgstr "Detta galleri är inte den enda platsen i vår dokumentation där du kan se explicit kod och videoexempel. Det finns många andra platser i vår :doc:`reference manual ` -- se till exempel vår dokumentation för modulerna :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene` och många andra." #: ../../source/examples.rst:19 msgid "Check out our `interactive Jupyter environment `_ which allows running the examples online, without requiring a local installation." msgstr "Kolla in vår `interaktiva Jupyter-miljö `_ som gör det möjligt att köra exemplen online utan att det krävs en lokal installation." #: ../../source/examples.rst:23 msgid "Also, visit our `Twitter `_ for more *manimations*!" msgstr "Besök även vår `Twitter `_ för fler *manimationer*!" #: ../../source/examples.rst:29 msgid "Basic Concepts" msgstr "Grundläggande Begrepp" #: ../../source/examples.rst:98 msgid "Animations" msgstr "Animationer" #: ../../source/examples.rst:180 msgid "You can use multiple ValueTrackers simultaneously." msgstr "Du kan använda flera ValueTrackers samtidigt." #: ../../source/examples.rst:274 msgid "Plotting with Manim" msgstr "Plottar med Manim" #: ../../source/examples.rst:402 msgid "Special Camera Settings" msgstr "Speciella kamerainställningar" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/index.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\n" "X-Crowdin-File-ID: 5163\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/index.rst:7 msgid "Manim Community Overview" msgstr "Manim Community Översikt" #: ../../source/index.rst:9 msgid "Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run." msgstr "Traditionellt så har det varit jobbigt att animera tekniska begrepp eftersom det är svårt att skapa animationer som är tillräckligt exakta för att förklara dem korrekt. ``Manim`` använder sig av Python för att generera animationer på ett programmatiskt sätt vilket gör det möjligt att ange exakt hur varje animation ska köras." #: ../../source/index.rst:14 msgid "This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``." msgstr "Detta projekt är fortfarande i hög grad ett pågående arbete, men vi hoppas att informationen här kommer att göra det lättare för nykomlingar att komma igång med ``Manim``." #: ../../source/index.rst:20 msgid "All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!" msgstr "Allt innehåll i dokumentationen är licensierat under MIT-licensen. Detta gäller även för alla exempel som du möter på. Använd gärna koden i dina egna projekt!" #: ../../source/index.rst:23 msgid "We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter `_, `Reddit `_, or via `Discord `_." msgstr "Vi är nyfikna på att se de fantastiska projekt du skapar med hjälp av detta bibliotek! Dela gärna dina projekt med oss på Twitter `_, `Reddit `_ eller via `Discord `_." #: ../../source/index.rst:27 msgid "In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage `_ or `our GitHub repository `_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_." msgstr "Om du publicerar ett projekt du skapad med Manim så skulle vi uppskatta om du lägger till en länk till `vår hemsida `_ eller `vårt GitHub-arkiv `_. Om du använder Manim i ett vetenskapligt sammanhang så finns instruktioner om hur man citerar en viss version av Manim `i vår README `_." #: ../../source/index.rst:36 msgid "As a quick reference, here are some often used modules, classes and methods:" msgstr "Som snabbreferens ges här några av de oftast använda modulerna, klasserna och metoderna:" #: ../../source/index.rst:38 msgid "Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," msgstr "Moduler: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`," #: ../../source/index.rst:43 msgid "Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," msgstr "Klasser: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`," ================================================ FILE: docs/i18n/sv/LC_MESSAGES/installation.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/installation.pot\n" "X-Crowdin-File-ID: 5165\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/installation.rst:2 msgid "Installation" msgstr "Installering" #: ../../source/installation.rst:4 msgid "Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try." msgstr "Beroende på ditt användningsfall rekommenderas olika installationsalternativ: om du bara vill testa Manim först så är interaktiva notebooks lätta att utforska biblioteket med. De kan dessutom öppnas i din webbläsare utan att installera Manim lokalt vilket gör dem enkla att använda. Ta gärna en titt https://try.manim.community för en interaktiv nybörjarkurs." #: ../../source/installation.rst:10 msgid "Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker)." msgstr "Annars, om du har för avsikt att använda Manim för att jobba på ett animationsprojekt, så rekommenderar vi att du installerar biblioteket lokalt (antingen till ditt systems Python, eller via Docker)." #: ../../source/installation.rst:16 msgid "Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :doc:`differences between Manim versions ` if you are unsure which version you should install." msgstr "Observera att det finns flera olika versioner av Manim. Instruktionerna på denna webbsida är **endast** för *community-utgåvan*. Läs mer om :doc:`skillnader mellan Manim versioner ` om du är osäker på vilken version du bör installera." #: ../../source/installation.rst:22 msgid ":ref:`Installing Manim to your system's Python `" msgstr ":ref:`Installera Manim till ditt systems Python `" #: ../../source/installation.rst:23 msgid ":ref:`Using Manim via Docker `" msgstr ":ref:`Använda Manim via Docker `" #: ../../source/installation.rst:24 msgid ":ref:`Interactive Jupyter notebooks via Binder / Google Colab `" msgstr ":ref:`Interaktiva Jupyter notebooks via Binder / Google Colab `" #: ../../source/installation.rst:31 msgid "Installing Manim locally" msgstr "Installering av Manim lokalt" #: ../../source/installation.rst:33 msgid "Manim is a Python library, and it can be `installed via pip `__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow." msgstr "Manim är ett Pythonbibliotek, och det kan `installeras via pip `__. För att Manim ska fungera ordentligt måste dock ytterligare systemberoenden installeras först. Följande sidor har operativsystemsspecifika instruktioner för dig att följa." #: ../../source/installation.rst:41 msgid "Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord `__, or start a new Discussion `directly on GitHub `__." msgstr "Beroende på ditt specifika system så kan installationsprocessen vara något annorlunda. Se till att du har försökt att följa stegen på följande sidor noga, men om du träffar en vägg så hjälper vi gärna till: du kan antingen `gå med i vår Discord `__, eller starta en ny diskussion `direkt på GitHub `__." #: ../../source/installation.rst:57 msgid "Once Manim is installed locally, you can proceed to our :doc:`quickstart guide ` which walks you through rendering a first simple scene." msgstr "När Manim väl installerats lokalt så kan du fortsätta till vår :doc:`snabbstartsguide ` som visar dig hur du renderar din första enkla scen." #: ../../source/installation.rst:61 msgid "As mentioned above, do not worry if there are errors or other problems: consult our :doc:`troubleshooting guide ` for help, or get in touch with the community via `GitHub discussions `__ or `Discord `__." msgstr "Som nämnts ovan så behöver du inte oroa dig om det finns fel eller andra problem: läs vår :doc:`felsökningsguide ` för att få hjälp, eller ta kontakt med communityn via `GitHub-diskussioner `__ eller `Discord `__." #: ../../source/installation.rst:73 msgid "Using Manim via Docker" msgstr "Användning av Manim via Docker" #: ../../source/installation.rst:75 msgid "`Docker `__ is a virtualization tool that allows the distribution of encapsulated software environments (containers)." msgstr "`Docker `__ är ett virtualiseringsverktyg som gör det möjligt att distribuera inkapslade mjukvarumiljöer (containers)." #: ../../source/installation.rst:78 msgid "The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:" msgstr "Följande sidor innehåller mer information om den Docker Image som underhålls av communityn, ``manimcommunity/manim``:" #: ../../source/installation.rst:89 msgid "Interactive Jupyter notebooks for your browser" msgstr "Interaktiva Jupyter notebooks för din webbläsare" #: ../../source/installation.rst:91 msgid "Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks `__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook." msgstr "Manim ges ut med ett inbyggt ``%%manim`` IPython magic command som är utformat för användning inuti `Jupyter notebooks `__. Vår interaktiva nybörjarkurs på https://try.manim.community illustrerar hur Manim kan användas inuti en Jupyter notebook." #: ../../source/installation.rst:96 msgid "The following pages explain how you can setup interactive environments like that yourself:" msgstr "Följande sidor förklarar hur du kan skapa sådana interaktiva miljöer själv:" #: ../../source/installation.rst:105 msgid "Installation for developers" msgstr "Installering för utvecklare" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/plugins.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/plugins.pot\n" "X-Crowdin-File-ID: 5181\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:30\n" #: ../../source/plugins.rst:5 msgid "Plugins" msgstr "Plugins" #: ../../source/plugins.rst:7 msgid "Plugins are features that extend Manim's core functionality. Since Manim is extensible and not everything belongs in its core, we'll go over how to install, use, and create your own plugins." msgstr "Plugins är tillägg som utökar Manims kärnfunktionalitet. Eftersom Manim är utökningsbart, och inte allt hör hemma dess kärna, så kommer vi gå över hur man kan installera, använda och skapa egna plugins." #: ../../source/plugins.rst:13 msgid "The standard naming convention for plugins is to prefix the plugin with ``manim-``. This makes them easy for users to find on package repositories such as PyPI." msgstr "Den namnkonvention som används som standard för plugins är att sätta prefixet ``manim-`` i början pluginens namn. Detta gör det enkelt för andra användare att hitta plugins via paketarkiv (repositories) som exempel PyPI." #: ../../source/plugins.rst:19 msgid "The plugin feature is new and under active development. Expect updates for the best practices on installing, using, and creating plugins; as well as new subcommands/flags for ``manim plugins``" msgstr "Pluginfunktionen är ny och under aktiv utveckling. Räkna med att de bästa metoderna att installera, använda och skapa plugins, samt nya underkommandon/flaggor för ``manim-plugins``, kommer uppdateras" #: ../../source/plugins.rst:25 msgid "See https://plugins.manim.community/ for the list of plugins available." msgstr "Se https://plugins.manim.community/ för listan över tillgängliga plugins." #: ../../source/plugins.rst:28 msgid "Installing Plugins" msgstr "Installering av Plugins" #: ../../source/plugins.rst:29 msgid "Plugins can be easily installed via the ``pip`` command:" msgstr "Plugins kan enkelt installeras via ``pip`` kommandot:" #: ../../source/plugins.rst:36 msgid "After installing a plugin, you may use the ``manim plugins`` command to list your available plugins, see the following help output:" msgstr "Efter att du har installerat en plugin kan du använda kommandot ``manim plugins`` för att lista dina tillgängliga plugins, se följande hjälpmeddelande:" #: ../../source/plugins.rst:52 msgid "You can list plugins as such:" msgstr "Du kan få en lista av plugins på detta sätt:" #: ../../source/plugins.rst:61 msgid "Using Plugins in Projects" msgstr "Användning av Plugins i Projekt" #: ../../source/plugins.rst:62 msgid "For enabling a plugin ``manim.cfg`` or command line parameters should be used." msgstr "För att aktivera en plugin bör ``manim.cfg`` eller command line parametrar användas." #: ../../source/plugins.rst:66 msgid "The plugins should be module name of the plugin and not PyPi name." msgstr "Pluginerna bör vara namnet på modulen, inte dess PyPI namn." #: ../../source/plugins.rst:68 msgid "Enabling plugins through ``manim.cfg``" msgstr "Aktivering av plugins via ``manim.cfg``" #: ../../source/plugins.rst:75 msgid "For specifying multiple plugins, command separated values must be used." msgstr "För att ange flera plugins så måste kommandoseparerade värden användas." #: ../../source/plugins.rst:83 msgid "Creating Plugins" msgstr "Skapa Plugins" #: ../../source/plugins.rst:84 msgid "Plugins are intended to extend Manim's core functionality. If you aren't sure whether a feature should be included in Manim's core, feel free to ask over on the `Discord server `_. Visit `manim-plugintemplate `_ on PyPI.org which serves as an in-depth tutorial for creating plugins." msgstr "Plugins är avsedda att utöka Manims kärnfunktionalitet. Om du inte är säker på om en funktion ska inkluderas i Manims kärna, fråga gärna på `Discord-servern `_. Besök även `manim-plugintemplate `_ på PyPI.org eftersom det fungerar som en fördjupad handledning för att skapa plugins." #: ../../source/plugins.rst:94 msgid "The only requirement of manim plugins is that they specify an entry point with the group, ``\"manim.plugins\"``. This allows Manim to discover plugins available in the user's environment. Everything regarding the plugin's directory structure, build system, and naming are completely up to your discretion as an author. The aforementioned template plugin is only a model using Poetry since this is the build system Manim uses. The plugin's `entry point `_ can be specified in poetry as:" msgstr "Det enda kravet på manim plugins är att de anger en ingångspunkt genom gruppen, ``\"manim.plugins\"``. Detta gör det möjligt för Manim att upptäcka plugins som finns i användarens arbetsmiljö. Allt om pluginens katalogstruktur, byggsystem och namngivning är helt upp till din dina egna val som författare. Den ovannämnda mallpluginen är bara en modell med Poesi eftersom detta är byggsystemet som Manim använder. Pluginens `ingångspunkt `_ kan anges i poesi som:" #: ../../source/plugins.rst:108 msgid "Here ``name`` is the name of the module of the plugin." msgstr "Här är ``name`` namnet på pluginens modul." #: ../../source/plugins.rst:110 msgid "Here ``object_reference`` can point to either a function in a module or a module itself. For example," msgstr "Här kan ``object_reference`` peka mot antingen en funktion i en modul eller en modul själv. Till exempel," #: ../../source/plugins.rst:118 msgid "Here a module is used as ``object_reference``, and when this plugin is enabled, Manim will look for ``__all__`` keyword defined in ``manim_plugintemplate`` and everything as a global variable one by one." msgstr "Här används en modul som ``object_reference``. När denna modul aktiveras så kommer Manim att leta efter nyckelordet ``__all__`` som definierats i ``manim_plugintemplate`` och allt som en global variabel en efter en." #: ../../source/plugins.rst:122 msgid "If ``object_reference`` is a function, Manim calls the function and expects the function to return a list of modules or functions that need to be defined globally." msgstr "Om ``object_reference`` är en funktion så kommer Manim anropa funktionen och förväntar sig att funktionen returnerar en lista över moduler eller funktioner som behöver definieras globalt." #: ../../source/plugins.rst:125 msgid "For example," msgstr "Till exempel," ================================================ FILE: docs/i18n/sv/LC_MESSAGES/reference.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/reference.pot\n" "X-Crowdin-File-ID: 5183\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:30\n" #: ../../source/reference.rst:2 msgid "Reference Manual" msgstr "Referensmanual" #: ../../source/reference.rst:4 msgid "This reference manual details modules, functions, and variables included in Manim, describing what they are and what they do. For learning how to use Manim, see :doc:`tutorials`. For a list of changes since the last release, see the :doc:`changelog`." msgstr "Denna referensmanual innehåller moduler, funktioner och variabler som inkluderas in Manim och beskriver de är och vad de gör. For att lära dig hur man använder Manim, se :doc:`tutorials`. For en lista över förändringar sedan den senaste utgåvan, se :doc:`förändringsrapporten`." #: ../../source/reference.rst:9 msgid "The pages linked to here are currently a work in progress." msgstr "De sidor som dessa länkar leder till är fortfarande under aktiv påbyggnad." #: ../../source/reference.rst:12 msgid "Inheritance Graphs" msgstr "Grafer för arv" #: ../../source/reference.rst:15 msgid "Animations" msgstr "Animationer" #: ../../source/reference.rst:35 msgid "Cameras" msgstr "Kameror" #: ../../source/reference.rst:47 msgid "Mobjects" msgstr "Mobjekt" #: ../../source/reference.rst:84 msgid "Scenes" msgstr "Scener" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/reporting_bugs.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/reporting_bugs.pot\n" "X-Crowdin-File-ID: 5833\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:30\n" #: ../../source/reporting_bugs.rst:2 msgid "Reporting bugs" msgstr "Rapportering av buggar" #: ../../source/reporting_bugs.rst:4 msgid "One of the best ways of contributing to Manim is by reporting bugs. If you have encountered something that you believe is a bug, please follow these steps:" msgstr "Ett av de bästa sätten att bidra till Manim är genom att rapportera buggar. Om du har stött på något som du tror är en bugg, följ dessa steg:" #: ../../source/reporting_bugs.rst:8 msgid "First of all, make sure you are running the latest version of manim. If not, update your version and try again." msgstr "Först och främst, se till att du kör den senaste versionen av manim. Om inte, uppdatera din version och försök igen." #: ../../source/reporting_bugs.rst:11 msgid "Search for other users who may have had similar issues in the past. Search the repository's `issues page `_ (don't forget to search closed issues), bring it up on our `Discord server `_, use sites like StackOverflow, and exercise your best Google practices. If you can't find anything helpful, then go to the next step." msgstr "Sök efter andra användare som kan ha haft liknande problem tidigare. Sök i arkivets (repository) `issues page `_ (glöm inte att söka även bland slutna ärenden), ta upp det i vår `Discord-server `_, använd webbplatser som StackOverflow och använd dig av dina bästa Google-metoder. Om du inte kan hitta något hjälpsamt, gå sedan till nästa steg." #: ../../source/reporting_bugs.rst:17 msgid "Can reproduce the issue, i.e. that you have some code that illustrates the bug **every time** (or at least most of the time) it is executed." msgstr "Kan reproducera problemet, dvs att du har en kod som illustrerar felet **varje gång** (eller åtminstone de flesta gångerna) det körs." #: ../../source/reporting_bugs.rst:21 msgid "Clarify what behavior you expected, and how the actual behavior differs from your expectation." msgstr "Klargör vilket beteende du förväntade dig och hur det faktiska beteendet skiljer sig från dina förväntningar." #: ../../source/reporting_bugs.rst:24 msgid "Gather information about your environment, such as your operating system, python version, and any stack traces that the code may have generated (if applicable)." msgstr "Samla information om din miljö, såsom ditt operativsystem, python-version, och eventuella stackspår som koden kan ha genererat (om möjligt)." #: ../../source/reporting_bugs.rst:28 msgid "Please open an issue only after you have gathered this information. When submitting an issue, make sure to follow the template (this is the default text you are shown when first opening the 'New Issue' page). A community member will (hopefully) respond and start a conversation to address the issue." msgstr "Vänligen öppna ett problem först efter att du har samlat in denna information. När du skickar in ett ärende, se till att följa mallen (detta är standardtexten du visas när du först öppnar sidan 'Nytt ärende'. En medlem i communityn kommer (förhoppningsvis) att svara och starta en konversation för att ta itu med problemet." ================================================ FILE: docs/i18n/sv/LC_MESSAGES/tutorials/building_blocks.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials/building_blocks.pot\n" "X-Crowdin-File-ID: 5839\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/tutorials/building_blocks.rst:3 msgid "Manim's building blocks" msgstr "Manims byggstenar" #: ../../source/tutorials/building_blocks.rst:5 msgid "This document explains the building blocks of manim and will give you all the necessary tools to start producing your own videos." msgstr "Detta dokument går igenom Manims byggstenar och ger dig alla verktyg som behövs för att börja producera dina egna videor." #: ../../source/tutorials/building_blocks.rst:8 msgid "Essentially, manim puts at your disposal three different concepts that you can orchestrate together to produce mathematical animations: the **mathematical object** (or **mobject** for short) the **animation**, and the **scene**. As we will see in the following sections, each of these three concepts is implemented in manim as a separate class: the :class:`.Mobject`, :class:`.Animation`, and :class:`.Scene` classes." msgstr "I huvudsak ställer Manim tre olika begrepp till ditt förfogande som du kan använda tillsammans med varandra för att producera matematiska animationer: det **matematiska objektet** (eller kortfattat **mobject**), **animationen** och **scenen**. Som vi kommer att se i följande avsnitt så implementeras var och ett av dessa i Manim som enskilda klasser: :class:`.Mobject`, :class:`.Animation`, och :class:`.Scene` klasserna." #: ../../source/tutorials/building_blocks.rst:15 msgid "It is recommended that you read the tutorials :doc:`quickstart` and :doc:`a_deeper_look` before reading this page." msgstr "Det rekommenderas att du först läser följande tutorials, :doc:`quickstart` och :doc:`a_deeper_look`, före du läser vidare på denna sidan." #: ../../source/tutorials/building_blocks.rst:21 msgid "Mobjects" msgstr "Mobjekt" #: ../../source/tutorials/building_blocks.rst:23 msgid "Mobjects are the basic building block for all manim animations. Each class that derives from :class:`.Mobject` represents an object that can be displayed on the screen. For example, simple shapes such as :class:`.Circle`, :class:`.Arrow`, and :class:`.Rectangle` are all mobjects. More complicated constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or :class:`.BarChart` are mobjects as well." msgstr "Mobject är den grundläggande byggstenen för alla animationer som görs i manim. Varje klass som ärver från :class:`.Mobject` representerar ett objekt som kan visas på skärmen. Som exempel är :class:`.Circle`, :class:`.Arrow`, och :class:`.Rectangle` allihopa Mobjekt. Andra mer komplicerade exempel är exempelvis :class:`.Axes`, :class:`.FunctionGraph`, och :class:`.BarChart`." #: ../../source/tutorials/building_blocks.rst:30 msgid "If you try to display an instance of :class:`.Mobject` on the screen, you will only see an empty frame. The reason is that the :class:`.Mobject` class is an abstract base class of all other mobjects, i.e. it does not have any pre-determined visual shape that can be displayed on the screen. It is only the skeleton of a thing that *could* be displayed. Therefore, you will rarely need to use plain instances of :class:`.Mobject`; instead, you will most likely create instances of its derived classes. One of these derived classes is :class:`.VMobject`. The ``V`` stands for Vectorized Mobject. In essence, a vmobject is a mobject that uses `vector graphics `_ to be displayed. Most of the time, you will be dealing with vmobjects, though we will continue to use the term \"mobject\" to refer to the class of shapes that can be displayed on the screen, as it is more general." msgstr "Om du försöker visa en instans av :class:`.Mobject` på skärmen kommer du bara att se en tom ram. Anledningen är att klassen :class:`.Mobject` är en abstrakt basklass för alla andra mobjects, dvs den har inte någon förutbestämd visuell form som kan visas på skärmen. Den är bara en skelettstruktur av en sak som *kunde* ha visats. Därför behöver du sällan använda vanliga instanser av :class:`.Mobject`; istället kommer du sannolikt att skapa instanser av dess härledda klasser. En av dessa härledda klasser är :class:`.VMobject`. ``V`` står för Vectorized Mobject. I grund och botten är ett vmobject ett mobject som använder `vektorgrafik `_ för att visas. För det mesta kommer du egentligen att hantera vmobjects men vi kommer att fortsätta att använda termen \"mobject\" för att hänvisa till klasser av former som kan visas på skärmen. Det gör vi eftersom \"mobject\" är mer allmänt." #: ../../source/tutorials/building_blocks.rst:44 msgid "Any object that can be displayed on the screen is a ``mobject``, even if it is not necessarily *mathematical* in nature." msgstr "Varje objekt som kan visas på skärmen är ett ``mobject`` även om det inte nödvändigtvis har en *matematisk* natur." #: ../../source/tutorials/building_blocks.rst:47 msgid "To see examples of classes derived from :class:`.Mobject`, see the :mod:`.geometry` module. Most of these are in fact derived from :class:`.VMobject` as well." msgstr "För att se exempel på klasser härledda från :class:`.Mobject`, se :mod:`.geometry`-modulen. De flesta av dessa härrör i själva verket från :class:`.VMobject` också." #: ../../source/tutorials/building_blocks.rst:53 msgid "Creating and displaying mobjects" msgstr "Skapa och visa mobjects" #: ../../source/tutorials/building_blocks.rst:55 msgid "As explained in :doc:`quickstart`, usually all of the code in a manim script is put inside the :meth:`.construct` method of a :class:`.Scene` class. To display a mobject on the screen, call the :meth:`~.Scene.add` method of the containing :class:`.Scene`. This is the principal way of displaying a mobject on the screen when it is not being animated. To remove a mobject from the screen, simply call the :meth:`~.Scene.remove` method from the containing :class:`.Scene`." msgstr "Som det förklaras i :doc:`quickstart` brukar all kod i ett manim-skript placeras i :meth:`.construct` metoden av en :class:`.Scene` klass. För att visa ett mobject på skärmen, anropa :meth:`~.Scene.add` metoden som finns i klassen :class:`.Scene`. Detta är det huvudsakliga sättet att visa ett mobject på skärmen när det inte animeras. För att ta bort ett mobject från skärmen anropa helt enkelt :meth:`~.Scene.remove`-metoden från klassen :class:`.Scene`." #: ../../source/tutorials/building_blocks.rst:75 msgid "Placing mobjects" msgstr "Placering av mobject" #: ../../source/tutorials/building_blocks.rst:77 msgid "Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add` some mobjects to it. This script generates a static picture that displays a circle, a square, and a triangle:" msgstr "Vi definierar nu en ny :class:`.Scene` som heter ``Shapes`` och lägger till några mobject till den med hjälp av metoden :meth:`~.Scene.add`. Detta skript genererar en orörlig bild som visar en cirkel, en kvadrat, och en triangel:" #: ../../source/tutorials/building_blocks.rst:96 msgid "By default, mobjects are placed at the center of coordinates, or *origin*, when they are first created. They are also given some default colors. Further, the ``Shapes`` scene places the mobjects by using the :meth:`.shift` method. The square is shifted one unit in the ``UP`` direction from the origin, while the circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively." msgstr "Som standard placeras mobjects i mitten av koordinatsystemet, eller *origin* (sv. origo), när de först skapas. De får också några standardfärger. Vidare placerar scenen ``Shapes`` mobject genom att använda :meth:`.shift` metoden. Kvadraten flyttas en enhet i ``UP`` riktningen från origo, medan cirkeln och triangeln respektive skiftas en enhet ``LEFT`` och ``RIGHT``." #: ../../source/tutorials/building_blocks.rst:102 msgid "Unlike other graphics software, manim places the center of coordinates at the center of the screen. The positive vertical direction is up, and the positive horizontal direction is right. See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT``, and others, defined in the :mod:`.constants` module." msgstr "Till skillnad från andra grafikprogram placerar manim centrum av koordinatsystemet i mitten av skärmen. Den positiva vertikala riktningen är uppåt, och den positiva horisontella riktningen är åt höger. Se även konstanterna ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT`` och andra konstanter som definieras i :mod:`.constants`-modulen." #: ../../source/tutorials/building_blocks.rst:108 msgid "There are many other possible ways to place mobjects on the screen, for example :meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`. The next scene ``MobjectPlacement`` uses all three." msgstr "Det finns många andra sätt att placera mobjekt på skärmen, till exempel genom metoderna :meth:`. move_to`, :meth:`.next_to` och :meth:`.align_to`. Nästa scen ``MobjectPlacement`` använder sig av alla tre." #: ../../source/tutorials/building_blocks.rst:130 msgid "The :meth:`.move_to` method uses absolute units (measured relative to the ``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the mobject passed as the first argument). :meth:`align_to` uses ``LEFT`` not as measuring units but as a way to determine the border to use for alignment. The coordinates of the borders of a mobject are determined using an imaginary bounding box around it." msgstr "Metoden :meth:`.move_to` använder sig av absoluta enheter (alltså, givet i förhållande till ``ORIGIN``), medan :meth:`.next_to` använder sig av relativa enheter (alltså, givet i förhållande till det mobject som ges i första argumentet). :meth:`align_to` använder ``LEFT`` inte som en mätenhet utan som ett sätt att bestämma vilket gränssnitt som mobjectet ska justeras till. Koordinaterna för ett mobjects gränser bestäms med hjälp av en icke-visuell begränsningsruta runt den." #: ../../source/tutorials/building_blocks.rst:137 msgid "Many methods in manim can be chained together. For example the two lines" msgstr "Många metoder i manim kan kedjas ihop. Till exempel de två raderna" #: ../../source/tutorials/building_blocks.rst:145 msgid "can be replaced by" msgstr "kan ersättas med" #: ../../source/tutorials/building_blocks.rst:151 msgid "Technically, this is possible because most methods calls return the modified mobject." msgstr "Tekniskt sett är detta möjligt eftersom de flesta metodanrop returnerar det modifierade mobjectet." #: ../../source/tutorials/building_blocks.rst:155 msgid "Styling mobjects" msgstr "Styla mobject" #: ../../source/tutorials/building_blocks.rst:157 msgid "The following scene changes the default aesthetics of the mobjects." msgstr "Följande scen ändrar mobjektens standardutseende." #: ../../source/tutorials/building_blocks.rst:174 msgid "This scene uses two of the main functions that change the visual style of a mobject: :meth:`.set_stroke` and :meth:`.set_fill`. The former changes the visual style of the mobject's border while the latter changes the style of the interior. By default, most mobjects have a fully transparent interior so you must specify the ``opacity`` parameter to display the color. An opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent." msgstr "Denna scen använder två huvudfunktioner som ändrar den visuella stilen på ett mobject: :meth:`.set_stroke` och :meth:`.set_fill`. Den första ändrar den visuella stilen på mobjectets rand medan den andra ändrar stilen på interiören. Som standard har de flesta mobjects en helt genomskinlig interiör så du måste ange parametern ``opacity`` för att visa färgen. Ett opacitetsvärde på ``1.0`` betyder helt ogenomskinlig, medan ``0.0`` betyder helt genomskinlig." #: ../../source/tutorials/building_blocks.rst:181 msgid "Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and :meth:`.set_fill`. Instances of :class:`.Mobject` implement :meth:`.~Mobject.set_color` instead. The vast majority of pre-defined classes are derived from :class:`.VMobject` so it is usually safe to assume that you have access to :meth:`.set_stroke` and :meth:`.set_fill`." msgstr "Endast instanser av :class:`.VMobject` implementerar :meth:`.set_stroke` och :meth:`.set_fill`. Instanser av :class:`.Mobject` implementerar :meth:`.~Mobject.set_color` istället. De allra flesta fördefinierade klasser härstammar från :class:`.VMobject` så det är vanligtvis säkert att anta att du har tillgång till :meth:`.set_stroke` och :meth:`.set_fill`." #: ../../source/tutorials/building_blocks.rst:189 msgid "Mobject on-screen order" msgstr "Ordningen av Mobject på skärmen" #: ../../source/tutorials/building_blocks.rst:191 msgid "The next scene is exactly the same as the ``MobjectStyling`` scene from the previous section, except for exactly one line." msgstr "Nästa scen är exakt samma som ``MobjectStyling`` scenen från föregående avsnitt, med undantag för exakt en rad." #: ../../source/tutorials/building_blocks.rst:209 msgid "The only difference here (besides the scene name) is the order in which the mobjects are added to the scene. In ``MobjectStyling``, we added them as ``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as ``add(triangle, square, circle)``." msgstr "Den enda skillnaden här (förutom scennamnet) är den ordning i vilken mobjects läggs till i scenen. I ``MobjectStyling``, lade vi till dem som ``add(circle, square, triangle)``, medan vi i ``MobjectZOrder`` lägger till dem som ``add(triangle, square, circle)``." #: ../../source/tutorials/building_blocks.rst:214 msgid "As you can see, the order of the arguments of :meth:`~.Scene.add` determines the order that the mobjects are displayed on the screen, with the left-most arguments being put in the back." msgstr "Som du kan se så bestämmer ordningen på argumenten i :meth:`~.Scene.add` den ordning som mobjects visas på skärmen, så att argumentet längst till vänster hamnar längst bak." #: ../../source/tutorials/building_blocks.rst:221 msgid "Animations" msgstr "Animationer" #: ../../source/tutorials/building_blocks.rst:223 msgid "At the heart of manim is animation. Generally, you can add an animation to your scene by calling the :meth:`~.Scene.play` method." msgstr "Manims största syfte är att animera. Allmänt så kan du lägga till en animation till din scen genom att anropa :meth:`~.Scene.play`-metoden." #: ../../source/tutorials/building_blocks.rst:244 msgid "Put simply, animations are procedures that interpolate between two mobjects. For example, :code:`FadeIn(square)` starts with a fully transparent version of :code:`square` and ends with a fully opaque version, interpolating between them by gradually increasing the opacity. :class:`.FadeOut` works in the opposite way: it interpolates from fully opaque to fully transparent. As another example, :class:`.Rotate` starts with the mobject passed to it as argument, and ends with the same object but rotated by a certain amount, this time interpolating the mobject's angle instead of its opacity." msgstr "Enkelt uttryckt är animationer procedurer som interpolerar mellan två mobjects. Till exempel börjar :code:`FadeIn(square)` med en helt genomskinlig version av :code:`square` och avslutas med en helt ogenomskinlig version, och detta sker genom att interpolera mellan dem genom att gradvis öka opaciteten. :class:`.FadeOut` fungerar på motsatt sätt: den interpolerar från helt ogenomskinlig till helt genomskinlig. Som ett annat exempel :class:`.Rotate` börjar med mobjectet som skickats till det som argument, och slutar med samma objekt men roterat med ett visst belopp, genom att denna gångenn interpolera mobjektets vinkel istället för dess opacitet." #: ../../source/tutorials/building_blocks.rst:255 msgid "Animating methods" msgstr "Animeringsmetoder" #: ../../source/tutorials/building_blocks.rst:257 msgid "Any property of a mobject that can be changed can be animated. In fact, any method that changes a mobject's property can be used as an animation, through the use of :meth:`.animate`." msgstr "Varje egenskap hos ett mobject som kan ändras kan även animeras. Faktum är att alla metoder som ändrar ett mobjects egenskaper kan användas som en animation genom att använda :meth:`.animate`." #: ../../source/tutorials/building_blocks.rst:277 msgid ":meth:`.animate` is a property of all mobjects that animates the methods that come afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of the square, while :code:`sqaure.animate.set_fill(WHITE)` animates this action." msgstr ":meth:`.animate` är en egenskap hos alla mobjekt som animerar metoderna som kommer efteråt. Till exempel anger :code:`square.set_fill(WHITE)` fyllnadsfärgen på fyrkanten, medan :code:`square.animate.set_fill(WHITE)` animerar detta." #: ../../source/tutorials/building_blocks.rst:282 msgid "Animation run time" msgstr "Animationens körtid" #: ../../source/tutorials/building_blocks.rst:284 msgid "By default, any animation passed to :meth:`play` lasts for exactly one second. Use the :code:`run_time` argument to control the duration." msgstr "Som standard varar varje animation som skickats till :meth:`play` i exakt en sekund. Använd argumentet :code:`run_time` för att kontrollera varaktigheten." #: ../../source/tutorials/building_blocks.rst:297 msgid "Creating a custom animation" msgstr "Skapa en egen animation" #: ../../source/tutorials/building_blocks.rst:299 msgid "Even though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another. If you find yourself in that situation, then you can define your own custom animation. You start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`. The :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation. So, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method. Then you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions." msgstr "Även om Manim har många inbyggda animationer, kommer det vara stunder när du behöver animera smidigt från ett tillstånd av ett :class:`~.Mobject` till ett annat. Om du befinner dig i den situationen kan du definiera en egen animation. Du börjar med att utöka :class:`~.Animation`-klassen och åsidosätter dess :meth:`~.Animation.interpolate_mobject`. :meth:`~.Animation.interpolate_mobject` -metoden får alfa som en parameter som startar vid 0 och ändras under hela animationen. Så du behöver bara manipulera self.mobject inuti Animation enligt alfa värdet i dess interpolate_mobject-metod. Då får du alla fördelar med :class:`~.Animation` såsom att spela det under olika körtider eller använda olika hastighetsfunktioner." #: ../../source/tutorials/building_blocks.rst:306 msgid "Let's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number. You can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number. But when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly. Manim has a feature that allows you to customize this behavior by defining your own custom animation." msgstr "Låt oss säga att du börjar med ett tal och vill skapa en :class:`~.Transform`-animation som omvandlar talet till ett annat givet tal. Du kan göra det med :class:`~.FadeTransform`, vilket kommer att tona bort det första talet och tona in det andra talet. Men när vi tänker på att omvandla ett tal till ett annat, är ett intuitivt sätt att göra det genom att inkrementera eller dekrementera det på ett smidigt sätt. Manim har en funktion som gör att du kan anpassa detta beteende genom att definiera din egen animation." #: ../../source/tutorials/building_blocks.rst:311 msgid "You can start by creating your own ``Count`` class that extends :class:`~.Animation`. The class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end. The constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end." msgstr "Du kan börja med att skapa din egen ``Count`` klass som utökar klassen :class:`~.Animation`. Klassen kan ha en konstruktor med tre argument, ett :class:`~.DecimalNumber` Mobject, start and end. Konstruktorn kommer att skicka :class:`~.DecimalNumber` Mobject till superkonstruktorn (i detta fall konstruktorn i :class:`~.Animation`) och kommer att ställa in start och slut." #: ../../source/tutorials/building_blocks.rst:315 msgid "The only thing that you need to do is to define how you want it to look at every step of the animation. Manim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played. The alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation. For example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation." msgstr "Det enda du behöver göra är att definiera hur du vill att det ska se ut för varje steg i animationen. Manim ger dig alfavärdet i :meth:`~. nimation.interpolate_mobject' metoden baserat på bildhastigheten av videon, hastighetsfunktionen och körtiden för den animation som spelas. Alfaparametern har ett värde mellan 0 och 1 som representerar steget i den aktuella animationen. Till exempel betyder 0 början av animationen, 0,5 betyder halvvägs genom animationen och 1 betyder slutet av animationen." #: ../../source/tutorials/building_blocks.rst:320 msgid "In the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation. Suppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation." msgstr "I fallet med ``Count`` animationen, behöver du bara hitta ett sätt att bestämma talet som ska visas för det givna alfavärdet och sedan ange det värdet i :meth:`~.Animation.interpolate_mobject` -metoden för ``Count``-animationen. Antag att du börjar med 50 och inkrementerar värdet tills :class:`~.DecimalNumber` når 100 i slutet av animationen." #: ../../source/tutorials/building_blocks.rst:323 msgid "If alpha is 0, you want the value to be 50." msgstr "Om alfa är 0, vill du att värdet ska vara 50." #: ../../source/tutorials/building_blocks.rst:324 msgid "If alpha is 0.5, you want the value to be 75." msgstr "Om alfa är 0,5, vill du att värdet ska vara 75." #: ../../source/tutorials/building_blocks.rst:325 msgid "If alpha is 1, you want the value to be 100." msgstr "Om alfa är 1, vill du att värdet ska vara 100." #: ../../source/tutorials/building_blocks.rst:327 msgid "Generally, you start with the starting number and add only some part of the value to be increment according to the alpha value. So, the logic of calculating the number to display at each step will be - 50 + alpha * (100 - 50). Once you set the calculated value for the :class:`~.DecimalNumber`, you are done." msgstr "Allmänt så börjar du med startnumret och adderar bara en del av värdet som ska inkrementeras enligt vad alfavärdet är. Så den programlogik som behövs för att beräkna talet som ska visas vid varje steg kommer att vara - 50 + alfa * (100 - 50). När du satt det beräknade värdet för :class:`~.DecimalNumber`-klassen är du klar." #: ../../source/tutorials/building_blocks.rst:331 msgid "Once you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function." msgstr "När du väl har definierat din ``Count`` animation kan du spela upp den i din :class:`~.Scene` med given varaktighet för vilken klass :class:`~.DecimalNumber` som helst, med valfri hastighetsfunktion." #: ../../source/tutorials/building_blocks.rst:368 msgid "Using coordinates of a mobject" msgstr "Använda ett mobjects koordinater" #: ../../source/tutorials/building_blocks.rst:370 msgid "Mobjects contain points that define their boundaries. These points can be used to add other mobjects respectively to each other, e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:" msgstr "Mobject innehåller punkter som definierar objektets rand. Dessa punkter kan användas för att lägga till andra mobjects gentemot varandra, t.ex. genom metoder som :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` och :meth:`~.Mobject.get_start`. Här är ett exempel på några viktiga koordinater:" #: ../../source/tutorials/building_blocks.rst:402 msgid "Transforming mobjects into other mobjects" msgstr "Omvandla mobjects till andra mobjects" #: ../../source/tutorials/building_blocks.rst:403 msgid "It is also possible to transform a mobject into another mobject like this:" msgstr "Det är också möjligt att förvandla ett mobject till ett annat mobject på detta vis:" #: ../../source/tutorials/building_blocks.rst:414 msgid "The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the `flip` function and reposition the points via the `roll `_ function of numpy:" msgstr "Transform-funktionen avbildar punkter hos det tidigare mobjectet till punkterna i nästa mobject. Detta kan resultera i konstigt beteende, t.ex. när punkter av ett mobject arrangeras medsols och det andra mobjectets punkter arrangeras motsols. Här kan det hjälpa att använda `flip`-funktionen och flytta punkterna via `roll `_ funktionen i numpy:" #: ../../source/tutorials/building_blocks.rst:440 msgid "Scenes" msgstr "Scener" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/tutorials/quickstart.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials/quickstart.pot\n" "X-Crowdin-File-ID: 5843\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:29\n" #: ../../source/tutorials/quickstart.rst:3 msgid "Quickstart" msgstr "Snabbstart" #: ../../source/tutorials/quickstart.rst:5 msgid "This document will lead you step by step through the necessary procedure to get started with manim for the first time as soon as possible. This tutorial assumes you have already installed manim following the steps in :doc:`../installation`." msgstr "Detta dokument kommer att leda dig steg för steg genom de nödvändiga stegen för att komma igång med manim för första gången. Den här övningen förutsätter att du redan har installerat manim efter stegen i :doc:`../installation`." #: ../../source/tutorials/quickstart.rst:12 msgid "Start a new project" msgstr "Starta ett nytt projekt" #: ../../source/tutorials/quickstart.rst:14 msgid "To start a new manim video project, all you need to do is choose a single folder where all of the files related to the video will reside. For this example, this folder will be called ``project``," msgstr "För att starta ett nytt manimvideoprojekt är allt du behöver göra att välja eller skapa en enda mapp där alla filer relaterade till videon kommer sparas. Till exempel kommer den här mappen att heta ``project``," #: ../../source/tutorials/quickstart.rst:22 msgid "Every file containing code that produces a video with manim will be stored here, as well as any output files that manim produces and configuration files that manim needs." msgstr "Varje fil som innehåller kod som genererar en video med manim kommer att lagras här, samt alla utdatafiler som manim producerar och konfigurationsfiler som manim behöver." #: ../../source/tutorials/quickstart.rst:28 msgid "In case you like to work with Jupyterlab / Jupyter notebooks, there is good news: Manim ships with a ``%%manim`` IPython magic command which makes it easy to use in such a setting as well. Find out more in the :meth:`corresponding documentation `." msgstr "Om du föredrar att arbeta med Jupyterlab / Jupyter notebooks så finns goda nyheter: Manim utges med ett ``%%manim`` IPython magic command som gör det enkelt att använda Manim i en sådan miljö också. Läs mer i :meth:`motsvarande dokumentation `." #: ../../source/tutorials/quickstart.rst:35 msgid "Your first Scene" msgstr "Din första scen" #: ../../source/tutorials/quickstart.rst:37 msgid "To produce your first scene, create a new file in your project folder called ``scene.py``," msgstr "För att producera din första scen skapar du en ny fil i din projektmapp som heter ``scene.py``," #: ../../source/tutorials/quickstart.rst:45 msgid "and copy the following code in it." msgstr "och klistra in följande kod in i den." #: ../../source/tutorials/quickstart.rst:58 msgid "Then open your command line, navigate to your project directory, and execute the following command:" msgstr "Öppa sedan din command line, navigera till din projectkatalog och kör följande kommando:" #: ../../source/tutorials/quickstart.rst:65 msgid "After showing some output, manim should render the scene into a .mp4 file, and open that file with the default movie player application. You should see a video playing the following animation." msgstr "Efter att ha visat lite utdata bör manim göra scenen till en .mp4 fil, samt öppna filen med din standard videospelare. Du bör se en video som spelar upp följande animation." #: ../../source/tutorials/quickstart.rst:78 msgid "If you see the video and it looks correct, congrats! You just wrote your first manim scene from scratch. If you get an error message instead, or if do not see a video, or if the video output does not look like this, it is likely that manim has not been installed correctly. Please refer to the :doc:`../installation/troubleshooting` page for more information." msgstr "Om du ser videon och den ser korrekt ut, grattis! Du har precis skrivit din första manimscen från grunden. Om du får ett felmeddelande istället, om du inte kan se en video eller om den producerade videon inte ser ut så här så är det troligt att manim inte har installerats korrekt. Se sidan :doc:`../installation/troubleshooting` för mer information." #: ../../source/tutorials/quickstart.rst:87 msgid "Explanation" msgstr "Förklaring" #: ../../source/tutorials/quickstart.rst:89 msgid "Let's go line by line over the script we just executed to see how manim was able to generate the video." msgstr "Låt oss gå rad för rad genom skriptet som vi just körde för att se hur manim kunde generera videon." #: ../../source/tutorials/quickstart.rst:92 msgid "The first line" msgstr "Första raden" #: ../../source/tutorials/quickstart.rst:98 msgid "imports all of the contents of the library. This is the recommended way of using manim, as usually in a single script you will be using quite a few names from the manim namespace. In particular, this line includes all of the names used in the script: ``Scene``, ``Circle``, ``PINK`` and ``Create``." msgstr "importerar allt innehåll i biblioteket. Detta är det rekommenderade sättet att använda manim eftersom du vanligtvis kommer att använda en hel del namn från manims namespace i ett enda skript. Speciellt innehåller den här raden alla namn som används i skriptet: ``Scene``, ``Circle``, ``PINK`` och ``Create``." #: ../../source/tutorials/quickstart.rst:103 msgid "Now let's look at the next two lines." msgstr "Nu kan vi titta på de nästa två raderna." #: ../../source/tutorials/quickstart.rst:111 msgid "Most of the time, the code for scripting an animation with manim will go inside the :meth:`~.Scene.construct` method of a class that derives from :class:`.Scene`. Inside this method, you will create objects, display them on screen, and animate them." msgstr "Merparten av tiden, kommer koden för att skripta en animation med manim att gå in i :meth:`~.Scene. onstruct` metoden av en klass som härstammar från :class:`.Scene`. Inuti denna metod kommer du att skapa objekt, visa dem på skärmen och animera dem." #: ../../source/tutorials/quickstart.rst:115 msgid "The next two lines create a circle and set its color and opacity." msgstr "De två nästkommande två raderna skapar en cirkel och anger dess färg och opacitet." #: ../../source/tutorials/quickstart.rst:122 msgid "Finally, the last line uses the animation :class:`.Create` to display the circle on the screen." msgstr "Slutligen använder den sista raden animationen :class:`.Create` för att visa cirkeln på skärmen." #: ../../source/tutorials/quickstart.rst:129 msgid "Every animation must be contained within the :meth:`~.Scene.construct` method of a class that derives from :class:`.Scene`. Other code, for example auxiliary or mathematical functions, may reside outside the class." msgstr "Varje animation måste finnas i :meth:`~.Scene.construct`-metoden i en klass som härstammar från :class:`.Scene`. Annan kod, till exempel hjälpfunktioner eller matematiska funktioner, får finnas utanför klassen." #: ../../source/tutorials/quickstart.rst:135 msgid "Some bells and whistles" msgstr "Lite extra fint och glans" #: ../../source/tutorials/quickstart.rst:137 msgid "Our scene is a little basic, so let's add some bells and whistles. Modify the ``scene.py`` file to contain the following:" msgstr "Vår scen är lite platt och tråkig, så vi kan lägga till lite extra glans. Ändra filen ``scene.py`` så att den innehåller följande:" #: ../../source/tutorials/quickstart.rst:157 msgid "And render it using the following command:" msgstr "Och rendera den genom att använda följande kommando:" #: ../../source/tutorials/quickstart.rst:163 msgid "The output should look as follows." msgstr "Utmatningen från skriptet bör se ut på följande sätt." #: ../../source/tutorials/quickstart.rst:180 msgid "This example shows one of the most basic features of manim: the ability to implement complicated and mathematically intensive animations (such as cleanly interpolating between two geometric shapes) in very few lines of code." msgstr "Detta exempel visar en av de mest grundläggande funktionerna hos manim: förmågan att genomföra komplicerade och matematiskt intensiva animationer (såsom att snyggt interpolera mellan två geometriska former) i mycket få rader av kod." #: ../../source/tutorials/quickstart.rst:187 msgid "You're done!" msgstr "Du är klar!" ================================================ FILE: docs/i18n/sv/LC_MESSAGES/tutorials.po ================================================ msgid "" msgstr "" "Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\n" "X-Crowdin-Project-ID: 1\n" "X-Crowdin-Language: sv\n" "X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials.pot\n" "X-Crowdin-File-ID: 5835\n" "Language-Team: Swedish\n" "Language: sv_SE\n" "PO-Revision-Date: 2021-11-06 12:30\n" #: ../../source/tutorials.rst:4 #: ../../source/tutorials.rst:4 msgid "Table of Contents" msgstr "Innehållsförteckning" ================================================ FILE: docs/make.bat ================================================ @ECHO OFF pushd %~dp0\source REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) REM The paths are taken from the source directory set SOURCEDIR=. set BUILDDIR=..\build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd ================================================ FILE: docs/requirements.txt ================================================ furo myst-parser sphinx>=7.3 sphinx-copybutton sphinxext-opengraph sphinx-design sphinx-reredirects ================================================ FILE: docs/rtd-requirements.txt ================================================ jupyterlab sphinxcontrib-programoutput ================================================ FILE: docs/skip-manim ================================================ ================================================ FILE: docs/source/_static/custom.css ================================================ @media (prefers-color-scheme: dark) { span.nc { text-decoration: none !important; } } .admonition-manim-example { padding: 0; display: flex; flex-direction: column; } .admonition-manim-example p.admonition-title { font-weight: 600; font-size: 0.925rem; margin: 0; } .admonition-manim-example .highlight-python { margin: 0; } .admonition-manim-example .highlight { border-radius: 0; } .admonition-manim-example .highlight pre { font-size: 15px; } .manim-video { width: 100%; padding: 8px 0; outline: 0; } .admonition-manim-example .manim-video { padding: 0; } .admonition-manim-example img { margin-bottom: 0; } .admonition-manim-example p:last-child { margin-top: 0; padding-left: 0.5rem; padding-bottom: 0.15rem; font-size: 15px; } .admonition-manim-example .copybtn { margin-right: 6px; font-size: 18px; } .admonition-manim-example .copybtn:hover { cursor: pointer; } p.rubric{ text-transform: capitalize; font-size: 1.25rem; font-weight: bold; } .sig-param{ color: var(--color-content-foreground); } dl.c .field-list dt, dl.cpp .field-list dt, dl.js .field-list dt, dl.py .field-list dt { text-transform: capitalize; font-weight: bold; font-size: var(--font-size--normal); } h4, h5, h6{ text-transform: none; } /* yikes-ish attempt at bugfix for navbar on some browsers */ .sidebar-tree a.internal.reference { display: table-cell; } .manim-binder-button { text-transform: capitalize; padding: 10px 20px; margin: 10px 0; } .manim-binder-wrapper { background-color: var(--color-code-background); color: var(--color-code-foreground); } .manim-binder-title { margin-top: 0; } .manim-binder-button-wrapper { margin: 0px 10px; } ================================================ FILE: docs/source/_static/manim-binder.min.js.LICENSE.txt ================================================ /*! * is-plain-object * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ ================================================ FILE: docs/source/_static/responsiveSvg.js ================================================ window.addEventListener("load", function () { const styleElements = [] const colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)'); const diagrams = document.querySelectorAll("object.inheritance.graphviz"); for (let diagram of diagrams) { style = document.createElement('style'); styleElements.push(style); console.log(diagram); diagram.contentDocument.firstElementChild.appendChild(style); } function setColorScheme(e) { let colors, additions = ""; if (e.matches) { // Dark colors = { text: "#e07a5f", box: "#383838", edge: "#d0d0d0", background: "#131416" }; } else { // Light colors = { text: "#e07a5f", box: "#fff", edge: "#413c3c", background: "#ffffff" }; additions = ` .node polygon { filter: drop-shadow(0 1px 3px #0002); } ` } for (let style of styleElements) { style.innerHTML = ` svg { background-color: ${colors.background}; } .node text { fill: ${colors.text}; } .node polygon { fill: ${colors.box}; } .edge polygon { fill: ${colors.edge}; stroke: ${colors.edge}; } .edge path { stroke: ${colors.edge}; } ${additions} `; } } setColorScheme(colorSchemeQuery); colorSchemeQuery.addEventListener("change", setColorScheme); }); ================================================ FILE: docs/source/_templates/autosummary/class.rst ================================================ {{ name | escape | underline}} Qualified name: ``{{ fullname | escape }}`` .. currentmodule:: {{ module }} .. autoclass:: {{ objname }} :show-inheritance: :members: :private-members: {% block methods %} {%- if methods %} .. rubric:: {{ _('Methods') }} .. autosummary:: :nosignatures: {% for item in methods if item != '__init__' and item not in inherited_members %} ~{{ name }}.{{ item }} {%- endfor %} {%- endif %} {%- endblock %} {% block attributes %} {%- if attributes %} .. rubric:: {{ _('Attributes') }} .. autosummary:: {% for item in attributes %} ~{{ name }}.{{ item }} {%- endfor %} {%- endif %} {% endblock %} ================================================ FILE: docs/source/_templates/autosummary/module.rst ================================================ {{ name | escape | underline }} .. currentmodule:: {{ fullname }} .. automodule:: {{ fullname }} {# SEE manim.utils.docbuild.autoaliasattr_directive #} {# FOR INFORMATION ABOUT THE CUSTOM autoaliasattr DIRECTIVE! #} .. autoaliasattr:: {{ fullname }} {% block classes %} {% if classes %} .. rubric:: Classes .. autosummary:: :toctree: . :nosignatures: {% for class in classes %} {{ class }} {% endfor %} {% endif %} {% endblock %} {% block functions %} {% if functions %} .. rubric:: {{ _('Functions') }} {% for item in functions %} .. autofunction:: {{ item }} {%- endfor %} {% endif %} {% endblock %} {% block exceptions %} {% if exceptions %} .. rubric:: {{ _('Exceptions') }} .. autosummary:: {% for item in exceptions %} {{ item }} {%- endfor %} {% endif %} {% endblock %} {% block modules %} {% if modules %} .. rubric:: Modules .. autosummary:: :toctree: :recursive: {% for item in modules %} {{ item }} {%- endfor %} {% endif %} {% endblock %} ================================================ FILE: docs/source/_templates/logo-text.html ================================================ ManimCommunity logo ================================================ FILE: docs/source/changelog/0.1.0-changelog.rst ================================================ ****** v0.1.0 ****** :Date: October 21, 2020 This is the first release of manimce after forking from 3b1b/manim. As such, developers have focused on cleaning up and refactoring the codebase while still maintaining backwards compatibility wherever possible. New Features ============ Command line ------------ #. Output of 'manim --help' has been improved #. Implement logging with the :code:`rich` library and a :code:`logger` object instead of plain ol' prints #. Added a flag :code:`--dry_run`, which doesn't write any media #. Allow for running manim with :code:`python3 -m manim` #. Refactored Tex Template management. You can now use custom templates with command line args using :code:`--tex_template`! #. Re-add :code:`--save_frames` flag, which will save each frame as a png #. Re-introduce manim feature that allows you to type manim code in :code:`stdin` if you pass a minus sign :code:`(-)` as filename #. Added the :code:`--custom_folders` flag which yields a simpler output folder structure #. Re-implement GIF export with the :code:`-i` flag (using this flag outputs ONLY a .gif file, and no .mp4 file) #. Added a :code:`--verbose` flag #. You can save the logs to a file by using :code:`--log_to_file` #. Read :code:`tex_template` from config file if not specified by :code:`--tex_template`. #. Add experimental javascript rendering with :code:`--use_js_renderer` #. Add :code:`-q/--quality [k|p|h|m|l]` flag and removed :code:`-m/-l` flags. #. Removed :code:`--sound` flag Config system ------------- #. Implement a :code:`manim.cfg` config file system, that consolidates the global configuration, the command line argument parsing, and some of the constants defined in :code:`constants.py` #. Added utilities for manipulating Manim’s :code:`.cfg` files. #. Added a subcommand structure for easier use of utilities managing :code:`.cfg` files #. Also some variables have been moved from ``constants.py`` to the new config system: #. ``FRAME_HEIGHT`` to ``config["frame_width"]`` #. ``TOP`` to ``config["frame_height"] / 2 * UP`` #. ``BOTTOM`` to ``config["frame_height"] / 2 * DOWN`` #. ``LEFT_SIDE`` to ``config["frame_width"] / 2 * LEFT`` #. ``RIGHT_SIDE`` to ``config["frame_width"] / 2 * RIGHT`` #. ``self.camera.frame_rate`` to ``config["frame_rate"]`` Mobjects, Scenes, and Animations -------------------------------- #. Add customizable left and right bracket for :code:`Matrix` mobject and :code:`set_row_colors` method for matrix mobject #. Add :code:`AddTeXLetterByLetter` animation #. Enhanced GraphScene #. You can now add arrow tips to axes #. extend axes a bit at the start and/or end #. have invisible axes #. highlight the area between two curves #. ThreeDScene now supports 3dillusion_camera_rotation #. Add :code:`z_index` for manipulating depth of Objects on scene. #. Add a :code:`VDict` class: a :code:`VDict` is to a :code:`VGroup` what a :code:`dict` is to a :code:`list` #. Added Scene-caching feature. Now, if a partial movie file is unchanged in your code, it isn’t rendered again! [HIGHLY UNSTABLE We're working on it ;)] #. Most :code:`get_` and :code:`set_` methods have been removed in favor of instance attributes and properties #. The :code:`Container` class has been made into an AbstractBaseClass, i.e. in cannot be instantiated. Instead, use one of its children classes #. The ``TextMobject`` and ``TexMobject`` objects have been deprecated, due to their confusing names, in favour of ``Tex`` and ``MathTex``. You can still, however, continue to use ``TextMobject`` and ``TexMobject``, albeit with Deprecation Warnings constantly reminding you to switch. #. Add a :code:`Variable` class for displaying text that continuously updates to reflect the value of a python variable. #. The ``Tex`` and ``MathTex`` objects allow you to specify a custom TexTemplate using the ``template`` keyword argument. #. :code:`VGroup` now supports printing the class names of contained mobjects and :code:`VDict` supports printing the internal dict of mobjects #. Add all the standard easing functions #. :code:`Scene` now renders when :code:`Scene.render()` is called rather than upon instantiation. #. :code:`ValueTracker` now supports increment using the `+=` operator (in addition to the already existing `increment_value` method) #. Add :class:`PangoText` for rendering texts using Pango. Documentation ============= #. Added clearer installation instructions, tutorials, examples, and API reference [WIP] Fixes ===== #. Initialization of directories has been moved to :code:`config.py`, and a bunch of bugs associated to file structure generation have been fixed #. Nonfunctional file :code:`media_dir.txt` has been removed #. Nonfunctional :code:`if` statements in :code:`scene_file_writer.py` have been removed #. Fix a bug where trying to render the example scenes without specifying the scene would show all scene objects in the library #. Many :code:`Exceptions` have been replaced for more specific exception subclasses #. Fixed a couple of subtle bugs in :code:`ArcBetweenPoints` Of interest to developers ========================= #. Python code formatting is now enforced by using the :code:`black` tool #. PRs now require two approving code reviews from community devs before they can be merged #. Added tests to ensure stuff doesn't break between commits (For developers) [Uses Github CI, and Pytest] #. Add contribution guidelines (for developers) #. Added autogenerated documentation with sphinx and autodoc/autosummary [WIP] #. Made manim internally use relative imports #. Since the introduction of the :code:`TexTemplate` class, the files :code:`tex_template.tex` and :code:`ctex_template.tex` have been removed #. Added logging tests tools. #. Added ability to save logs in json #. Move to Poetry. #. Colors have moved to an Enum Other Changes ============= #. Cleanup 3b1b Specific Files #. Rename package from manimlib to manim #. Move all imports to :code:`__init__`, so :code:`from manim import *` replaces :code:`from manimlib.imports import *` #. Global dir variable handling has been removed. Instead :code:`initialize_directories`, if needed, overrides the values from the cfg files at runtime. ================================================ FILE: docs/source/changelog/0.1.1-changelog.rst ================================================ ****** v0.1.1 ****** :Date: December 1, 2020 Changes since Manim Community release v0.1.0 Plugins ======= #. Provided a standardized method for plugin discoverability, creation, installation, and usage. See the :ref:`documentation `. Fixes ===== #. JsRender is optional to install. (via :pr:`697`). #. Allow importing modules from the same directory as the input file when using ``manim`` from the command line (via :pr:`724`). #. Remove some unnecessary or unpythonic methods from :class:`~.Scene` (``get_mobjects``, ``add_mobjects_among``, ``get_mobject_copies``), via :pr:`758`. #. Fix formatting of :class:`~.Code` (via :pr:`798`). Configuration ============= #. Removed the ``skip_animations`` config option and added the ``Renderer.skip_animations`` attribute instead (via :pr:`696`). #. The global ``config`` dict has been replaced by a global ``config`` instance of the new class :class:`~.ManimConfig`. This class has a dict-like API, so this should not break user code, only make it more robust. See the Configuration tutorial for details. #. Added the option to configure a directory for external assets (via :pr:`649`). Documentation ============= #. Add ``:issue:`` and ``:pr:`` directives for simplifying linking to issues and pull requests on GitHub (via :pr:`685`). #. Add a ``skip-manim`` tag for skipping the ``.. manim::`` directive when building the documentation locally (via :pr:`796`). Mobjects, Scenes, and Animations ================================ #. The ``alignment`` attribute to Tex and MathTex has been removed in favour of ``tex_environment``. #. :class:`~.Text` now uses Pango for rendering. ``PangoText`` has been removed. The old implementation is still available as a fallback as :class:`~.CairoText`. #. Variations of :class:`~.Dot` have been added as :class:`~.AnnotationDot` (a bigger dot with bolder stroke) and :class:`~.LabeledDot` (a dot containing a label). #. Scene.set_variables_as_attrs has been removed (via :pr:`692`). #. Ensure that the axes for graphs (:class:`GraphScene`) always intersect (:pr:`580`). #. Now Mobject.add_updater does not call the newly-added updater by default (use ``call_updater=True`` instead) (via :pr:`710`) #. VMobject now has methods to determine and change the direction of the points (via :pr:`647`). #. Added BraceBetweenPoints (via :pr:`693`). #. Added ArcPolygon and ArcPolygonFromArcs (via :pr:`707`). #. Added Cutout (via :pr:`760`). #. Added Mobject raise not implemented errors for dunder methods and implementations for VGroup dunder methods (via :pr:`790`). #. Added :class:`~.ManimBanner` for a animated version of our logo and banner (via :pr:`729`) #. The background color of a scene can now be changed reliably by setting, e.g., ``self.camera.background_color = RED`` (via :pr:`716`). ================================================ FILE: docs/source/changelog/0.10.0-changelog.rst ================================================ ******* v0.10.0 ******* :Date: September 01, 2021 Contributors ============ A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Animfysyk + * Benjamin Hackl * Christian Clauss * Daniel Adelodun + * Darigov Research * Darylgolden * Eric Biedert + * Harivinay * Jan-Hendrik Müller * Jephian Lin + * Joy Bhalla + * Laith Bahodi * Lalourche + * Max Stoumen * Naveen M K * Oliver * Partha Das + * Raj Dandekar + * Rohan Sharma + * Ryan McCauley * Václav Hlaváč + * asjadaugust + * ccn * icedcoffeeee * sparshg * vinnniii15 + * vladislav doster + * xia0long + The patches included in this release have been reviewed by the following contributors. * Aathish Sivasubrahmanian * Benjamin Hackl * Darylgolden * Devin Neal * Eric Biedert * GameDungeon * Harivinay * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * Jephian Lin * Joy Bhalla * KingWampy * Laith Bahodi * Naveen M K * Oliver * Raghav Goel * Raj Dandekar * Ryan McCauley * ccn * icedcoffeeee * ralphieraccoon * sparshg Pull requests merged ==================== A total of 59 pull requests were merged for this release. Breaking changes ---------------- * :pr:`1843`: Dropped redundant OpenGL files and add metaclass support for :class:`~.Surface` - ``OpenGL`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed. - ``ParametricSurface`` has been renamed to :class:`~.Surface` Deprecated classes and functions -------------------------------- * :pr:`1941`: Added examples, tests and improved documentation for :mod:`~.coordinate_systems` * :pr:`1694`: Added ``font_size`` parameter for :class:`~.Tex` and :class:`~.Text`, replaced ``scale`` parameters with ``font_size`` * :pr:`1860`: Removed :class:`~.GraphScene`, :class:`~.NumberLineOld` and parameters for :class:`~.ChangingDecimal` New features ------------ * :pr:`1929`: Implementing a ``zoom`` parameter for :meth:`.ThreeDScene.move_camera` Zooming into a :class:`~.ThreeDScene` can now be done by calling, for example, ``self.move_camera(zoom=2)`` in the ``construct`` method. * :pr:`1980`: Added a ``dissipating_time`` keyword argument to :class:`~.TracedPath` to allow animating a dissipating path * :pr:`1899`: Allow switching the renderer to OpenGL at runtime Previously, the metaclass approach only changed the inheritance chain to switch between OpenGL and cairo mobjects when the class objects are initialized, i.e., at import time. This PR also triggers the changes to the inheritance chain when the value of ``config.renderer`` is changed. * :pr:`1828`: Added configuration option ``zero_pad`` for zero padding PNG file names Enhancements ------------ * :pr:`1882`: Added OpenGL support for :class:`~.PMobject` and its subclasses * :pr:`1881`: Added methods :meth:`.Angle.get_lines` and :meth:`.Angle.get_value` to :class:`~.Angle` * :pr:`1952`: Added the option to save last frame for OpenGL * :pr:`1922`: Fixed IPython interface to exit cleanly when OpenGL renderer raises an error * :pr:`1923`: Fixed CLI help text for ``manim init`` subcommand so that it is not truncated * :pr:`1868`: Added OpenGL support to IPython magic The OpenGL renderer can now be used in jupyter notebooks when using the ``%%manim`` magic command. * :pr:`1841`: Reduced default resolution of :class:`~.Dot3D` * :pr:`1866`: Allow passing keyword argument ``corner_radius`` to :class:`~.SurroundingRectangle` * :pr:`1847`: Allow :class:`~.Cross` to be created without requiring a mobject Fixed bugs ---------- * :pr:`1985`: Use ``height`` to determine ``font_size`` instead of the ``_font_size`` attribute * :pr:`1758`: Fixed scene selection being ignored when using the OpenGL renderer * :pr:`1871`: Fixed broken :meth:`.VectorScene.vector_to_coords` * :pr:`1973`: Fixed indexing of :meth:`.Table.get_entries` to respect row length * :pr:`1950`: Fixed passing custom arrow shapes to :class:`~.CurvedArrow` * :pr:`1967`: Fixed :attr:`.Axes.coordinate_labels` referring to the entire axis, not just its labels * :pr:`1951`: Fixed :meth:`.Axes.get_line_graph` returning a graph rendered below the axes * :pr:`1943`: Added ``buff`` keyword argument to :class:`~.BraceLabel` * :pr:`1938`: Fixed :class:`~.Rotate` for angles that are multiples of :math:`2\pi` * :pr:`1924`: Made arrow tips rotate ``IN`` and ``OUT`` properly * :pr:`1931`: Fixed ``row_heights`` in :meth:`.Mobject.arrange_in_grid` * :pr:`1893`: Fixed CLI error when rendering a file containing a single scene without specifying the scene name * :pr:`1744`: Fixed bug in :class:`~.NumberPlane` with strictly positive or strictly negative values for ``x_range`` and ``y_range`` * :pr:`1887`: Fixed ``custom_config`` not working in ``frames_comparison`` * :pr:`1879`: Fixed how the installed version is determined by Poetry Documentation-related changes ----------------------------- * :pr:`1979`: Corrected Japanese phrases in documentation * :pr:`1976`: Fixed labelling of languages in documentation example * :pr:`1949`: Rewrite installation instructions from scratch * :pr:`1963`: Added sitemap to ``robots.txt`` * :pr:`1939`: Fixed formatting of parameter description of :class:`~.NumberPlane` * :pr:`1918`: Fixed a typo in the text tutorial * :pr:`1915`: Improved the wording of the installation instructions for Google Colab * :pr:`1906`: Improved language and overall consistency in ``README`` * :pr:`1880`: Updated tutorials to use ``.animate`` instead of :class:`~.ApplyMethod` * :pr:`1877`: Remove duplicated imports in some documentation examples * :pr:`1869`: Fixed duplicated Parameters section in :meth:`.Mobject.arrange_in_grid` Changes concerning the testing system ------------------------------------- * :pr:`1894`: Fixed an OpenGL test Changes to our development infrastructure ----------------------------------------- * :pr:`1987`: Added support for using OpenGL in subprocess in Windows pipeline * :pr:`1964`: Added ``CITATION.cff`` and a method to automatically update this citation with new releases * :pr:`1856`: Modified Dockerfile to support multi-platform builds via ``docker buildx`` * :pr:`1955`: Partially support OpenGL rendering with Docker * :pr:`1896`: Made RTD apt install FFMPEG instead of installing a Python binding * :pr:`1864`: Shortened and simplified PR template * :pr:`1853`: Updated Sphinx to 4.1.2 Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1960`: Ignore fewer flake8 errors * :pr:`1947`: Set flake8 not to ignore undefined names in Python code * :pr:`1948`: flake8: Set max-line-length instead of ignoring long lines * :pr:`1956`: Upgrade to modern Python syntax - This pull request was created `with the command `__ ``pyupgrade --py36-plus **/*.py`` - Python f-strings simplify the code and `should speed up execution `__. * :pr:`1898`: Replaced ``self.data["attr"]`` and ``self.uniforms["attr"]`` with ``self.attr`` In particular, ``OpenGLVMobject.points`` can now be accessed directly. * :pr:`1934`: Improved code quality by implementing suggestions from LGTM * :pr:`1861`: Updated ``dearpygui`` version to 0.8.x New releases ------------ * :pr:`1989`: Prepare new release v0.10.0 ================================================ FILE: docs/source/changelog/0.11.0-changelog.rst ================================================ ******* v0.11.0 ******* :Date: October 02, 2021 Contributors ============ A total of 31 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Aathish Sivasubrahmanian * Benjamin Hackl * Charlie + * Christopher Besch + * Darylgolden * Evan Boehs + * GameDungeon * Hugues Devimeux * Jerónimo Squartini * Laith Bahodi * Meredith Espinosa + * Mysaa * Naveen M K * Nicolai Weitkemper + * Oliver * Ryan McCauley * Tim + * icedcoffeeee * imadjamil + * leleogere + * Максим Заякин + The patches included in this release have been reviewed by the following contributors. * Aathish Sivasubrahmanian * Benjamin Hackl * Charlie * Darylgolden * Evan Boehs * GameDungeon * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * Laith Bahodi * Mark Miller * Mysaa * Naveen M K * Nicolai Weitkemper * Oliver * Raghav Goel * Ryan McCauley * Skaft * friedkeenan * icedcoffeeee * leleogere Pull requests merged ==================== A total of 55 pull requests were merged for this release. Breaking changes ---------------- * :pr:`1990`: Changed and improved the implementation of :meth:`.CoordinateSystem.get_area` to work without Riemann rectangles This changes how :meth:`.CoordinateSystem.get_area` is implemented. To mimic the old behavior (tiny Riemann rectangles), use :meth:`.CoordinateSystem.get_riemann_rectangles` with a small value for ``dx``. * :pr:`2095`: Changed angles for polar coordinates to use math convention This PR switches the parameter names ``phi`` and ``theta`` in :func:`cartesian_to_spherical` and :func:`spherical_to_cartesian` to align with the `usual definition in mathematics `__. Highlights ---------- * :pr:`2094`: Implemented :class:`~.ImplicitFunction` and :meth:`.CoordinateSystem.get_implicit_curve` for plotting implicit curves An :class:`~.ImplicitFunction` that plots the points :math:`(x, y)` which satisfy some equation :math:`f(x,y) = 0`. * :pr:`2075`: Implemented :meth:`.Mobject.set_default`, a mechanism for changing default values of keyword arguments * :pr:`1998`: Added support for Boolean Operations on VMobjects This PR introduces boolean operations for :class:`~.VMobject`; see details and examples at :class:`~.Union`, :class:`~.Difference`, :class:`~.Intersection` and :class:`~.Exclusion`. Deprecated classes and functions -------------------------------- * :pr:`2123`: Renamed ``distance`` parameter of :class:`.ThreeDScene` and :class:`.ThreeDCamera` to ``focal_distance`` * :pr:`2102`: Deprecated :class:`~.SampleSpaceScene` and :class:`~.ReconfigurableScene` * :pr:`2061`: Removed deprecated ``u_min``, ``u_max``, ``v_min``, ``v_max`` in :class:`~.Surface` * :pr:`2024`: Deprecated redundant methods :meth:`.Mobject.rotate_in_place`, :meth:`.Mobject.scale_in_place`, :meth:`.Mobject.scale_about_point` * :pr:`1991`: Deprecated :meth:`.VMobject.get_points` New features ------------ * :pr:`2118`: Added 3D support for :class:`~.ArrowVectorField` and :class:`~.StreamLines` * :pr:`1469`: Added :meth:`.VMobject.proportion_from_point` to measure the proportion of points along a Bezier curve Enhancements ------------ * :pr:`2111`: Improved setting of OpenGL colors * :pr:`2113`: Added OpenGL compatibility to :meth:`.ThreeDScene.begin_ambient_camera_rotation` and :meth:`.ThreeDScene.move_camera` * :pr:`2016`: Added OpenGL support for :mod:`~.mobject.boolean_ops` * :pr:`2084`: Added :meth:`~Table.get_highlighted_cell` and fixed :meth:`~Table.add_highlighted_cell` * :pr:`2013`: Removed unnecessary check in :class:`~.TransformMatchingAbstractBase` * :pr:`1971`: Added OpenGL support for :class:`~.StreamLines` * :pr:`2041`: Added config option to enable OpenGL wireframe for debugging Fixed bugs ---------- * :pr:`2070`: Fixed :meth:`~OpenGLRenderer.get_frame` when window is created * :pr:`2071`: Fixed :class:`~AnimationGroup` OpenGL compatibility * :pr:`2108`: Fixed swapped axis step values in :class:`~.NumberPlane` * :pr:`2072`: Added OpenGL compatibility for :class:`~.Cube`. * :pr:`2060`: Fixed OpenGL compatibility issue for meth:`~Line.set_opacity` * :pr:`2037`: Fixed return value of :meth:`~.OpenGLMobject.apply_complex_function` * :pr:`2039`: Added OpenGL compatibility for :meth:`~Cylinder.add_bases`. * :pr:`2066`: Fixed error raised by logging when cache is full * :pr:`2026`: Fixed OpenGL shift animation for :class:`~.Text` * :pr:`2028`: Fixed OpenGL overriding SVG fill color * :pr:`2043`: Fixed bug where :meth:`.NumberLine.add_labels` cannot accept non-mobject labels * :pr:`2011`: Fixed ``-a`` flag for OpenGL rendering * :pr:`1994`: Fix :meth:`~.input_to_graph_point` when passing a line graph (from :meth:`.Axes.get_line_graph`) * :pr:`2017`: Avoided using deprecated ``get_points`` method and fixed :class:`~.OpenGLPMPoint` color Documentation-related changes ----------------------------- * :pr:`2131`: Copyedited the configuration tutorial in the documentation * :pr:`2120`: Changed ``manim_directive`` to use a clean configuration via ``tempconfig`` * :pr:`2122`: Fixed broken links in inheritance graphs by moving them to ``reference.rst`` * :pr:`2115`: Improved docstring of :meth:`.PMobject.add_points` * :pr:`2116`: Made type hint for ``line_spacing`` argument of :class:`~.Paragraph` more accurate * :pr:`2117`: Changed the way the background color was set in a documentation example to avoid leaking the setting to other examples * :pr:`2101`: Added note that translation process is not ready * :pr:`2055`: Fixed parameter types of :meth:`.Graph.add_edges` and :meth:`.Graph.add_vertices` * :pr:`862`: Prepared documentation for translation (still work in progress) * :pr:`2035`: Fixed broken link in README * :pr:`2020`: Corrected paths to user-wide configuration files for MacOS and Linux Changes concerning the testing system ------------------------------------- * :pr:`2008`: Reuse CLI flag tests for OpenGL * :pr:`2080`: Reused :class:`~.Mobject` tests for :class:`~.OpenGLMobject` Changes to our development infrastructure ----------------------------------------- * :pr:`2004`: Cancel previous workflows in the same branch in Github Actions Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2050`: Make colour aliases IDE-friendly * :pr:`2126`: Fixed whitespace in info message issued by :meth:`.SceneFileWriter.clean_cache` * :pr:`2124`: Upgraded several dependencies (in particular: ``skia-pathops``) * :pr:`2001`: Fixed several warnings issued by LGTM * :pr:`2064`: Removed duplicate insert shader directory * :pr:`2027`: Improved wording in info message issued by :meth:`.SceneFileWriter.clean_cache` * :pr:`1968`: Sharpened Flake8 configuration and fixed resulting warnings New releases ------------ * :pr:`2114`: Prepared new release, ``v0.11.0`` ================================================ FILE: docs/source/changelog/0.12.0-changelog.rst ================================================ ******* v0.12.0 ******* :Date: November 02, 2021 Contributors ============ A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Anima. + * Arcstur + * Benjamin Hackl * Christopher Besch * Darylgolden * David Yang + * Dhananjay Goratela + * Ethan Rooke + * Eugene Chung + * GameDungeon * Gustav-Rixon + * Jan-Hendrik Müller * Josiah Winslow + * Laith Bahodi * Martmists + * Michael Hill + * Naveen M K * Nick + * NotWearingPants + * Peeter Joot + * Ryan McCauley * Viicos + * heitor + * icedcoffeeee * kieran-pringle + * Виктор Виктор + The patches included in this release have been reviewed by the following contributors. * Alex Lembcke * Anima. * Benjamin Hackl * Christopher Besch * Darylgolden * David Yang * Dhananjay Goratela * Ethan Rooke * Eugene Chung * Gustav-Rixon * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * Laith Bahodi * Mysaa * Naveen M K * Nick * Oliver * Ryan McCauley * Viicos * icedcoffeeee * kieran-pringle Pull requests merged ==================== A total of 52 pull requests were merged for this release. Highlights ---------- * :pr:`1812`: Implemented logarithmic scaling for :class:`~.NumberLine` / :class:`~.Axes` This implements scaling bases that can be passed to the ``scaling`` keyword argument of :class:`.NumberLine`. See :class:`.LogBase` (for a logarithmic scale) and :class:`.LinearBase` (for the default scale) for more details and examples. * :pr:`2152`: Introduced API for scene sections via :meth:`.Scene.next_section` Sections divide a scene into multiple parts, resulting in multiple output videos (when using the ``--save_sections`` flag). The cuts between two sections are defined by the user in the :meth:`~.Scene.construct` method. Each section has an optional name and type, which can be used by a plugin (`see an example `__). You can skip rendering specific sections with the ``skip_animations`` keyword argument. Deprecated classes and functions -------------------------------- * :pr:`1926`: OpenGL: changed ``submobjects`` to be a property * :pr:`2245`: Removed deprecated method ``get_center_point`` and parameters ``azimuth_label_scale``, ``number_scale_value``, ``label_scale``, ``scale_factor``, ``size``, ``x_min``, ``x_max``, ``delta_x``, ``y_min``, ``y_max``, ``delta_y`` * :pr:`2187`: Renamed ``get_graph`` and its variants to :meth:`~.CoordinateSystem.plot` * :pr:`2065`: Deprecated :class:`~.FullScreenFadeRectangle` and :class:`~.PictureInPictureFrame` New features ------------ * :pr:`2025`: Implemented :meth:`.CoordinateSystem.input_to_graph_coords` and fixed :meth:`.CoordinateSystem.angle_of_tangent` * :pr:`2151`: Added option to set the input file from a config file * :pr:`2128`: Added keyword arguments ``match_center``, ``match_width`` etc. to :meth:`.Mobject.become` * :pr:`2162`: Implemented :meth:`.MovingCamera.auto_zoom` for automatically zooming onto specified mobjects * :pr:`2236`: Added ``skip_animations`` argument to :meth:`.Scene.next_section` * :pr:`2196`: Implemented :meth:`.Line3D.parallel_to` and :meth:`.Line3D.perpendicular_to` Enhancements ------------ * :pr:`2138`: Fixed example for :meth:`~.Vector.coordinate_label` and added more customization for :class:`~.Matrix` - Additional keyword arguments for :meth:`~.Vector.coordinate_label` are passed to the constructed matrix. - :class:`~.Matrix` now accepts a ``bracket_config`` keyword argument. * :pr:`2139`: Changed the color of :class:`~.NumberLine` from ``LIGHT_GREY`` to ``WHITE`` * :pr:`2157`: Added :meth:`.CoordinateSystem.plot_polar_graph` * :pr:`2243`: Fixed wasteful recursion in :meth:`.Mobject.get_merged_array` * :pr:`2205`: Improved last frame output handling for the OpenGL renderer * :pr:`2172`: Added ``should_render`` attribute to disable rendering mobjects * :pr:`2182`: Changed the default width of videos in Jupyter notebooks to 60% Fixed bugs ---------- * :pr:`2244`: Fixed :meth:`.CoordinateSystem.get_area` when using few plot points and a boundary graph * :pr:`2232`: Fixed :class:`.Graph` stopping to update after animating additions/deletions of vertices or edges * :pr:`2142`: Fixed issue with duplicates in OpenGL family and added tests * :pr:`2168`: Fixed order of return values of :func:`.space_ops.cartesian_to_spherical` * :pr:`2160`: Made projection shaders compatible with :class:`.StreamLines` * :pr:`2140`: Fixed passing color lists to :meth:`.Mobject.set_color` for the OpenGL renderer * :pr:`2211`: Fixed animations not respecting the specified rate function * :pr:`2161`: Fixed ``IndexOutOfBoundsError`` in TeX logging * :pr:`2148`: Fixed :class:`~.Arrow` tip disorientation with :meth:`.Line.put_start_and_end_on` * :pr:`2192`: Fixed :func:`.svg_path.string_to_numbers` sometimes returning strings * :pr:`2185`: Fixed type mismatch for height and width parameters of :class:`~.Text` Documentation-related changes ----------------------------- * :pr:`2228`: Added a new boolean operation example to the gallery * :pr:`2239`: Removed erroneous raw string from text tutorial * :pr:`2184`: Moved comments in :class:`~.VMobject` to documentation * :pr:`2217`: Removed superfluous dots in documentation of :class:`.Section` * :pr:`2215`: Fixed typo in docstring of :meth:`.ThreeDAxes.get_z_axis_label` * :pr:`2212`: Fixed Documentation for Sections * :pr:`2201`: Fixed a typo in the documentation * :pr:`2165`: Added Crowdin configuration and changed source files to ``.pot`` format * :pr:`2130`: Transferred troubleshooting installation related snippets from Discord to the documentation * :pr:`2176`: Modified :meth:`.Mobject.set_default` example to prevent leaking across the docs Changes concerning the testing system ------------------------------------- * :pr:`2197`: Added tests for resolution flag * :pr:`2146`: Increased test coverage for OpenGL renderer Changes to our development infrastructure ----------------------------------------- * :pr:`2191`: Removed ``add-trailing-comma`` pre-commit hook Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2136`: Added type hints to all colors * :pr:`2220`: Cleanup: let ``Scene.renderer.time`` return something that makes sense * :pr:`2222`: Updated Classifiers in ``pyproject.toml``: removed Python 3.6, added Python 3.9 * :pr:`2213`: Removed redundant ``partial_movie_files`` parameter in :meth:`.SceneFileWriter.combine_to_movie` * :pr:`2200`: Addressed some maintenance TODOs - Changed an `Exception` to `ValueError` - Fixed :meth:`.MappingCamera.points_to_pixel_coords` by adding the ``mobject`` argument of the parent - Rounded up width in :class:`.SplitScreenCamera` - Added docstring to :meth:`.Camera.capture_mobject` * :pr:`2194`: Added type hints to :mod:`.utils.images` * :pr:`2171`: Added type hints to :mod:`.utils.ipython_magic` * :pr:`2164`: Improved readability of regular expression New releases ------------ * :pr:`2247`: Prepared new release ``v0.12.0`` ================================================ FILE: docs/source/changelog/0.13.0-changelog.rst ================================================ ******* v0.13.0 ******* :Date: December 04, 2021 Contributors ============ A total of 27 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Benjamin Hackl * Christopher Besch * Darylgolden * Filip + * John Ingles + * Laith Bahodi * Lucas Ricci + * Marcin Serwin + * Mysaa * Naveen M K * Ricky + * Viicos * ask09ok + * citrusmunch + * icedcoffeeee * mostlyaman + * vmiezys + * zhujisheng + The patches included in this release have been reviewed by the following contributors. * Alex Lembcke * Benjamin Hackl * Christopher Besch * Darylgolden * Filip * Hugues Devimeux * Jan-Hendrik Müller * Laith Bahodi * Lucas Ricci * Naveen M K * Oliver * Ryan McCauley * Viicos * ask09ok * icedcoffeeee * mostlyaman Pull requests merged ==================== A total of 39 pull requests were merged for this release. Highlights ---------- * :pr:`2313`: Finalized translation process and documentation Deprecated classes and functions -------------------------------- * :pr:`2331`: Removed deprecations up to ``v0.12.0`` - Removed ``distance`` parameters from :class:`~.ThreeDCamera` (replacement: ``focal_distance``) - Removed ``min_distance_to_new_point`` parameter from :class:`~.TracedPath` - Removed ``positive_space_ratio`` and ``dash_spacing`` parameters from :class:`~.DashedVMobject` - Removed ``_in_place`` methods from :mod:`.mobject` - Removed ``ReconfigurableScene`` - Removed ``SampleSpaceScene`` * :pr:`2312`: Replaced all occurrences of ``set_submobjects`` New features ------------ * :pr:`2314`: Added basic support for adding subcaptions via :meth:`.Scene.add_subcaption` - New method :meth:`.Scene.add_subcaption` - New keyword arguments ``subcaption``, ``subcaption_duration``, ``subcaption_offset`` for :meth:`.Scene.play` * :pr:`2267`: Implemented :meth:`.CoordinateSystem.plot_antiderivative_graph` Enhancements ------------ * :pr:`2347`: Moved ``manim_directive.py`` to ``manim.utils.docbuild`` * :pr:`2340`: Added documentation for :mod:`.animation.growing` and improved :class:`.SpinInFromNothing` * :pr:`2343`: Replaced current tree layout algorithm with SageMath's for improved layout of large trees * :pr:`2351`: Added missing ``**kwargs`` parameter to :meth:`.Table.add_highlighted_cell` * :pr:`2344`: Resized SVG logos, fit content to canvas Fixed bugs ---------- * :pr:`2359`: Resolved ``ValueError`` when calling ``manim cfg write`` * :pr:`2276`: Fixed bug with alignment of z-axis in :class:`~.ThreeDAxes` * :pr:`2325`: Several improvements to handling of ``quality`` argument * :pr:`2335`: Fixed bug with zooming camera and :class:`~.PointCloud` * :pr:`2328`: Fixed bug causing incorrect RGBA values to be passed to cairo * :pr:`2292`: Fixed positioning of :class:`~.Flash` * :pr:`2262`: Fixed wrong cell coordinates with :meth:`.Table.get_cell` after scaling * :pr:`2280`: Fixed :class:`~.DecimalNumber` color when number of displayed digits changes Documentation-related changes ----------------------------- * :pr:`2354`: Port over docs and typings from ``mobject.py`` and ``vectorized_mobject.py`` to their OpenGL counterparts * :pr:`2350`: Added mention of Manim sideview extension for VS Code * :pr:`2342`: Removed :meth:`~.CoordinateSystem.get_graph` usage from :class:`~.Axes` example * :pr:`2216`: Edited and added new sections to the quickstart tutorial * :pr:`2279`: Added documentation for discontinuous functions * :pr:`2319`: Swapped ``dotL`` and ``dotR`` in :meth:`.Mobject.interpolate` example * :pr:`2230`: Copyedited building blocks tutorial * :pr:`2310`: Clarified that Manim does not support Python 3.10 yet in the documentation * :pr:`2294`: Made documentation front page more concise and rearranged order of tutorials * :pr:`2287`: Replace link to old interactive notebook Changes concerning the testing system ------------------------------------- * :pr:`2346`: Made ``frames_comparsion`` decorator for frame testing a proper module of the library * :pr:`2318`: Added tests for ``remover`` keyword argument of :class:`~.AnimationGroup` * :pr:`2301`: Added a test for :meth:`.ThreeDScene.add_fixed_in_frame_mobjects` * :pr:`2274`: Optimized some tests to reduce duration * :pr:`2272`: Added test for :class:`~.Broadcast` Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2327`: Corrected type hint for ``labels`` keyword argument of :class:`~.Graph` * :pr:`2329`: Remove unintended line break in README * :pr:`2305`: Corrected type hint ``discontinuities`` argument for :class:`~.ParametricFunction` * :pr:`2300`: Add contact email for PyPi New releases ------------ * :pr:`2353`: Prepare new release: ``v0.13.0`` Unclassified changes -------------------- * :pr:`2348`: Updated translation source files ================================================ FILE: docs/source/changelog/0.13.1-changelog.rst ================================================ ******* v0.13.1 ******* :Date: December 05, 2021 Contributors ============ A total of 2 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Benjamin Hackl The patches included in this release have been reviewed by the following contributors. * Laith Bahodi Pull requests merged ==================== A total of 2 pull requests were merged for this release. Fixed bugs ---------- * :pr:`2363`: Fixed broken IPython magic command New releases ------------ * :pr:`2364`: Prepared bugfix release ``v0.13.1`` ================================================ FILE: docs/source/changelog/0.14.0-changelog.rst ================================================ ******* v0.14.0 ******* :Date: January 07, 2022 Contributors ============ A total of 29 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Benjamin Hackl * BorisTheBrave + * Darylgolden * GameDungeon * Gergely Bencsik + * Jan-Hendrik Müller * Jihoon + * Kian Kasad + * Kiran-Raj-Dev + * Laith Bahodi * Leo Xu + * Marcin Serwin * Matt Gleich + * Naveen M K * Steven nguyen + * Vectozavr + * Viicos * citrusmunch * netwizard22 + The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * BorisTheBrave * Christopher Besch * Darylgolden * GameDungeon * Gergely Bencsik * Hugues Devimeux * Jan-Hendrik Müller * Kiran-Raj-Dev * Laith Bahodi * Leo Xu * Lucas Ricci * Marcin Serwin * Naveen M K * Raghav Goel * Ryan McCauley * Viicos * icedcoffeeee Pull requests merged ==================== A total of 29 pull requests were merged for this release. Deprecated classes and functions -------------------------------- * :pr:`2390`: Removed deprecations up to `v0.13.0` - Removed ``get_graph``, ``get_implicit_curve``, ``get_derivative_graph``, ``get_line_graph`` and ``get_parametric_curve`` in favour of their ``plot`` variants - Removed ``FullScreenFadeRectangle`` and ``PictureInPictureFrame`` - Removed ``path_arc`` parameter from :class:`~.SpinInFromNothing` - Removed ``set_submobjects`` method from ``opengl_mobject.py`` New features ------------ * :pr:`2341`: Update :class:`~.Text` to use new ``ManimPango`` color setting * :class:`~.Text` class now uses color setting introduced in ``ManimPango 0.4.0`` for color and gradient. * :pr:`2397`: Added ``label_constructor`` parameter for :class:`~.NumberLine` Allows changing the class that will be used to construct :class:`~.Axes` and :class:`~.NumberLine` labels by default. Makes it possible to easily use :class:`~.Text` for labels if needed. Enhancements ------------ * :pr:`2383`: Made :meth:`.Surface.set_fill_by_value` support gradients along different axes * :pr:`2388`: Added ``about_point`` keyword argument to :class:`~.ApplyMatrix` * :pr:`2395`: Add documentation for paths functions * :pr:`2372`: Improved :class:`~.DashedVMobject` :class:`~.DashedVMobject` used to create stretched and uneven dashes on most plotted curves. Now the dash lengths are equalized. An option is reserved to use the old method. New keyword argument: ``dash_offset``. This parameter shifts the starting point. Fixed bugs ---------- * :pr:`2409`: Fixed performance degradation by trimming empty curves from paths when calling :meth:`.VMobject.align_points` * :pr:`2392`: Fixed ``ZeroDivisionError`` in :mod:`~.mobject.three_dimensions` * :pr:`2362`: Fixed phi updater in :meth:`.ThreeDScene.begin_3dillusion_camera_rotation` Documentation-related changes ----------------------------- * :pr:`2415`: Removed instructions on using and installing Docker in README * :pr:`2414`: Made improvements to the :doc:`/guides/configuration` tutorial * :pr:`2423`: Changed recommendation to ``mactex-no-gui`` from ``mactex`` for macOS install * :pr:`2407`: Clarified docstrings of :meth:`.Mobject.animate`, :meth:`.Mobject.set` and :class:`~.Variable` * :pr:`2352`: Added Crowdin badge * :pr:`2371`: Added ``dvips`` to list of required LaTeX packages on Linux * :pr:`2403`: Improved docstring of :class:`~.ApplyMethod` and removed propagated ``__init__`` docstring * :pr:`2391`: Fixed typo in parameter name in documentation of :class:`~.NumberLine` * :pr:`2368`: Added note in Internationalization Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2408`: Removed various return annotations that were stifling type inference * :pr:`2424`: Removed ``strings.py`` * :pr:`1972`: Added support for MyPy * :pr:`2410`: Fixed Flake8 * :pr:`2401`: Fixed type annotations in :mod:`.mobject.three_dimensions` * :pr:`2405`: Removed some unused OpenGL files * :pr:`2399`: Fixed type annotations in :mod:`~.mobject.table` * :pr:`2385`: Made comments in quickstart tutorial more precise * :pr:`2377`: Fixed type hint for an argument of :class:`~.MoveAlongPath` New releases ------------ * :pr:`2411`: Prepare new release, ``v0.14.0`` ================================================ FILE: docs/source/changelog/0.15.0-changelog.rst ================================================ ******* v0.15.0 ******* :Date: February 26, 2022 Contributors ============ A total of 34 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * AnonymoZ + * Benjamin Hackl * Darylgolden * Eshaan Naga Venkata + * Faruk D. + * GameDungeon * Kevin Cen + * Laith Bahodi * Leo Xu * Lucas Ricci * Marcin Serwin * Michael McNeil Forbes + * Mysaa * Naveen M K * Pierre Couy + * Simon Ellmann + * Tommy Chu + * Viicos * ad_chaos * betafcc + * friedkeenan * icedcoffeeee * vmoros + * 鹤翔万里 The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Christopher Besch * Darylgolden * Eshaan Naga Venkata * GameDungeon * Jan-Hendrik Müller * Laith Bahodi * Marcin Kurczewski * Marcin Serwin * Naveen M K * Raghav Goel * RomainJMend * Ryan McCauley * Tommy Chu * ad_chaos * betafcc * icedcoffeeee Pull requests merged ==================== A total of 71 pull requests were merged for this release. Breaking changes ---------------- * :pr:`2476`: Improved structure of the :mod:`.mobject` module Arrow tips now have to be imported from ``manim.mobject.geometry.tips`` instead of ``manim.mobject.geometry``. * :pr:`2387`: Refactored :class:`~.BarChart` and made it inherit from :class:`~.Axes` - :class:`~.BarChart` now inherits from :class:`~.Axes`, allowing it to use :class:`~.Axes`' methods. Also improves :class:`~.BarChart`'s configuration and ease of use. - Added :meth:`~.BarChart.get_bar_labels` to annotate the value of each bar of a :class:`~.BarChart`. Deprecated classes and functions -------------------------------- * :pr:`2568`: Removed Deprecated Methods Removed methods and classes that were deprecated since v0.10.0 and v0.11.0 * :pr:`2457`: Deprecated :class:`.ShowCreationThenFadeOut` New features ------------ * :pr:`2442`: Added ``media_embed`` config option to control whether media in Jupyter notebooks is embedded * :pr:`2504`: Added finer control over :meth:`.Scene.wait` being static (i.e., no updaters) or not - Added keyword argument ``frozen_frame`` to :class:`.Wait` and :meth:`.Scene.wait` - New convenience method: :meth:`.Scene.pause` (alias for ``Scene.wait(frozen_frame=True)``) - Changed default behavior for OpenGL updaters: updater functions are now not called by default when they are added - Changed default behavior of :meth:`.Scene.should_mobjects_update`: made it respect the set value of ``Wait.frozen_frame``, changed automatic determination of frozen frame state to also consider Scene updaters Enhancements ------------ * :pr:`2478`: Alternative scaling for tree graph layout * :pr:`2565`: Allowed passing vertex configuration keyword arguments to :meth:`.Graph.add_edges` * :pr:`2467`: :class:`~.MathTex`, :class:`~.Tex`, :class:`~.Text` and :class:`~.MarkupText` inherit color from their parent mobjects * :pr:`2537`: Added support for PySide coordinate system * :pr:`2158`: Added OpenGL compatibility to :meth:`.ThreeDScene.add_fixed_orientation_mobjects` and :meth:`.ThreeDScene.add_fixed_in_frame_mobjects` * :pr:`2535`: Implemented performance enhancement for :meth:`.VMobject.insert_n_curves_to_point_list` * :pr:`2516`: Cached view matrix for :class:`~.OpenGLCamera` * :pr:`2508`: Improve performance for :meth:`.Mobject.become` * :pr:`2332`: Changed ``color``, ``stroke_color`` and ``fill_color`` attributes to properties * :pr:`2396`: Fixed animations introducing or removing objects * :class:`.ShowPassingFlash` now removes objects when the animation is finished * Added ``introducer`` keyword argument to :class:`.Animation` analogous to ``remover`` * Updated :class:`.Graph` vertex addition handling Fixed bugs ---------- * :pr:`2574`: Improved Error in :mod:`.utils.tex_file_writing` * :pr:`2580`: Fixed :func:`.find_intersection` in :mod:`.space_ops` * :pr:`2576`: Fixed a bug with animation of removal of edges from a :class:`.Graph` * :pr:`2556`: Fixed showing highlighted cells when creating :class:`.Table` * :pr:`2559`: Fix setting line numbers in :class:`.Text` when using ManimPango settings * :pr:`2557`: Fixed logger bug in :meth:`.Camera.make_background_from_func` * :pr:`2548`: Fixed :class:`.Axes` plotting bug with logarithmic x-axis * :pr:`1547`: Fixed certain unicode characters in users' paths causing issues on Windows * :pr:`2526`: Fixed segfault when using ``--enable_gui`` * :pr:`2538`: Fixed flickering OpenGL preview when using ``frozen_frame`` * :pr:`2528`: Fixed custom naming of gifs and added some tests * :pr:`2487`: Fixed :meth:`.ThreeDCamera.remove_fixed_orientation_mobjects` * :pr:`2530`: Use single source of truth for default text values * :pr:`2494`: Fixed an issue related to previewing gifs * :pr:`2490`: Fixed order of transformation application in :class:`~.SVGMobject` * :pr:`2357`: Fixed ``screeninfo.get_monitors`` for MacOS * :pr:`2444`: Fixed :meth:`.VectorScene.add_axes` Documentation-related changes ----------------------------- * :pr:`2560`: Refactored more docstrings in :mod:`.geometry` * :pr:`2571`: Refactored docstrings in :mod:`.graphing` * :pr:`2569`: Refactored docstrings in :mod:`.geometry` * :pr:`2549`: Added a page for internals which links to our GitHub wiki * :pr:`2458`: Improved documentation for :class:`.Rotate` * :pr:`2459`: Added examples to some transform animations * :pr:`2517`: Added guide on profiling and improving performance * :pr:`2518`: Added imports to examples for ``deprecation`` decorator * :pr:`2499`: Improved help text for ``--write_to_movie`` * :pr:`2465`: Added documentation for :func:`.index_labels` * :pr:`2495`: Updated minimal LaTeX installation instructions * :pr:`2500`: Added note about contributions during refactor period * :pr:`2431`: Changed example in :meth:`.Surface.set_fill_by_value` * :pr:`2485`: Fixed some typos in documentation * :pr:`2493`: Fixed typo in documentation for parameters of :class:`.Square` * :pr:`2482`: Updated Python version requirement in installation guide * :pr:`2438`: Removed unnecessary rotation from example * :pr:`2468`: Hid more private methods from the docs * :pr:`2466`: Fixed a typo in the documentation for plugins * :pr:`2448`: Improvements to the ``.pot`` files cleaning system * :pr:`2436`: Fixed typo and improved example in building blocks tutorial Changes to our development infrastructure ----------------------------------------- * :pr:`2554`: Removed ``Remove-Item`` calls for MSYS2 Python * :pr:`2531`: Added a GitHub Action for automatic validation of citation metadata * :pr:`2536`: Upgraded version of setup-ffmpeg CI action * :pr:`2484`: Updated tinytex download URL Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2573`: Moved :mod:`.value_tracker` back inside :mod:`.mobject` * :pr:`2566`: Removed unused livestream-related imports and functions from :mod:`.scene_file_writer` * :pr:`2524`: Reworked :mod:`.space_ops` * :pr:`2519`: Removed outdated comment * :pr:`2503`: Removed unused imports * :pr:`2475`: Removed setuptools dependency * :pr:`2472`: Removed unnecessary comment in :mod:`.simple_functions` * :pr:`2429`: Upgraded to future-style type annotations * :pr:`2464`: Bump pillow from 8.4.0 to 9.0.0 * :pr:`2376`: Updated dependencies for Python 3.10 * :pr:`2437`: Cleaned up :mod:`.simple_functions` - Removed ``fdiv`` as in all cases where it was used, it was just doing the same thing as numpy array division. - Replaced old implementation of the choose function with scipy's implementation - Use ``lru_cache`` (least recently used cache) for caching the choose function. Since it's only used for beziers, only 2 choose k and 3 choose k will be used, hence a size of 10 should be enough. - Removed ``clip_in_place`` in favor of ``np.clip`` - Removed one use of ``clip_in_place`` that wasn't actually doing anything * :pr:`2439`: Removed twitter template from scripts New releases ------------ * :pr:`2547`: Prepared new release, ``v0.15.0`` ================================================ FILE: docs/source/changelog/0.15.1-changelog.rst ================================================ ******* v0.15.1 ******* :Date: March 08, 2022 Contributors ============ A total of 9 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Benjamin Hackl * Nicolai Weitkemper * Yuchen + * ad_chaos The patches included in this release have been reviewed by the following contributors. * Alex Lembcke * Benjamin Hackl * Darylgolden * Naveen M K * Raghav Goel * ad_chaos * icedcoffeeee Pull requests merged ==================== A total of 9 pull requests were merged for this release. Enhancements ------------ * :pr:`2602`: Support groups in :class:`.TransformMatchingTex` Fixed bugs ---------- * :pr:`2594`: Fixed render flow issues with introducer animations * :pr:`2584`: Fixed bug with invalid color type ``None`` * :pr:`2587`: Fixed bug with rendering Tex string that contain ``%`` * :pr:`2593`: Fixed bug with displaying images in Jupyter Notebooks when ``config.media_embed`` is set to ``False`` Documentation-related changes ----------------------------- * :pr:`2570`: Refactored docstrings in :mod:`.coordinate_systems` * :pr:`2603`: Reduced the number of warnings during documentation build Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2578`: Fixed incorrect type hint for color property of :class:`.Text` New releases ------------ * :pr:`2596`: Prepared bugfix release v0.15.1 ================================================ FILE: docs/source/changelog/0.15.2-changelog.rst ================================================ ******* v0.15.2 ******* :Date: April 25, 2022 Contributors ============ A total of 33 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Bailey Powers + * Benjamin Hackl * Dan Walsh + * Darigov Research * Darylgolden * David Millard + * Hamidreza Hashemi + * Jan-Hendrik Müller * Jason Villanueva * Jonathan Alpert + * Joy Bhalla * Kian Cross + * Luca + * Mohsin Shaikh + * Naveen M K * Prismo + * Ryan McCauley * WillSoltas + * ad_chaos * darkways + * dawn*squirryl + * icedcoffeeee * peaceheis * sparshg * trickypr + The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Dan Walsh * Darylgolden * GameDungeon * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * Jonathan Alpert * Luca * Naveen M K * Prismo * Ryan McCauley * ad_chaos * darkways * hickmott99 * icedcoffeeee * peaceheis Pull requests merged ==================== A total of 39 pull requests were merged for this release. New features ------------ * :pr:`1975`: Improved CLI help page styling - Updates dependencies on Click and Cloup libraries for CLI help page styling. - Removed the dependency on click-default-group. - Added ``no_args_is_help`` parameter for ``manim render`` to allow easy access to help page. - Added note to ``manim`` help page epilog on how to access other command help pages. * :pr:`2404`: Add :class:`.SpiralIn` Animation - Make :class:`.ManimBanner` to use :class:`.SpiralIn`. * :pr:`2534`: Implement :class:`~.OpenGLImageMobject` * :pr:`2684`: Created a more accessible way to create Angles with line.py angle function - :meth:`.Angle.from_three_points` Enhancements ------------ * :pr:`2062`: Reuse shader wrappers and shader data * :pr:`2642`: Migrated ``file_ops.py`` and ``scene_file_writer.py`` from os.path to Pathlib In ``file_ops.py`` and ``scene_file_writer.py``: Uses of str type file names have been mostly (see further information) converted to pathlib's Path objects. Uses of ``os.path`` methods have been converted to equivalent pathlib methods. * :pr:`2655`: Fix :func:`.assert_is_mobject_method` when using OpenGL * :pr:`2665`: Improved handling of attributes when using the ``.animate`` syntax * :pr:`2674`: Document and type ``simple_functions.py`` - Add documentation for ``simple_functions.py``. - Small additions with some extra clarity for these functions. * :pr:`2693`: Allow using :meth:`.MovingCamera.auto_zoom` without animation Allows auto zooming camera without having to play an animation by passing an ``animation=False`` argument Fixed bugs ---------- * :pr:`2546`: Fixed a file logging bug and some maintenance * :pr:`2597`: Fix Bug in :class:`.Uncreate` with ``rate_func`` via introducing new parameter ``reversed`` to :class:`.Animation` - Refractor the :class:`.Uncreate`. The new implementation uses a flag member ``reversed``. Set it to ``True`` and its superclass handles the reverse. - Introduce a bool parameter ``reversed`` to :class:`.Animation`. It decides whether the animation needs to be played backwards. Default to be False. - Add conditional branches in :meth:`.Animation.get_sub_alpha`. If the parameter ``reversed`` is True, it would set ``rate_func(t)`` to ``rate_func(1 - t)``. * :pr:`2613`: Fixed bug in :meth:`.Circle.point_at_angle` when the angle is not in the interval :math:`[0, 2\pi]` * :pr:`2634`: Fix background lines drawn twice in :class:`.NumberPlane` * :pr:`2648`: Handle user-defined centers for Wiggle animation * :pr:`2658`: Fix arguments of overridden ``set_style`` for :class:`.BackgroundRectangle` Using :class:`.Write` animation on a :class:`.Text` object with ``.add_background_rectangle()`` applied no longer generates a ``TypeError``. * :pr:`2668`: (Re)set background color of :class:`.OpenGLRenderer` when initializing scene * :pr:`2676`: Fixed propagation of custom attributes in animations for the OpenGL renderer * :pr:`2688`: Fixed two minor issues of :class:`.SpiralIn` and :class:`.ManimBanner` Documentation-related changes ----------------------------- * :pr:`2609`: Copyedit troubleshooting.rst * :pr:`2610`: Add example PolygonOnAxes * :pr:`2617`: Re-added :mod:`.value_tracker` documentation * :pr:`2619`: Improve Example for arrange_in_grid * :pr:`2620`: Fixed typo in :meth:`.Animation.is_introducer` * :pr:`2640`: Copyedited Documentation Reviewed ``tutorials/configurations.rst``. Edited simple mistakes such as Manim not being capitalized and commas. * :pr:`2649`: Document and type utils/iterables.py * :pr:`2651`: Update copyright year in documentation to 2020-2022 * :pr:`2663`: Added documentation for scene updater functions * :pr:`2686`: Add instructions to install extra dependencies with poetry Changes to our development infrastructure ----------------------------------------- * :pr:`2561`: Run tests on Linux-aarch64 * :pr:`2656`: Fixed incompatibility with black version Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2630`: Remove WebGL renderer The WebGL renderer is broken and unmaintained. The support for it in Manim is removed. * :pr:`2652`: Update ``cloup`` version to 0.13.0 from 0.7.0 * :pr:`2678`: Require ``backports-cached-property`` only for Python < 3.8 * :pr:`2685`: Migrate from ``os.path`` to ``pathlib`` in testing scripts This pull request changes a number of instances of ``os.path`` to Pathlib objects and functions. In addition, this PR modifies the SVGMobject constructor to accept both a Pathlib object or a string variable pathname its constructor. * :pr:`2691`: Removed :class:`CameraFrame` * :pr:`2696`: Made changelog generation run in parallel plus further improvements to ``scripts/dev_changelog.py`` * :pr:`2697`: Sort PRs by number in changelog sections before writing New releases ------------ * :pr:`2694`: Prepared bugfix release v0.15.2 ================================================ FILE: docs/source/changelog/0.16.0-changelog.rst ================================================ ******* v0.16.0 ******* :Date: July 13, 2022 Contributors ============ A total of 44 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Baroudi Aymen + * Benjamin Hackl * Charalampos Georgiou + * Cindy Park + * Ejar + * Francesco Frassinelli + * Francisco Manríquez Novoa + * Jacob Evan Shreve + * Jaime Santos + * Jonathan Alpert * Joshua Mankelow + * Kevin Lubick + * Laith Bahodi * Lingren Kong + * Logen + * Naveen M K * Noam Zaks * Pedro Lamkowski + * Raghav Goel * Simeon Widdis * Sparsh Goenka * TornaxO7 + * Tristan Schulz + * WillSoltas * ad_chaos * conor-oneill-2 + * fcrozatier + * mooncaker816 + * niklebedenko + * nyabkun + * quark67 The patches included in this release have been reviewed by the following contributors. * Alex Lembcke * Benjamin Hackl * Darylgolden * Francesco Frassinelli * Francisco Manríquez Novoa * Gianluca Gippetto * Jan-Hendrik Müller * Jonathan Alpert * Kevin Lubick * Laith Bahodi * Naveen M K * Pedro Lamkowski * Philipp Imhof * Raghav Goel * Ryan McCauley * Sparsh Goenka * TornaxO7 * Tristan Schulz * ad_chaos * hickmott99 Pull requests merged ==================== A total of 56 pull requests were merged for this release. Highlights ---------- * :pr:`2550`: New thematic guide: a deep dive into the internals of the library This new :doc:`thematic guide ` aims to be a comprehensive walkthrough describing all the things that Manim does when you run it to produce a video. * :pr:`2732`: Improved overall structure of deployed documentation; added a dedicated :doc:`FAQ section ` * :pr:`2749`: Added :class:`.ChangeSpeed`, an animation wrapper that allows to smoothly change the speed at which an animation is played The speed of any animation can be changed by wrapping the animation with :class:`.ChangeSpeed` and passing a dictionary as ``speedinfo`` whose keys are the relative animation run time stamps and whose values are the absolute speed factors; e.g., ``{0.5: 2, 0.75: 0.25}`` smoothly speeds up the animation by a factor of 2 once it has been completed to 50%, and then it is smoothly slowed down to 1/4 of the default run speed after 75% of the animation are completed. The ``run_time`` of the animation will be adjusted to match the changed play speed. It is also possible to add time-based updaters that respect the change in speed, use the auxiliary :meth:`.ChangeSpeed.add_updater` method to do so. New features ------------ * :pr:`2667`: Made FFmpeg executable path configurable * :pr:`2739`: Added vectorized plotting functionality via keyword argument ``use_vectorized`` to improve performance Enhancements ------------ * :pr:`2186`: Enabled filling color by value for :class:`.OpenGLSurface`, replaced ``colors`` keyword argument of :meth:`.Surface.set_fill_by_value` with ``colorscale`` * :pr:`2288`: Added warning when attempting to add same mobject as child twice * :pr:`2707`: Fixed missing ``get_nth_curve_length_pieces`` method of :class:`.OpenGLVMobject` - Removed duplicate definition of ``get_curve_functions_with_lengths`` in ``OpenGLVMobject`` - Added definition of ``get_nth_curve_length_pieces`` to ``OpenGLVMobject`` * :pr:`2709`: Improved the look of the brackets of :class:`.Matrix` * :pr:`2714`: Fixed :meth:`.OpenGLVMobject.pointwise_become_partial` to improve stroke rendering * :pr:`2727`: Slight performance improvement for :class:`.ArrowVectorField` and Bézier curve computation * :pr:`2728`: Added :meth:`.VectorField.fit_to_coordinate_system` to fit a vector field to a given coordinate system * :pr:`2730`: Added note to let users find documentation of default CLI subcommand easier * :pr:`2746`: Installed ghostscript in the docker image * :pr:`2841`: Added :func:`.split_quadratic_bezier` and :func:`.subdivide_quadratic_bezier` * :pr:`2842`: CLI: Moved functionality from ``manim new`` to ``manim init`` and added deprecation warning for ``manim new`` * :pr:`2866`: Reorganize test files to match library module structure Fixed bugs ---------- * :pr:`2567`: Use tempconfig for every scene render * :pr:`2638`: Fixed :meth:`BarChart.change_bar_values` not updating when height is 0 * :pr:`2661`: Fixed tip resize functionality for :class:`.Axes` to match documentation * :pr:`2703`: Default to utf-8 when reading files in :class:`.Code` * :pr:`2721`: Fixed bad text slicing for lines in :class:`.Paragraph` * :pr:`2725`: Fixed wrong indentation in :class:`.Code` * :pr:`2734`: Fixed OpenGL segfaults when running :meth:`.Scene.play` or :meth:`.Scene.wait` in interactive mode * :pr:`2753`: Fixed multiplatform builds for docker images in pipeline * :pr:`2757`: Added missing ``__init__.py`` file in :mod:`.docbuild` module * :pr:`2770`: Fixed bug in :meth:`.VMobject.proportion_from_point` that caused proportions greater than 1 to be returned * :pr:`2826`: Fixed leaked mobjects coming from :class:`.TransformMatchingAbstractBase` * :pr:`2870`: Fixed issue with ``manim init scene SCENE_NAME filename.py`` and removed necessity of ``main.py`` to be present in working directory Documentation-related changes ----------------------------- * :pr:`2704`: Updated URL to Pango Markup formatting page * :pr:`2716`: Improved the order of the reference manuals * :pr:`2720`: Fixed typo in docstring of :class:`.Angle` * :pr:`2722`: Fixed typos in docstrings of classes in :mod:`.mobject.table` * :pr:`2726`: Edited note on :class:`.NumberPlane` length and added another example * :pr:`2740`: Fixed documentation of :meth:`.Cylinder.get_direction` * :pr:`2755`: Fixed docstring of :meth:`.VMobject.get_end_anchors` * :pr:`2760`: Removed ``cmake`` from the MacOS installation section * :pr:`2767`: Added more questions and answers to FAQ section, new :doc:`OpenGL FAQ ` * :pr:`2771`: Added documentation and testing for ``path_func`` keyword argument of :class:`.Transform` * :pr:`2828`: Removed suggestion issue template, added FAQ answer regarding proposing new features * :pr:`2849`: Added example for ``path_arc`` keyword argument of :class:`.Transform` * :pr:`2851`: Added an example on constructing a (neural) network using a partite :class:`.Graph` * :pr:`2855`: Added implicit ``docker.io/`` URL base in reference to docker images * :pr:`2861`: Added docstring for :meth:`.CoordinateSystem.plot_parametric_curve` Changes concerning the testing system ------------------------------------- * :pr:`2743`: Replaced ``assert`` statements with with assertion functions from ``np.testing`` Changes to our development infrastructure ----------------------------------------- * :pr:`2700`: CI: updated Python versions * :pr:`2701`: CI: added a workflow to publish docker image after releases and commits to main branch Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2680`: Increased minimum required version of ``numpy`` to 1.19 * :pr:`2687`: Migrated from ``os.path`` to ``pathlib`` in :class:`.SVGMobject` and other locations * :pr:`2715`: Updated deprecated ``pillow`` constants * :pr:`2735`: Bump pyjwt from 2.3.0 to 2.4.0 * :pr:`2748`: Bump pillow from 9.1.0 to 9.1.1 * :pr:`2751`: Fixed flake C417 and improved a comment * :pr:`2825`: Bump notebook from 6.4.11 to 6.4.12 * :pr:`2864`: Updated lockfile New releases ------------ * :pr:`2863`: Prepared new release, ``v0.16.0`` ================================================ FILE: docs/source/changelog/0.17.0-changelog.rst ================================================ ******* v0.17.0 ******* :Date: December 02, 2022 Contributors ============ A total of 32 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Alexander Vázquez * Benjamin Hackl * Duc Phat + * Hugues Devimeux * Ievgen Pyrogov + * Isaac Beh + * Jeff Hanke + * John Hammond + * Jérome Eertmans + * Kevin Lubick * Kian-Meng Ang + * Naveen M K * Nick Skriloff + * NotWearingPants * Onur Solmaz + * OpenRefactory, Inc + * Owen Samuel + * Pavel Zwerschke + * Sparsh Goenka * Taxo Rubio * ad-chaos + * fcrozatier * mostly documentation + * vahndi + The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Darylgolden * Hugues Devimeux * Jan-Hendrik Müller * Kevin Lubick * Mohammed Belgoumri * Naveen M K * NotWearingPants * Raghav Goel * Sparsh Goenka * Tristan Schulz * ad-chaos * friedkeenan Pull requests merged ==================== A total of 63 pull requests were merged for this release. Breaking changes ---------------- * :pr:`2898`: Ported improved implementation of :class:`.SVGMobject` from 3b1b/manim The implementation of :class:`.SVGMobject` is completely changed in this release. Manim now uses the Python library ``svgelements`` to parse SVGs, instead of trying to do it itself. The former class for SVG path objects, ``SVGPathMobject`` has been replaced (without deprecation) with :class:`.VMobjectFromSVGPath`. If you need to create a mobject from an SVG path string, you can do so via:: import svgelements as se my_path_mobject = VMobjectFromSVGPath(se.Path(my_path_string)) The unused class ``TexSymbol`` has been removed. The modules ``manim.mobject.svg.svg_path`` and ``manim.mobject.svg.style_utils`` became superfluous due to the rework and have been removed. * :pr:`3030`: Added support for Python 3.11, dropped support for Python 3.7 Highlights ---------- * :pr:`3049`: Added thematic guide for the ``manim-voiceover`` plugin This new :doc:`thematic guide ` provides a brief introduction to ``manim-voiceover``, a plugin that helps to add voiceovers to your manimations. Supports both working with your own voice as well as synthetically generated voices. New features ------------ * :pr:`2883`: Added animation :class:`.RemoveTextLetterByLetter` * :pr:`3016`: Implemented :class:`.LineJointTypes` for both Cairo and OpenGL renderer * :pr:`3017`: Replaced renderer strings with :class:`.RendererType` enum entries Enhancements ------------ * :pr:`2927`: Allowed ``networkx`` to return 3D layouts when passing ``dim=3`` in the ``layout_config`` of a :class:`.Graph` * :pr:`3014`: Enabled code completion for :meth:`.Mobject.animate` for some IDEs Uses a Union of the existing Generic `Mobject` Type `T` and `_Animation Builder` as the declared return type from `Mobject.animate` to improve code completion. Fixed bugs ---------- * :pr:`2846`: Prevent :class:`.TransformMatchingTex` from crashing when there is nothing to fade * :pr:`2885`: Always expand user when validating file-paths * :pr:`2888`: Fixed bug with propagation of ``tex_template`` value when using ``tempconfig`` * :pr:`2895`: Fixed broken :class:`.ShowPassingFlashWithThinningStrokeWidth` * :pr:`2920`: Fixed alignment of faded lines when passing ``faded_line_ratio`` to :class:`.NumberPlane` * :pr:`2977`: Allow rendering of empty text strings * :pr:`2992`: Fixed ``CLI.tex_template_file`` config file setting * :pr:`3003`: Fixed setting ``run_time`` of :class:`.Succession` after creating the animation object * :pr:`3019`: Fixed rendering SVG paths with multiple move commands Documentation-related changes ----------------------------- * :pr:`2881`: Fixed small typo in deep dive guide * :pr:`2886`: Added docstring to and fixed type hint of :func:`.get_winding_number` * :pr:`2892`: Corrected error in the ``PolygonOnAxes`` example * :pr:`2903`: Fixed minor grammar issues in :doc:`/faq/general` * :pr:`2904`: Fixed formatting and grammar issues in :doc:`/contributing/development` * :pr:`2911`: Disabled autoplay for ``SoundExample`` in documentation * :pr:`2914`: Added conda installation instructions * :pr:`2915`: Added documentation to :mod:`.three_dimensions` * :pr:`2919`: Corrected parameters and enhanced the description of :meth:`.ImageMobject.interpolate_color` * :pr:`2932`: Fixed whitespace formatting issue * :pr:`2933`: Improved answer to the "no scenes in this module" error * :pr:`2936`: Added installation instructions for Windows via ``winget`` * :pr:`2962`: Disabled "Edit on GitHub" button in documentation * :pr:`2978`: Added documentation and example for :class:`.CyclicReplace` * :pr:`3001`: Added FAQ entry regarding failed ``manimpango`` build * :pr:`3004`: Fixed docbuild warnings * :pr:`3018`: Follow-up to :pr:`2988` -- fixes and improvements to some docstrings * :pr:`3022`: Corrected type hint in :meth:`Axes.coords_to_point` * :pr:`3035`: Include latex install instructions on ubuntu * :pr:`3044`: Added Debian dependencies required for pycairo and manimpango Changes concerning the testing system ------------------------------------- * :pr:`2893`: Improved performance of ``test_threed.py`` * :pr:`2981`: Implemented fallback save behavior for ``pytest --show_diff`` * :pr:`2982`: Rewrote unstable tests for :mod:`.text_mobject` to be non-graphical * :pr:`2991`: Migrated ``os.path`` to ``pathlib.Path`` in tests * :pr:`3053`: Added threshold for pixel value errors in frame comparison tests Changes to our development infrastructure ----------------------------------------- * :pr:`2925`: CI (test-arm): Updated python version to ``3.10.6`` * :pr:`2963`: CI (test-arm): Always select the correct python version * :pr:`3029`: CI: Updated actions version and added dependabot config * :pr:`3045`: Updated python-opengl -> python3-opengl for Ubuntu CI task Code quality improvements and similar refactors ----------------------------------------------- * :pr:`2872`: Add ``extract_frames.py`` utility script to help visualize test control data * :pr:`2877`: Fixed binder launch problem by adding missing optional ``notebook`` dependency * :pr:`2887`: Removed empty i18n files that caused filename clashes * :pr:`2931`: Updated ``mapbox-earcut`` * :pr:`2938`: Suggested fixes by iCR, OpenRefactory, Inc. * :pr:`2954`: Fixed click version string in ``pyproject.toml`` * :pr:`2958`: Fix missing stub packages for mypy * :pr:`2975`: Fixed broken links in README * :pr:`2980`: Migrate more ``os.path`` to ``pathlib.Path`` * :pr:`2983`: Fixed Windows CI Pipeline * :pr:`2988`: Converted all types of parameters in docstrings to proper type annotations * :pr:`2994`: Fixed segmentation faults from doctests under Python 3.10 * :pr:`2995`: Added encoding to ``open`` in :mod:`.utils.text_file_writing` * :pr:`3032`: Bump jupyter-core from 4.11.1 to 4.11.2 * :pr:`3033`: Bump pillow from 9.2.0 to 9.3.0 * :pr:`3054`: Removed unused ``GraphicalUnitTester`` New releases ------------ * :pr:`3023`: Prepared new release: v0.17.0 ================================================ FILE: docs/source/changelog/0.17.1-changelog.rst ================================================ ******* v0.17.1 ******* :Date: December 08, 2022 Contributors ============ A total of 5 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Benjamin Hackl * Naveen M K * Onur Solmaz The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Naveen M K * Sparsh Goenka Pull requests merged ==================== A total of 6 pull requests were merged for this release. Fixed bugs ---------- * :pr:`3061`: Always expand file paths using ``/`` when calling LaTeX * :pr:`3062`: Added Unicode encoding in :meth:`.Scene.add_subcaption` Documentation-related changes ----------------------------- * :pr:`2953`: Added documentation for lagged animations in :mod:`.animation.composition` Code quality improvements and similar refactors ----------------------------------------------- * :pr:`3064`: Increased minimal required version of ``svgelements`` * :pr:`3066`: Increased minimal version of ``pytest`` New releases ------------ * :pr:`3065`: Prepared new release: ``v0.17.1`` ================================================ FILE: docs/source/changelog/0.17.2-changelog.rst ================================================ ******* v0.17.2 ******* :Date: December 26, 2022 Contributors ============ A total of 5 people contributed to this release. People with a '+' by their names authored a patch for the first time. * CaftBotti + * Tristan Schulz * lgtm-com[bot] + The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Naveen M K * Tristan Schulz Pull requests merged ==================== A total of 7 pull requests were merged for this release. Fixed bugs ---------- * :pr:`3089`: Fixed OpenGL mobjects like :class:`.Surface` by reordering init calls Documentation-related changes ----------------------------- * :pr:`3073`: Fixed typo: "Whetherer" to "Whether" * :pr:`3074`: Fixed typo in a comment Code quality improvements and similar refactors ----------------------------------------------- * :pr:`3024`: Add CodeQL workflow for GitHub code scanning * :pr:`3079`: Updated CI syntax for runner version >= 2.298.2 * :pr:`3084`: Properly setup CodeQL New releases ------------ * :pr:`3090`: Prepared new Hotfix Release: ``v0.17.2`` ================================================ FILE: docs/source/changelog/0.17.3-changelog.rst ================================================ ******* v0.17.3 ******* :Date: April 06, 2023 Contributors ============ A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Benjamin Hackl * DegrangeM + * Elyanah Aco + * Francisco Manríquez Novoa * Fredrik Lundström + * Frédéric Crozatier * Ikko Eltociear Ashimine + * ItIsJoeyG + * JinchuLi2002 + * Kevin Lubick * KingAndCross + * M. A. Ali + * Matthew Lee + * Max Coplan + * Naveen M K * NotWearingPants * Oscar Rangel + * Papierkorb2292 + * Phoenix2157 + * Tristan Schulz * ciobaca + * coreyp1 + * davidot + * icedcoffeeee * karpfediem + * vahndi The patches included in this release have been reviewed by the following contributors. * Benjamin Hackl * Fredrik Lundström * Frédéric Crozatier * Hugues Devimeux * Kevin Lubick * KingAndCross * Matthew Lee * Naveen M K * Tristan Schulz * coreyp1 * davidot * strager Pull requests merged ==================== A total of 42 pull requests were merged for this release. Deprecated classes and functions -------------------------------- * :pr:`3103`: Removed deprecated function ``OpenGLSurface.set_fill_by_value`` New features ------------ * :pr:`2974`: Added :class:`.DiGraph`, a mobject representing directed graphs * :pr:`3042`: Added :meth:`.Scene.replace` and use in :class:`.ReplacementTransform` * :pr:`3155`: Added support for individualized radius values in :meth:`.Polygram.round_corners` * :pr:`3159`: Added :meth:`.set_opacity_by_tex` method for setting the opacity of parts of Tex mobjects * :pr:`3201`: New tip shape :class:`.StealthTip`, allow specifying tip shape of :class:`.NumberLine` Enhancements ------------ * :pr:`3046`: Add warning if font is not found for Text, Code, and MarkupText * :pr:`3083`: Minor performance improvement in :mod:`.bezier` with preallocating array * :pr:`3092`: Improved :meth:`.Mobject.add` performance by checking for redundancy only once * :pr:`3134`: Performance: Store color data of ``OpenGLSurface`` to prevent OpenGL embed lag * :pr:`3180`: Performance: Speed up width/height/depth calculations by reducing copying * :pr:`3181`: Improved creation time for large :class:`.Text` mobjects * :pr:`3182`: Reduce memory allocations when building :class:`.SVGMobject` * :pr:`3191`: Fixed OpenGL rendering in named threads Fixed bugs ---------- * :pr:`3015`: Fixed bug with ``label_constructor`` in :meth:`.NumberLine.add_labels` * :pr:`3095`: Fixed ``get_axis_labels`` for :class:`.Axes` and :class:`.ThreeDAxes` * :pr:`3106`: Fixed ignored ``depth_test`` argument for ``OpenGLVMobjects`` * :pr:`3149`: Allow to use ``call_updater=True`` in :meth:`.Mobject.add_updater` with non-timebased updaters too * :pr:`3152`: Fixed behavior of :class:`.Wait` and :meth:`.Scene.wait` with specified ``stop_condition`` * :pr:`3163`: Fixed :class:`.BraceLabel` not passing additional keyword arguments to :class:`.Brace` * :pr:`3195`: Fixed :class:`.Axes` scaling for :meth:`.plot_implicit_curve` Documentation-related changes ----------------------------- * :pr:`3105`: Converted types specified in docstrings to proper type hints in :mod:`.three_dimensions` * :pr:`3108`: Clarified documentation for ``--resolution`` command line flag * :pr:`3109`: Clean-up, type-hints and documentation for :mod:`.three_dimensions` * :pr:`3124`: Fixed docstring of :meth:`.ThreeDCamera.get_value_trackers` * :pr:`3126`: Fixed dead links to troubleshooting page * :pr:`3137`: Fixed example using ``reverse=True`` with :class:`.Write` * :pr:`3160`: Fixed a typo * :pr:`3189`: Corrected the hinted return type for :func:`angle_between_vectors` * :pr:`3199`: Updated ``winget`` command for installing MiKTeX in documentation * :pr:`3204`: Fixed docstring formatting of :meth:`.Scene.replace` and improved its error handling Code quality improvements and similar refactors ----------------------------------------------- * :pr:`3144`: Fixed typo in ``stripUntranslatable.awk`` * :pr:`3154`: Bump ipython from 8.7.0 to 8.10.0 * :pr:`3156`: CI: Remove actions using self-hosted runners * :pr:`3164`: Bump markdown-it-py from 2.1.0 to 2.2.0 * :pr:`3165`: Removed deprecated keyword argument in :meth:`.Mobject.align_to` * :pr:`3166`: Made :class:`.ArrowTriangleTip`, :class:`.ArrowTriangleFilledTip` available to module namespace * :pr:`3179`: Fixed deprecation warning in :class:`.ParametricFunction` with ``use_vectorized=True`` * :pr:`3186`: Updated extlinks to work with latest version of Sphinx * :pr:`3196`: CI: updated PATH for recent changed in TinyTex * :pr:`3200`: Made import from ``moderngl`` compatible with more recent versions New releases ------------ * :pr:`3198`: Prepare new release: v0.17.3 ================================================ FILE: docs/source/changelog/0.18.0-changelog.rst ================================================ ******* v0.18.0 ******* :Date: November 11, 2023 Contributors ============ A total of 41 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Abulafia + * Adhyyan Sekhsaria + * Adrien Ludwig + * Alex Kempen + * Andres Berejnoi + * Anousheh Moonen + * Benjamin Hackl * Francisco Manríquez Novoa * Harald Schilly + * Immanuel-Alvaro-Bhirawa + * Jason Grace + * Jason Villanueva * Jinchu Li * John Lynch + * Jérome Eertmans * Matt Turner + * Narahari Rao + * Naveen M K * Nikhil Iyer + * Ron Li + * Sujal Singh + * Tristan Schulz * Uwe Zimmermann + * Václav Blažej + * Zachary Winkeler + The patches included in this release have been reviewed by the following contributors. * Alex Lembcke * Andres Berejnoi * Axel * Benjamin Hackl * Francisco Manríquez Novoa * Immanuel-Alvaro-Bhirawa * Jan-Hendrik Müller * Jason Grace * Jason Villanueva * Jinchu Li * John Lynch * Jérome Eertmans * Kevin Lubick * Narahari Rao * Naveen M K * NotWearingPants * SsNiPeR1 * TheMathematicFanatic * Tristan Schulz * Uwe Zimmermann * Viicos * icedcoffeeee Pull requests merged ==================== A total of 59 pull requests were merged for this release. Breaking changes ---------------- * :pr:`3020`: Rewrote Manim's color system This change removed the ``colour`` library as a dependency of Manim and replaced the internal handling of colors with the newly added :class:`.ManimColor`. This also adds hundreds of new predefined colors, see :mod:`.utils.color` for more details. This should only be a breaking change if you have interacted directly with the ``colour`` module before. The general interface has been kept stable. Highlights ---------- * :pr:`3299`: Added new ``manim checkhealth`` CLI subcommand This adds a new command line interface subcommand which can be used to check whether a local installation of Manim has been configured correctly, and all required (and optional) dependencies are available. To try it, run it via ``manim checkhealth`` or ``python -m manim checkhealth``. * :pr:`3427`: New feature: rendered examples in documentation can now be run directly via binder This adds a "Make interactive" button below the examples in our documentation that establishes a connection to binder such that examples can be modified and rerendered directly from your browser. * :pr:`3086`: Introduced a new module :mod:`.typing` for type hints This also adds various type hints to integral parts of the code base. * :pr:`3322`: Implemented auto-removal of auxiliary LaTeX files, enabled by default This automatically removes auxiliary files creating during the compilation of LaTeX documents like ``.aux`` or ``.dvi`` files. This behavior can be controlled via the newly introduced ``no_latex_cleanup`` config key (``False`` by default). On the command line, the autoremoval can be disabled via the ``--no_latex_cleanup`` CLI flag. * :pr:`3395`: Added support for Python 3.12 New features ------------ * :pr:`3361`: Added three new rate functions This adds the rate functions :func:`.smoothstep`, :func:`.smootherstep`, :func:`.smoothererstep` based on the SmoothStep sigmoid functions. * :pr:`3264`: Added new mobjects :class:`.LabeledLine` and :class:`.LabeledArrow` Enhancements ------------ * :pr:`3190`: Made :class:`.CurvesAsSubmobjects` mobjects compatible with :meth:`.input_to_graph_point` * :pr:`3226`: Avoid using a mobject as a default argument of :class:`.ArcBrace` * :pr:`3366`: Added spacing between values and unit in :class:`.DecimalNumber` This adds the new keyword argument ``unit_buff_per_font_unit`` (default: 0, for backwards compatibility). Setting it to some positive number creates additional space between the numeric value and the displayed unit. Fixed bugs ---------- * :pr:`3205`: Fixed type hint of ``angle`` in :class:`.Arc` * :pr:`3210`: Fixed :class:`.DecimalNumber` with ``show_ellipsis=True`` with the OpenGL renderer * :pr:`3211`: Fixed display issues with custom labels for :class:`.Axes` with the OpenGL renderer * :pr:`3298`: Fixed expand animation for :class:`.ManimBanner` * :pr:`3306`: Fixed IPython terminal history and embedded shell instantiation for scenes using :meth:`.Scene.interactive_embed` * :pr:`3315`: Fixed issue with parameter types in :meth:`.Scene.add_subcaption` * :pr:`3423`: Fixed incorrect submobject count of multi-part :class:`.Tex` mobjects This resolves various issues where formulas were not displayed completely, like it was the case with ``MathTex("1", "^{", "0")``. * :pr:`3284`: Fixed ``LinearTransformationSceneExample`` in Jupyter notebooks * :pr:`3302`: Fixed typo in comparison in :meth:`.OpenGLVMobject.interpolate` * :pr:`3340`: Fixed incorrect computation of bounding box for rotated :class:`.ImageMobject` * :pr:`3343`: Fixed return value of :meth:`.TexTemplate.add_to_preamble` and :meth:`.TexTemplate.add_to_document` * :pr:`3282`: Ensure that :meth:`.ArrowVectorField.get_vector` does not modify the passed inputs * :pr:`3392`: Fixed behavior of elongated tick lines for :class:`.NumberLine` * :pr:`3430`: Fixed CSV reader adding empty lists in rendering summary during documentation build * :pr:`3404`: Properly raise an exception on empty inputs to :class:`.AddTextLetterByLetter` Documentation-related changes ----------------------------- * :pr:`3219`: Enabled social cards for links to documentation * :pr:`3274`: Replaced incorrect mentions of Python 3.7 as the minimally required version * :pr:`3297`: Improved arrow tip sowcase example for :class:`.ArrowTip` * :pr:`3312`: Added documentation for :func:`.always_redraw` * :pr:`3218`: Improved grammar in the :doc:`deep dive guide ` * :pr:`3251`: Add LaTeX installation instructions for Fedora * :pr:`3290`: Updated required dependencies for MacOS installations * :pr:`3325`: Added documentation for functions in :mod:`.mobject_update_utils` This adds docstrings and typehints to :func:`.always_rotate`, :func:`.always_shift`, :func:`.turn_animation_into_updater` * :pr:`3353`: Added documentation for :meth:`.Mobject.center` * :pr:`3355`: Temporarily enabled ``htmlzip`` build on ReadTheDocs * :pr:`3377`: Fixed a typo in the :doc:`deep dive guide ` * :pr:`3389`: Removed superfluous curly braces in a LaTeX expression * :pr:`3417`: Replaced ``htmlzip`` ReadTheDocs build with workflow attaching downloadable documentation to GitHub releases Changes concerning the testing system ------------------------------------- * :pr:`3416`: Fixed tests to run on Cairo 1.18.0 * :pr:`3257`: Fix a configuration error concerning poetry * :pr:`3419`: Fixed caching of Cairo builds on CI runners Code quality improvements and similar refactors ----------------------------------------------- * :pr:`3229`: Made docbuild errors easier to debug and fixed error from changed exception class * :pr:`3231`: Fixed errors reported by ``flake8`` * :pr:`3232`: Upgrade ReadTheDocs build environment to use newer image * :pr:`3286`: Optimized :meth:`.Axes.coords_to_point` * :pr:`3224`: Replace final few occurrences of ``os.path`` by ``pathlib.Path`` * :pr:`3236`: Return self in :meth:`.AbstractImageMobject.set_resampling_algorithm` * :pr:`3253`: Bump tornado from 6.3.1 to 6.3.2 * :pr:`3272`: Bump docker/build-push-action from 3 to 4 * :pr:`3287`: Bump cryptography from 41.0.1 to 41.0.2 * :pr:`3350`: Added missing dependency ``typing-extensions`` * :pr:`3431`: Bump teatimeguest/setup-texlive-action from 2 to 3 * :pr:`3433`: Bump dependencies * :pr:`3399`: Updated several dependencies * :pr:`3397`: Several GitHub actions updates * :pr:`3405`: Updated manimpango version to fix error regarding type strictness * :pr:`3421`: Improved order of input checks when creating a tree graph New releases ------------ * :pr:`3439`: Prepared new release: v0.18.0 ================================================ FILE: docs/source/changelog/0.18.0.post0-changelog.rst ================================================ ************* v0.18.0.post0 ************* :Date: April 08, 2024 This release is a post-release fixing `#3676 `_, a bug caused by a recent change introduced to the way how SVG files of text are generated by Pango. ================================================ FILE: docs/source/changelog/0.18.1-changelog.md ================================================ --- short-title: v0.18.1 description: Changelog for Manim v0.18.1 --- # v0.18.1 Date : April 28, 2024 ## What's Changed ### Breaking Changes and Deprecations * Removed deprecated `manim new` command by {user}`chopan050` in {pr}`3512` * Removed support for dynamic plugin imports by {user}`Viicos` in {pr}`3524` * Remove meth:``.Mobject.wag`` by {user}`JasonGrace2282` in {pr}`3539` * Remove deprecated parameters and animations by {user}`JasonGrace2282` in {pr}`3688` ### New Features * Added `cap_style` feature to `VMobject` by {user}`MathItYT` in {pr}`3516` * Allow hiding version splash by {user}`jeertmans` in {pr}`3329` * Added the ability to pass lists and generators to `Scene.play()` by {user}`MrDiver` in {pr}`3365` * Added ``--preview_command`` cli flag by {user}`JasonGrace2282` in {pr}`3615` ### Fixed Bugs and Enhancements * Allow accessing ghost vectors in :class:`.LinearTransformationScene` by {user}`JasonGrace2282` in {pr}`3435` * Optimized `get_unit_normal()` and replaced `np.cross()` with custom `cross()` in `manim.utils.space_ops` by {user}`chopan050` in {pr}`3494` * Implement caching of fonts list to improve runtime performance by {user}`MrDiver` in {pr}`3316` * Reformatting the `--save_sections` output to have the format `__` by {user}`doaamuham` in {pr}`3499` * Account for dtype in the pixel array so the maximum value stays correct in the invert function by {user}`jeertmans` in {pr}`3493` * Added `grid_lines` attribute to `Rectangle` to add individual styling to the grid lines by {user}`RobinPH` in {pr}`3428` * Fixed rectangle grid properties (#3082) by {user}`pauluhlenbruck` in {pr}`3513` * Fixed animations with zero runtime length to give a useful error instead of a broken pipe by {user}`MrDiver` in {pr}`3491` * Fixed stroke width being ignored by `StreamLines` with a single color by {user}`yashm277` in {pr}`3436` * Fixed formatting of ``MoveAlongPath`` docs by {user}`JasonGrace2282` in {pr}`3541` * Added helpful hints to `VGroup.add()` error message by {user}`vvolhejn` in {pr}`3561` * Made `earclip_triangulation` more robust by {user}`hydromelvictor` in {pr}`3574` * Refactored `TexTemplate` by {user}`Viicos` in {pr}`3520` * Fixed `write_subcaption_file` error when using OpenGL renderer by {user}`yuan-xy` in {pr}`3546` * Fixed `get_arc_center()` returning reference of point by {user}`sparshg` in {pr}`3599` * Improved handling of specified font name by {user}`staghado` in {pr}`3429` * Fixing the behavior of `.become` to not modify target mobject via side effects fix color linking by {user}`MrDiver` in {pr}`3508` * Fixed bug in :class:`.VMobjectFromSVGPath` by {user}`abul4fia` in {pr}`3677` * Fix for windows cp1252 encoding failure (fix test pipeline) by {user}`JasonGrace2282` in {pr}`3687` * Fix NameError in try... except by {user}`JasonGrace2282` in {pr}`3694` * Fix successive calls of :meth:`.LinearTransformationScene.apply_matrix` by {user}`SirJamesClarkMaxwell` in {pr}`3675` * Fixed `Mobject.put_start_and_end_on` with same start and end point by {user}`MontroyJosh` in {pr}`3718` * Fixed issue where `SpiralIn` doesn't show elements by {user}`Gixtox` in {pr}`3589` * Cleaned `Graph` layouts and increase flexibility by {user}`Nikhil-42` in {pr}`3434` * `AnimationGroup`: optimized `interpolate()` and fixed alpha bug on `finish()` by {user}`chopan050` in {pr}`3542` * Fixed warning about missing plugin `""` by {user}`behackl` in {pr}`3734` ### Documentation * Typo in `indication` documentation by {user}`jcep` in {pr}`3477` * Fixed typo: 360° to 180° in quickstart tutorial by {user}`szchixy` in {pr}`3498` * Fixed typo in mobject docstring: `line` -> `square` by {user}`yuan-xy` in {pr}`3509` * Explain ``.Transform`` vs ``.ReplacementTransform`` in quickstart examples by {user}`JasonGrace2282` in {pr}`3500` * Fixed formatting in building blocks tutorial by {user}`MrDiver` in {pr}`3515` * Fixed `Indicate` docstring typo by {user}`Lawqup` in {pr}`3461` * Added Documentation to `.to_edge` and `to_corner` by {user}`TheMathematicFanatic` in {pr}`3408` * Added some words about Cairo 1.18 by {user}`jeertmans` in {pr}`3530` * Fixed typo of `get_y_axis_label` parameter documentation by {user}`yuan-xy` in {pr}`3547` * Added note in docstring of `ManimColor` about class constructors by {user}`JasonGrace2282` in {pr}`3554` * Improve documentation section about contributing to docs by {user}`chopan050` in {pr}`3555` * Removed duplicated documentation for -s / --save_last_frame CLI flag by {user}`Gixtox` in {pr}`3528` * Updated Docker instructions to use bash from the PATH by {user}`NotWearingPants` in {pr}`3582` * Fixed typo in `value_tracker.py` by {user}`yuan-xy` in {pr}`3594` * Added `ref_class` for `BooleanOperations` in Example Gallery by {user}`JasonGrace2282` in {pr}`3598` * Changed `Vector3` to `Vector3D` in contributing docs by {user}`JasonGrace2282` in {pr}`3639` * Added some examples for `Mobject`/`VMobject` methods by {user}`JasonGrace2282` in {pr}`3641` * Fixed broken link to Poetry's installation guide in the documentation by {user}`biinnnggggg` in {pr}`3692` * Fixed minor grammatical errors found in the index page of the documentation by {user}`biinnnggggg` in {pr}`3690` * Fixed typo on page about translations by {user}`biinnnggggg` in {pr}`3696` * Fixed outdated description of CLI option in Manim's Output Settings by {user}`HairlessVillager` in {pr}`3674` * Mention pixi in installation guide by {user}`pavelzw` in {pr}`3678` * Updated typing guidelines by {user}`JasonGrace2282` in {pr}`3704` * Updated documentation and typings for `ParametricFunction` by {user}`danielzsh` in {pr}`3703` * Fixed docstring markup in `Rotate` by {user}`TheCrowned` in {pr}`3721` * Improve consistency in axis label example by {user}`amrear` in {pr}`3730` ### Maintenance and Testing * Fixed wrong path in action building downloadable docs by {user}`behackl` in {pr}`3450` * Add type hints to `_config` by {user}`Viicos` in {pr}`3440` * Update dependency constraints, fix deprecation warnings by {user}`Viicos` in {pr}`3376` * Update Docker base image to python3.12-slim (#3458) by {user}`PikaBlue107` in {pr}`3459` * Fixed `line_join` to `joint_type` in example_scenes/basic.py by {user}`szchixy` in {pr}`3510` * Fixed :attr:`.Mobject.animate` type-hint to allow LSP autocomplete by {user}`JasonGrace2282` in {pr}`3543` * Finish TODO's in ``contributing/typings.rst`` by {user}`JasonGrace2282` in {pr}`3545` * Fixed use of `Mobject`'s deprecated `get_*()` and `set_*()` methods in Cairo tests by {user}`JasonGrace2282` in {pr}`3549` * Added support for Manim type aliases in Sphinx docs and added new TypeAliases by {user}`chopan050` in {pr}`3484` * Fixed typing of `Animation` by {user}`dandavison` in {pr}`3568` * Added some TODOs for future use of `ManimFrame` by {user}`chopan050` in {pr}`3553` * Fixed typehint of :attr:`InternalPoint2D_Array` by {user}`JasonGrace2282` in {pr}`3592` * Fixed error in Windows CI pipeline by {user}`behackl` in {pr}`3611` * Fixed type hint of indication.py by {user}`yuan-xy` in {pr}`3613` * Revert vector type aliases to NumPy ndarrays by {user}`chopan050` in {pr}`3595` * Run `poetry lock --no-update` by {user}`JasonGrace2282` in {pr}`3621` * Code Cleanup: removing unused imports and global variables by {user}`JasonGrace2282` in {pr}`3620` * Fixed type hint of `Vector` direction parameter by {user}`JasonGrace2282` in {pr}`3640` * Flake8 rule C901 is about McCabe code complexity by {user}`cclauss` in {pr}`3673` * Updated year in license by {user}`JasonGrace2282` in {pr}`3689` * Automated copyright updating for docs by {user}`JasonGrace2282` in {pr}`3708` * Fixed some typehints in `mobject.py` by {user}`JasonGrace2282` in {pr}`3668` * Search for type aliases if TYPE_CHECKING by {user}`JasonGrace2282` in {pr}`3671` * Follow-up to graph layout cleanup: improvements for tests and typing by {user}`behackl` in {pr}`3728` * GH Actions: Changed from macos-latest to macos-13 by {user}`JasonGrace2282` in {pr}`3729` * Fixed return type inconsistency for `get_anchors()` by {user}`JinchuLi2002` in {pr}`3214` * Prepared new release: `v0.18.1` by {user}`behackl` in {pr}`3719` #### Dependency Version Changes * Bump jupyter-server from 2.9.1 to 2.11.2 by {user}`dependabot` in {pr}`3497` * Bump github/codeql-action from 2 to 3 by {user}`dependabot` in {pr}`3567` * Bump actions/upload-artifact from 3 to 4 by {user}`dependabot` in {pr}`3566` * Bump actions/setup-python from 4 to 5 by {user}`dependabot` in {pr}`3565` * updated several packages (pillow, jupyterlab, notebook, jupyterlab-lsp, jinja2, gitpython) by {user}`behackl` in {pr}`3593` * Update jupyter.rst by {user}`abul4fia` in {pr}`3630` * Bump black from 23.12.1 to 24.3.0 by {user}`dependabot` in {pr}`3649` * Bump cryptography from 42.0.0 to 42.0.4 by {user}`dependabot` in {pr}`3629` * Bump actions/cache from 3 to 4 by {user}`dependabot` in {pr}`3607` * Bump FedericoCarboni/setup-ffmpeg from 2 to 3 by {user}`dependabot` in {pr}`3608` * Bump ssciwr/setup-mesa-dist-win from 1 to 2 by {user}`dependabot` in {pr}`3609` * Bump idna from 3.6 to 3.7 by {user}`dependabot` in {pr}`3693` * Bump pillow from 10.2.0 to 10.3.0 by {user}`dependabot` in {pr}`3672` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci` in {pr}`3332` * Updated sphinx deps by {user}`JasonGrace2282` in {pr}`3720` ## New Contributors * {user}`Lawqup` made their first contribution in {pr}`3461` * {user}`jcep` made their first contribution in {pr}`3477` * {user}`szchixy` made their first contribution in {pr}`3498` * {user}`PikaBlue107` made their first contribution in {pr}`3459` * {user}`yuan-xy` made their first contribution in {pr}`3509` * {user}`MathItYT` made their first contribution in {pr}`3516` * {user}`doaamuham` made their first contribution in {pr}`3499` * {user}`RobinPH` made their first contribution in {pr}`3428` * {user}`pauluhlenbruck` made their first contribution in {pr}`3513` * {user}`yashm277` made their first contribution in {pr}`3436` * {user}`TheMathematicFanatic` made their first contribution in {pr}`3408` * {user}`vvolhejn` made their first contribution in {pr}`3561` * {user}`hydromelvictor` made their first contribution in {pr}`3574` * {user}`dandavison` made their first contribution in {pr}`3568` * {user}`Gixtox` made their first contribution in {pr}`3528` * {user}`staghado` made their first contribution in {pr}`3429` * {user}`biinnnggggg` made their first contribution in {pr}`3692` * {user}`HairlessVillager` made their first contribution in {pr}`3674` * {user}`SirJamesClarkMaxwell` made their first contribution in {pr}`3675` * {user}`danielzsh` made their first contribution in {pr}`3703` * {user}`TheCrowned` made their first contribution in {pr}`3721` * {user}`MontroyJosh` made their first contribution in {pr}`3718` * {user}`amrear` made their first contribution in {pr}`3730` **Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.18.0.post0...v0.18.1 ================================================ FILE: docs/source/changelog/0.19.0-changelog.rst ================================================ ******* v0.19.0 ******* :Date: January 20, 2025 Major Changes ============= With the release of Manim v0.19.0, we've made lots of progress with making Manim easier to install! One of the biggest changes in this release is the replacement of the external ``ffmpeg`` dependency with the ``pyav`` library. This means that users no longer have to install ``ffmpeg`` in order to use Manim - they can just ``pip install manim`` and it will work! In light of this change, we also rewrote our :ref:`installation docs ` to recommend using a new tool called `uv `_ to install Manim. .. note:: Do not worry if you installed Manim with any previous methods, like homebrew, pip, choco, or scoop. Those methods will still work, and are not deprecated. However, the recommended way to install Manim is now with `uv `_. Contributors ============ A total of 54 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Aarush Deshpande * Abulafia * Achille Fouilleul + * Benjamin Hackl * CJ Lee + * Cameron Burdgick + * Chin Zhe Ning * Christopher Hampson + * ChungLeeCN + * Eddie Ruiz + * F. Muenkel + * Francisco Manríquez Novoa * Geoo Chi + * Henrik Skov Midtiby + * Hugo Chargois + * Irvanal Haq + * Jay Gupta + * Laifsyn + * Larry Skuse + * Nemo2510 + * Nikhil Iyer * Nikhila Gurusinghe + * Rehmatpal Singh + * Romit Mohane + * Saveliy Yusufov + * Sir James Clark Maxwell * Sophia Wisdom + * Tristan Schulz * VPC + * Victorien * Xiuyuan (Jack) Yuan + * alembcke * anagorko + * czuzu + * fogsong233 + * jkjkil4 + * modjfy + * nitzanbueno + * yang-tsao + The patches included in this release have been reviewed by the following contributors. * Aarush Deshpande * Achille Fouilleul * Benjamin Hackl * Christopher Hampson * Eddie Ruiz * Francisco Manríquez Novoa * Henrik Skov Midtiby * Hugo Chargois * Irvanal Haq * Jay Gupta * Jérome Eertmans * Nemo2510 * Nikhila Gurusinghe * OliverStrait * Saveliy Yusufov * Sir James Clark Maxwell * Tristan Schulz * VPC * Victorien * Xiuyuan (Jack) Yuan * alembcke * github-advanced-security[bot] Pull requests merged ==================== A total of 138 pull requests were merged for this release. Highlights ---------- * :pr:`3501`: Replaced external ``ffmpeg`` dependency with ``pyav`` This change removes the need to have ``ffmpeg`` available as a command line tool when using Manim. While ``pyav`` technically also uses ``ffmpeg`` internally, the maintainers of ``pyav`` distribute it in their binary wheels. * :pr:`3518`: Created a :class:`.HSV` color class, and added support for custom color spaces This extends the color system of Manim and adds support to implement custom color spaces. See the implementation of :class:`.HSV` for a practical example. * :pr:`3930`: Completely reworked the installation instructions As a consequence of removing the need for the external ``ffmpeg`` dependency, we have reworked and massively simplified the installation instructions. Given that practically, user-written scenes are effectively small self-contained Python projects, the new instructions strongly recommend using the `project and dependency management tool uv `__ to ensure a consistent and reproducible environment. * :pr:`3967`: Added support for Python 3.13 This adds support for Python 3.13, which brings the range of currently supported Python versions to 3.9 -- 3.13. * :pr:`3966`: :class:`.VGroup` can now be initialized with :class:`.VMobject` iterables Groups of Mobjects can now be created by passing an iterable to the :class:`.VGroup` constructors:: my_group = VGroup(Dot() for _ in range(10)) Breaking changes ---------------- * :pr:`3797`: Replaced ``Code.styles_list`` with :meth:`.Code.get_styles_list` The ``styles_list`` attribute of the :class:`.Code` class has been replaced with a class method :meth:`.Code.get_styles_list`. This method returns a list of all available values for the ``formatter_style`` argument of :class:`.Code`. * :pr:`3884`: Renamed parameters and variables conflicting with builtin functions To avoid having keyword arguments named after builtin functions, the following two changes were made to user-facing functions: - ``ManimColor.from_hex(hex=...)`` is now ``ManimColor.from_hex(hex_str=...)`` - ``Scene.next_section(type=...)`` is now ``Scene.next_section(section_type=...)`` * :pr:`3922`: Removed ``inner_radius`` and ``outer_radius`` from :class:`.Sector` constructor To construct a :class:`.Sector`, you now need to specify a ``radius`` (and an ``angle``). In particular, :class:`.AnnularSector` still accepts both ``inner_radius`` and ``outer_radius`` arguments. * :pr:`3964`: Allow :class:`.SurroundingRectangle` to accept multiple Mobjects This changes the signature of :class:`.SurroundingRectangle` to accept a sequence of Mobjects instead of a single Mobject. As a consequence, other arguments that could be specified as positional ones before now need to be specified as keyword arguments:: SurroundingRectangle(some_mobject, RED, 0.3) # raises error now SurroundingRectangle(some_mobject, color=RED, buff=0.3) # correct usage * :pr:`4115`: Completely rewrite the implementation of the :class:`.Code` mobject This includes several breaking changes to the interface of the class to make it more consistent. See the documentation of :class:`.Code` for a detailed description of the new interface, and the description of the pull request :pr:`4115` for an overview of changes to the old keyword arguments. New features ------------ * :pr:`3148`: Added a ``colorscale`` argument to :meth:`.CoordinateSystem.plot` * :pr:`3612`: Add three animations that together simulate a typing animation * :pr:`3754`: Add ``@`` shorthand for :meth:`.Axes.coords_to_point` and :meth:`.Axes.point_to_coords` * :pr:`3876`: Add :meth:`.Animation.set_default` class method * :pr:`3903`: Preserve colors of LaTeX coloring commands * :pr:`3913`: Added :mod:`.DVIPSNAMES` and :mod:`.SVGNAMES` color palettes * :pr:`3933`: Added :class:`.ConvexHull`, :class:`.ConvexHull3D`, :class:`.Label` and :class:`.LabeledPolygram` * :pr:`3992`: Add darker, lighter and contrasting methods to :class:`.ManimColor` * :pr:`3997`: Add a time property to scene (:attr:`.Scene.time`) * :pr:`4039`: Added the ``delay`` parameter to :func:`.turn_animation_into_updater` Enhancements ------------ * :pr:`3829`: Rewrite :func:`~.bezier.get_quadratic_approximation_of_cubic` to produce smoother animated curves * :pr:`3855`: Log execution time of sample scene in the ``manim checkhealth`` command * :pr:`3888`: Significantly reduce rendering time with a separate thread for writing frames to stream * :pr:`3890`: Better error messages for :class:`.DrawBorderThenFill` * :pr:`3893`: Improve line rendering performance of :class:`.Cylinder` * :pr:`3901`: Changed :attr:`.Square.side_length` attribute to a property * :pr:`3965`: Added the ``scale_stroke`` boolean parameter to :meth:`.VMobject.scale` * :pr:`3974`: Made videos embedded in Google Colab by default * :pr:`3982`: Refactored ``run_time`` validation for :class:`.Animation` and :meth:`.Scene.wait` * :pr:`4017`: Allow animations with ``run_time=0`` and implement convenience :class:`.Add` animation * :pr:`4034`: Draw more accurate circular :class:`.Arc` mobjects for large angles * :pr:`4051`: Add ``__hash__`` method to :class:`.ManimColor` * :pr:`4108`: Remove duplicate declaration of ``__all__`` in :mod:`.vectorized_mobject` Optimizations ------------- * :pr:`3760`: Optimize :meth:`.VMobject.pointwise_become_partial` * :pr:`3765`: Optimize :class:`.VMobject` methods which append to ``points`` * :pr:`3766`: Created and optimized Bézier splitting functions such as :func:`~.utils.bezier.partial_bezier_points()` in :mod:`manim.utils.bezier` * :pr:`3767`: Optimized :func:`manim.utils.bezier.get_smooth_cubic_bezier_handle_points()` * :pr:`3768`: Optimized :func:`manim.utils.bezier.is_closed` * :pr:`3960`: Optimized :func:`~.bezier.interpolate` and :func:`~.bezier.bezier` in :mod:`manim.utils.bezier` Fixed bugs ---------- * :pr:`3706`: Fixed :meth:`.Line.put_start_and_end_on` to use the actual end of an :class:`.Arrow3D` * :pr:`3732`: Fixed infinite loop in OpenGL :meth:`.BackgroundRectangle.get_color` * :pr:`3756`: Fix assertions and improve error messages when adding submobjects * :pr:`3778`: Fixed :func:`.there_and_back_with_pause` rate function behaviour with different ``pause_ratio`` values * :pr:`3786`: Fix :class:`.DiGraph` edges not fading correctly on :class:`.FadeIn` and :class:`.FadeOut` * :pr:`3790`: Fixed the :func:`.get_nth_subpath` function expecting a numpy array * :pr:`3832`: Convert audio files to ``.wav`` before passing to pydub * :pr:`3680`: Fixed behavior of ``config.background_opacity < 1`` * :pr:`3839`: Fixed :attr:`.ManimConfig.format` not updating movie file extension * :pr:`3885`: Fixed :meth:`.OpenGLMobject.invert` not reassembling family * :pr:`3951`: Call :meth:`.Animation.finish` for animations in an :class:`.AnimationGroup` * :pr:`4013`: Fixed scene skipping for :attr:`ManimConfig.upto_animation_number` set to 0 * :pr:`4089`: Fixed bug with opacity of :class:`.ImageMobject` * :pr:`4091`: Fixed :meth:`.VMobject.add_points_as_corners` to safely handle empty ``points`` parameter Documentation-related changes ----------------------------- * :pr:`3669`: Added a :mod:`manim.typing` guide * :pr:`3715`: Added docstrings to Brace * :pr:`3745`: Underline tag should be ```` in the documentation * :pr:`3818`: Automatically document usages of :class:`typing.TypeVar` * :pr:`3849`: Fix incorrect ``versionadded`` version number in plugin section in docs * :pr:`3851`: Rename ``manim.typing.Image`` type aliases to :class:`.PixelArray` to avoid conflict with ``PIL.Image`` * :pr:`3857`: Update installation instructions for MacOS (via dedicated brew formula) * :pr:`3878`: Fixed typehint in ``types.rst`` and replaced outdated reference to ``manim.typing.Image`` with :class:`manim.typing.PixelArray` * :pr:`3924`: Fix ``SyntaxWarning`` when building docs + use Python 3.13 for readthedocs build * :pr:`3958`: Fix: ``.to_edge``'s example demonstration in docs * :pr:`3972`: Refining documentations for :mod:`.moving_camera_scene` module * :pr:`4032`: Bump version and create changelog for ``v0.19.0`` * :pr:`4044`: Added support for autodocumenting type aliases that use the ``type`` syntax * :pr:`4065`: Polish documentation of :mod:`.utils.color.core` and remove ``interpolate_array`` function * :pr:`4077`: Update README and documentation landing page, improve way how 3b1b is credited * :pr:`4100`: Add wavy square example to :class:`.Homotopy` * :pr:`4107`: Corrected a typo in the deep dive guide * :pr:`4116`: Fix broken link to Poetry installation in contribution docs Type Hints ---------- * :pr:`3751`: Added typehints to :mod:`manim.utils.iterables` * :pr:`3803`: Added typings to :class:`.OpenGLMobject` * :pr:`3902`: fixed a wrong type hint in :meth:`.Scene.restructure_mobjects` * :pr:`3916`: fixed type hint in :meth:`.DrawBorderThenFill.interpolate_submobject` * :pr:`3926`: Fixed some typehints of :class:`.ParametricFunction` * :pr:`3940`: Fixed ``np.float_`` to ``np.float64`` while using numpy versions above 2.0 * :pr:`3961`: Added typehints to :mod:`manim.mobject.geometry` * :pr:`3980`: Added new :class:`.PointND` and :class:`.PointND_Array` type aliases * :pr:`3988`: Added type hints to :mod:`manim.cli` module * :pr:`3999`: Add type annotations to :mod:`manim.utils` * :pr:`4006`: Stopped ignoring :mod:`manim.plugins` errors in ``mypy.ini`` * :pr:`4007`: Added typings to :mod:`manim.__main__` * :pr:`4027`: Rename ``InternalPoint3D`` to :class:`~.typing.Point3D`, ``Point3D`` to :class:`~.Point3DLike` and other point-related type aliases * :pr:`4038`: Fixed type hint of :meth:`.Scene.play` to allow :attr:`.Mobject.animate` Internal Improvements and Automation ------------------------------------ * :pr:`3737`: Fixed action for building downloadable documentation * :pr:`3761`: Use ``--py39-plus`` in pre-commit * :pr:`3777`: Add pyproject for ruff formatting * :pr:`3779`: Switch pre-commit to use ``ruff`` for linting * :pr:`3795`: Replace Pyupgrade with Ruff rule * :pr:`3812`: Fix MacOS LaTeX CI * :pr:`3853`: Change from tempconfig to a config fixture in tests * :pr:`3858`: Update docker to use ENV x=y instead of ENV x y * :pr:`3872`: Use ruff for pytest style * :pr:`3873`: Use ruff instead of flake8-simplify * :pr:`3877`: Fix pre-commit linting * :pr:`3780`: Add Ruff Lint * :pr:`3781`: Ignore Ruff format in git blame * :pr:`3881`: Standardize docstrings with ruff pydocstyle rules * :pr:`3882`: Change flake8-comprehensions and flake8-bugbear to ruff * :pr:`3887`: Fix typo from HSV PR * :pr:`3923`: Use Ruff pygrep rules * :pr:`3925`: Use Github Markdown on README * :pr:`3955`: Use ``subprocess`` instead of ``os.system``. * :pr:`3956`: Set AAC codec for audio in mp4 files, add transcoding utility * :pr:`4069`: Include Noto fonts in Docker image * :pr:`4102`: Remove PT004 from Ruff ignore rules Dependencies ------------ * :pr:`3739`: [pre-commit.ci] pre-commit autoupdate * :pr:`3746`: Bump tqdm from 4.66.1 to 4.66.3 * :pr:`3750`: Bump jinja2 from 3.1.3 to 3.1.4 * :pr:`3776`: Bump requests from 2.31.0 to 2.32.0 * :pr:`3784`: [pre-commit.ci] pre-commit autoupdate * :pr:`3794`: [pre-commit.ci] pre-commit autoupdate * :pr:`3796`: Bump tornado from 6.4 to 6.4.1 * :pr:`3801`: [pre-commit.ci] pre-commit autoupdate * :pr:`3809`: [pre-commit.ci] pre-commit autoupdate * :pr:`3810`: Bump urllib3 from 2.2.1 to 2.2.2 * :pr:`3823`: [pre-commit.ci] pre-commit autoupdate * :pr:`3827`: Fix docker build * :pr:`3834`: [pre-commit.ci] pre-commit autoupdate * :pr:`3835`: Bump docker/build-push-action from 5 to 6 * :pr:`3841`: Bump certifi from 2024.2.2 to 2024.7.4 * :pr:`3844`: [pre-commit.ci] pre-commit autoupdate * :pr:`3847`: Bump zipp from 3.18.2 to 3.19.1 * :pr:`3865`: [pre-commit.ci] pre-commit autoupdate * :pr:`3880`: [pre-commit.ci] pre-commit autoupdate * :pr:`3889`: [pre-commit.ci] pre-commit autoupdate * :pr:`3895`: Lock `poetry.lock` * :pr:`3896`: [pre-commit.ci] pre-commit autoupdate * :pr:`3904`: [pre-commit.ci] pre-commit autoupdate * :pr:`3911`: [pre-commit.ci] pre-commit autoupdate * :pr:`3918`: [pre-commit.ci] pre-commit autoupdate * :pr:`3929`: [pre-commit.ci] pre-commit autoupdate * :pr:`3931`: Bump cryptography from 43.0.0 to 43.0.1 * :pr:`3987`: [pre-commit.ci] pre-commit autoupdate * :pr:`4023`: Bump tornado from 6.4.1 to 6.4.2 * :pr:`4035`: [pre-commit.ci] pre-commit autoupdate * :pr:`4037`: Cap ``pyav`` version ================================================ FILE: docs/source/changelog/0.19.1-changelog.md ================================================ --- short-title: v0.19.1 description: Changelog for Manim v0.19.1 --- # v0.19.1 Date : December 01, 2025 ## What's Changed ### New Features * Introduce seed in `random_color` method to produce colors deterministically by {user}`ishu9bansal` in {pr}`4265` * Add support for arithmetic operators `//`, `%`, `*`, `**` and `/` on `ValueTracker` by {user}`fmuenkel` in {pr}`4351` * Add `TangentialArc` mobject by {user}`Brainsucker92` in {pr}`4469` ### Fixed Bugs and Enhancements * Fix environment formatting for Tex() mobject by {user}`fmuenkel` in {pr}`4159` * Improved consistency of rate_function implementations by {user}`BenKirkels` in {pr}`4144` * Make new `Code` mobject compatible with OpenGL renderer by {user}`behackl` in {pr}`4164` * Fix HSL color ordering in ManimColor by {user}`thehugwizard` in {pr}`4202` * Fix return type of `Polygram.get_vertex_groups()` and rename variables in `.round_corners()` by {user}`chopan050` in {pr}`4063` * Improve `Mobject.align_data` docstring by {user}`irvanalhaq9` in {pr}`4152` * Fix :meth:`VMobject.pointwise_become_partial` failing when `vmobject` is `self` by {user}`irvanalhaq9` in {pr}`4193` * Fix `add_points_as_corners` not connecting single point to existing path by {user}`irvanalhaq9` in {pr}`4219` * Complete typing for logger_utils.py by {user}`fmuenkel` in {pr}`4134` * Fix(graph): Allow any Line subclass as edge_type in Graph/DiGraph by {user}`Akshat-Mishra-py` in {pr}`4251` * Replace exceptions, remove unused parameters, and fix type hints in `Animation`, `ShowPartial`, `Create`, `ShowPassingFlash`, and `DrawBorderThenFill` by {user}`irvanalhaq9` in {pr}`4214` * Fix: `Axes` submobject colors are not being set properly by {user}`ishu9bansal` in {pr}`4291` * Refactor `Rotating` and add docstrings to `Mobject.rotate()` and `Rotating` by {user}`irvanalhaq9` in {pr}`4147` * Fix default config of `manim init project` to use correct `pixel_height` and `pixel_width` by {user}`StevenH34` in {pr}`4213` * Handle opacity and transparent images by {user}`henrikmidtiby` in {pr}`4313` * Gracefully fall back when version metadata is missing by {user}`mohiuddin-khan-shiam` in {pr}`4324` * Fix for issue 4255 - Do not clear points when the number of curves is zero by {user}`henrikmidtiby` in {pr}`4320` * Use utf-8 encoding to read generated .tex files. by {user}`OliverStrait` in {pr}`4334` * Add zero to vmobject points to remove negative zeros in `get_mobject_key` by {user}`elshorbagyx` in {pr}`4332` * Ensure `stroke_width` attribute of `SVGMobject` is not set to `None` by {user}`henrikmidtiby` in {pr}`4319` * Fix `Prism` incorrectly rendering with `dimensions=[2, 2, 2]` in OpenGL by {user}`ra1u` in {pr}`4003` * Fix `BraceLabel.change_label()` and document `BraceText` by {user}`henrikmidtiby` in {pr}`4347` * Include `Text.gradient` in hash to properly regenerate `Text` when its gradient changes by {user}`AbhilashaTandon` in {pr}`4099` * Fixed surface animations in OpenGL by {user}`nubDotDev` in {pr}`4286` * Add type hints and support for arithmetic operators `+` and `-` on `ValueTracker` by {user}`fmuenkel` in {pr}`4129` * Fix duplicate references in `Scene.mobjects` after `ReplacementTransform` with existing target mobject by {user}`irvanalhaq9` in {pr}`4242` * Optimize `always_redraw()` by reducing `Mobject` copying in `Mobject.become()` by {user}`chopan050` in {pr}`4357` * Enhance `manim cfg show` output and add info-level logging for config files read by {user}`xnov18` in {pr}`4375` * Let `Cube` use Bevel type line joints by {user}`nubDotDev` in {pr}`4361` * Properly define `init_points` methods for use in OpenGL instead of defining `init_points = generate_points` by {user}`chopan050` in {pr}`4360` * Allow passing a tuple to `buff` in `SurroundingRectangle` to specify buffer in x and y direction independently by {user}`nubDotDev` in {pr}`4390` * Rewrite `color_gradient` to always return a list of ManimColors by {user}`henrikmidtiby` in {pr}`4380` * Ensure leading whitespace does not change line height for lines in CodeMobject by {user}`behackl` in {pr}`4392` * Simplify the function `remove_invisible_chars` in `text_mobject.py` by {user}`henrikmidtiby` in {pr}`4394` * Fix some config options specified via `--config_file` not being respected properly by {user}`behackl` in {pr}`4401` * Fix: Correct resolution tuple order to (height, width) by {user}`Nikhil172913832` in {pr}`4440` * Ensure that start and end points are stored as float values in Line3D by {user}`SirJamesClarkMaxwell` in {pr}`4080` * OpenGL: Fix iterated nesting in `DecimalNumber.set_value` by {user}`henrikmidtiby` in {pr}`4373` * Update default resolution in CLI to match Manim’s 1920x1080 default settings by {user}`SASHAKT1290` in {pr}`4452` * Better parsing of color styles in CodeMobject by {user}`SirJamesClarkMaxwell` in {pr}`4454` * Allow selection of all scenes to render using '*' by {user}`NightyStudios` in {pr}`4470` * Prevent mutation of `about_point` in `apply_points_function_about_point` by {user}`Morkunas` in {pr}`4478` * Fix behavior of `Mobject.suspend_updating`: when only suspending parent mobject, let children continue updating by {user}`behackl` in {pr}`4402` * Allow passing a `buff` to `LabeledDot` by {user}`nubDotDev` in {pr}`4403` * Pass ndarrays to `mapbox_earcut.triangulate_float32()` to fix `TypeError` in `mapbox_earcut==2.0.0` by {user}`GuiCT` in {pr}`4479` * Fix duplicated arrow tips in DashedVMobject (issue #3220) by {user}`jakekinchen` in {pr}`4484` ### Documentation * Add docstring to :meth:`.Mobject.get_family` by {user}`irvanalhaq9` in {pr}`4127` * Fix link formatting and clarify the distinction between Manim versions in index.rst by {user}`irvanalhaq9` in {pr}`4131` * Add instructions for installing system utilities `cairo` and `pkg-config` via Homebrew on MacOS by {user}`behackl` in {pr}`4146` * Add missing line break in Code of Conduct's conflict of interest policy by {user}`Hasan-Mesbaul-Ali-Taher` in {pr}`4185` * Fix links to Pango website by {user}`ragibson` in {pr}`4217` * Replace poetry with uv in the README by {user}`xinoehp512` in {pr}`4226` * Improve docstring for `interpolate` method in `Mobject` class by {user}`irvanalhaq9` in {pr}`4149` * Add docstrings to `Line` and remove `None` handling for `path_arc` parameter by {user}`irvanalhaq9` in {pr}`4223` * Add docstring to :meth:`Mobject.family_members_with_points` by {user}`irvanalhaq9` in {pr}`4128` * Update incorrect docstring for :attr:`ManimConfig.gui_location` property by {user}`SAYAN02-DEV` in {pr}`4254` * Fix formatting of color space documentation by {user}`behackl` in {pr}`4274` * Enhance and Paraphrase Description of ManimCE in README.md by {user}`irvanalhaq9` in {pr}`4141` * docs: add explanation about the rate_func in the custom animation by {user}`pedropxoto` in {pr}`4278` * Fixed artifact in docstring of Animation by {user}`barollet` in {pr}`4283` * Rename update function `dot_position` to `update_label` in `.add_updater` example by {user}`irvanalhaq9` in {pr}`4196` * Fix Microsoft typo in `TexFontTemplateLibrary` scene in `example_scenes/advanced_tex_fonts.py` by {user}`alterdim` in {pr}`4305` * Improved readability, grammar, as well as added docstrings for consistency by {user}`NASAnerd05` in {pr}`4267` * Add docstrings for `ChangingDecimal` and `ChangeDecimalToValue` by {user}`haveheartt` in {pr}`4346` * Fix Sphinx exceptions when trying to build documentation via latex / as pdf by {user}`behackl` in {pr}`4370` * Added license information to documentation landing page by {user}`Nikil-D-Gr8` in {pr}`3986` * Set the default Python version to 3.13 in the uv installation guide by {user}`henrikmidtiby` in {pr}`4480` ### Maintenance and Testing * Change project management tool from poetry to uv by {user}`behackl` in {pr}`4138` * Re-add ffmpeg as dependency within Docker image by {user}`behackl` in {pr}`4150` * Add tests for Matrix, DecimalMatrix, IntegerMatrix by {user}`pdrzan` in {pr}`4279` * Add tests for polylabel utility by {user}`giolucasd` in {pr}`4269` * Add support for `pycodestyle W` rule in Ruff by {user}`KaiqueDultra` in {pr}`4276` * Fix files with few MyPy typing errors by {user}`henrikmidtiby` in {pr}`4263` * Explicitly mention all files that mypy should ignore in the `mypy.ini` configuration file by {user}`henrikmidtiby` in {pr}`4306` * Remove dead code from `scene.py` and `vector_space_scene.py` by {user}`henrikmidtiby` in {pr}`4310` * Add type annotations to `scene.py` and `vector_space_scene.py` by {user}`henrikmidtiby` in {pr}`4260` * Replace setup-texlive-action in CI workflow by {user}`behackl` in {pr}`4326` * Adding type annotations to polyhedra.py and matrix.py by {user}`henrikmidtiby` in {pr}`4322` * Handling typing errors in text/numbers.py by {user}`henrikmidtiby` in {pr}`4317` * Move `configure_pygui` into a `Scene` method and remove `manim.gui` by {user}`chopan050` in {pr}`4314` * Add typing annotations to svg_mobject.py by {user}`henrikmidtiby` in {pr}`4318` * Add type annotations to `mobject/svg/brace.py` and default to `label_constructor=Text` in `BraceText` by {user}`henrikmidtiby` in {pr}`4309` * Add classes `MethodWithArgs`, `SceneInteractContinue` and `SceneInteractRerun` inside new module `manim.data_structures` by {user}`chopan050` in {pr}`4315` * Fix typo in import of OpenGLCamera in `utils/hashing.py` by {user}`fmuenkel` in {pr}`4352` * Add type annotations to `manim/renderer/shader.py` by {user}`henrikmidtiby` in {pr}`4350` * Add type annotations to `tex_mobject.py` by {user}`henrikmidtiby` in {pr}`4355` * Add type annotations to `three_d_camera.py` by {user}`henrikmidtiby` in {pr}`4356` * Revert change of default value for tex_environment by {user}`henrikmidtiby` in {pr}`4358` * Add type hints to `scene_file_writer.py`, `section.py`, and `zoomed_scene.py` by {user}`fmuenkel` in {pr}`4133` * Add type annotations for most of `camera` and `mobject.graphing` by {user}`henrikmidtiby` in {pr}`4125` * Add `VectorNDLike` type aliases by {user}`chopan050` in {pr}`4068` * Add type annotations to `dot_cloud.py`, `vectorized_mobject_rendering.py` and `opengl_three_dimensions.py` by {user}`henrikmidtiby` in {pr}`4359` * Add type annotations to `indication.py` by {user}`henrikmidtiby` in {pr}`4367` * Add type annotations to `composition.py` by {user}`henrikmidtiby` in {pr}`4366` * Add type annotations to `growing.py` by {user}`henrikmidtiby` in {pr}`4368` * Add type annotations to `movement.py` by {user}`henrikmidtiby` in {pr}`4371` * Exclude check for cyclic imports by CodeQL by {user}`behackl` in {pr}`4384` * Refactor imports from `collections.abc`, `typing` and `typing_extensions` for Python 3.9 by {user}`chopan050` in {pr}`4353` * Add type annotations to `opengl_renderer_window.py` by {user}`fmuenkel` in {pr}`4363` * Rename `SceneFileWriter.save_final_image()` to `save_image()` by {user}`fmuenkel` in {pr}`4378` * Add type annotations to `text_mobject.py` by {user}`henrikmidtiby` in {pr}`4381` * Rename types like `RGBA_Array_Float` to `FloatRGBA` and add types like `FloatRGBA_Array` by {user}`chopan050` in {pr}`4386` * Add type annotations to `opengl_geometry.py` by {user}`henrikmidtiby` in {pr}`4396` * Add type annotations to `moving_camera.py` by {user}`henrikmidtiby` in {pr}`4397` * Add type annotations to `opengl_mobject.py` by {user}`RBerga06` in {pr}`4398` * Fix failing pre-commit tests by {user}`cclauss` in {pr}`4434` * Add type annotations to `cairo_renderer.py` by {user}`fmuenkel` in {pr}`4393` * Fix type errors and add typings for `Mobject.apply_function()`, its derivatives, and other utility functions by {user}`godalming123` in {pr}`4228` * Bump macOS image from deprecated macos-13 to macos-15-intel by {user}`chopan050` in {pr}`4481` * Prepare new release `v0.19.1` and bump minimum required Python version to 3.10 by {user}`behackl` in {pr}`4490` ### Dependency Version Changes * Bump typing extensions minimum version by {user}`JasonGrace2282` in {pr}`4121` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4122` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4140` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4148` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4181` * Bump astral-sh/setup-uv from 5 to 6 by {user}`dependabot`[bot] in {pr}`4234` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4204` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4391` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4405` * Bump actions/setup-python from 5 to 6 by {user}`dependabot`[bot] in {pr}`4433` * Bump actions/checkout from 4 to 5 by {user}`dependabot`[bot] in {pr}`4418` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4409` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4460` * [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4467` * Bump github/codeql-action from 3 to 4 by {user}`dependabot`[bot] in {pr}`4466` * Bump astral-sh/setup-uv from 6 to 7 by {user}`dependabot`[bot] in {pr}`4465` * Bump actions/upload-artifact from 4 to 5 by {user}`dependabot`[bot] in {pr}`4464` ## New Contributors * {user}`BenKirkels` made their first contribution in {pr}`4144` * {user}`Hasan-Mesbaul-Ali-Taher` made their first contribution in {pr}`4185` * {user}`ragibson` made their first contribution in {pr}`4217` * {user}`thehugwizard` made their first contribution in {pr}`4202` * {user}`xinoehp512` made their first contribution in {pr}`4226` * {user}`SAYAN02-DEV` made their first contribution in {pr}`4254` * {user}`Akshat-Mishra-py` made their first contribution in {pr}`4251` * {user}`pdrzan` made their first contribution in {pr}`4279` * {user}`pedropxoto` made their first contribution in {pr}`4278` * {user}`giolucasd` made their first contribution in {pr}`4269` * {user}`KaiqueDultra` made their first contribution in {pr}`4276` * {user}`ishu9bansal` made their first contribution in {pr}`4291` * {user}`StevenH34` made their first contribution in {pr}`4213` * {user}`alterdim` made their first contribution in {pr}`4305` * {user}`mohiuddin-khan-shiam` made their first contribution in {pr}`4324` * {user}`elshorbagyx` made their first contribution in {pr}`4332` * {user}`NASAnerd05` made their first contribution in {pr}`4267` * {user}`ra1u` made their first contribution in {pr}`4003` * {user}`AbhilashaTandon` made their first contribution in {pr}`4099` * {user}`nubDotDev` made their first contribution in {pr}`4286` * {user}`haveheartt` made their first contribution in {pr}`4346` * {user}`xnov18` made their first contribution in {pr}`4375` * {user}`Nikil-D-Gr8` made their first contribution in {pr}`3986` * {user}`RBerga06` made their first contribution in {pr}`4398` * {user}`Nikhil172913832` made their first contribution in {pr}`4440` * {user}`SASHAKT1290` made their first contribution in {pr}`4452` * {user}`Brainsucker92` made their first contribution in {pr}`4469` * {user}`NightyStudios` made their first contribution in {pr}`4470` * {user}`Morkunas` made their first contribution in {pr}`4478` * {user}`GuiCT` made their first contribution in {pr}`4479` * {user}`godalming123` made their first contribution in {pr}`4228` * {user}`jakekinchen` made their first contribution in {pr}`4484` **Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.19.0...v0.19.1 ================================================ FILE: docs/source/changelog/0.19.2-changelog.md ================================================ --- short-title: v0.19.2 description: Changelog for Manim v0.19.2 --- # v0.19.2 Date : January 17, 2026 ## What's Changed ### Highlights 🌟 * Add support for Python 3.14, bump minimum Python to 3.11 and av to 14.0.1 by {user}`behackl` in {pr}`4385` ### Bug Fixes 🐛 * Fix argument passed to `get_hash_from_play_call` in hashing by {user}`judenimo` in {pr}`4524` * Fix incorrect `Circle.point_at_angle` calculation by {user}`Swarnlataaa` in {pr}`4438` ### Testing 🧪 * Test on Apple Silicon ARM64 by {user}`cclauss` in {pr}`4496` ### Code Quality & Refactoring 🧹 * Add ruff rules PERF for performance by {user}`cclauss` in {pr}`4492` * Remove deprecation warning from pytest "np.trapz" -> "np.trapezoid" by {user}`henrikmidtiby` in {pr}`4513` * Bump Python target versions of both mypy and ruff by {user}`behackl` in {pr}`4520` * Replace legacy numpy usage -- ruff rule NPY002 by {user}`cclauss` in {pr}`4516` * Add `.github/release.yml` for improved classifications in automatically generated changelogs by {user}`behackl` in {pr}`4526` * Check and bump lower version requirements for dependencies by {user}`henrikmidtiby` in {pr}`4529` ### Type Hints 📝 * Add type annotations to `three_dimensions.py` by {user}`henrikmidtiby` in {pr}`4497` ### Other Changes * Prepare new release `v0.19.2` by {user}`behackl` in {pr}`4528` ## New Contributors * {user}`judenimo` made their first contribution in {pr}`4524` * {user}`Swarnlataaa` made their first contribution in {pr}`4438` **Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.19.1...v0.19.2 ================================================ FILE: docs/source/changelog/0.2.0-changelog.rst ================================================ ****** v0.2.0 ****** :Date: January 1, 2021 The changes since Manim Community release v0.1.1 are listed below. Breaking Changes ================ - Remove all CONFIG dictionaries and all calls to ``digest_config`` and allow passing options directly to the constructor of the corresponding classes (:pr:`783`). Practically, this means that old constructions using ``CONFIG`` like:: class SomeMobject(Thing): CONFIG = { "my_awesome_property": 42 } where corresponding objects were then instantiated as ``my_mobject = SomeMobject()`` should now be created simply using ``my_mobject = SomeMobject(my_awesome_property=42)``. - Remove old syntax for animating mobject methods by passing the methods and arguments to ``self.play``, and use a new syntax featuring the ``animate`` property (:pr:`881`). For example: the old-style ``play`` call :: self.play(my_square.shift, LEFT) should be replaced with the new following call using the ``animate`` property:: self.play(my_square.animate.shift(LEFT)) New Features ============ - Added creation animation for :class:`~.ManimBanner` (:pr:`814`) - Added some documentation to :meth:`~.Scene.construct` (:pr:`753`) - Added a black and white monochromatic version of Manim's logo (:pr:`826`) - Added support for a plugin system (``manim plugin`` subcommand + documentation) (:pr:`784`) - Implemented ``__add__``, ``__iadd__``, ``__sub__``, and ``__isub__`` for :class:`~.Mobject` (allowing for notation like ``some_vgroup + some_mobject``) (:pr:`790`) - Added type hints to several files in the library (:pr:`835`) - Added some examples to :mod:`~.animation.creation` (:pr:`820`) - Added some examples to :class:`~.DashedLine` and :class:`~.CurvesAsSubmobjects` (:pr:`833`) - Added new implementation for text rendered with Pango, :class:`~.MarkupText`, which can be formatted with an HTML-like syntax (:pr:`855`) - Added Fading in and out examples and deprecation of ``FadeInFromDown`` and ``FadeOutAndShiftDown`` (:pr:`827`) - Added example for :class:`~.MoveAlongPath` to the docs (:pr:`873`) - Added ambient rotate for other angles - theta, phi, gamma (:pr:`660`) - Use custom bindings for Pango (:pr:`878`) - Added :class:`~.Graph`, a basic implementation for (graph theory) graphs (:pr:`861`) - Allow for chaining methods when using the new ``.animate`` syntax in :meth:`~.Scene.play` (:pr:`889`) Bugfixes ======== - Fix doctests in .rst files (:pr:`797`) - Fix failing doctest after adding ``manim plugin`` subcommand (:pr:`831`) - Normalize the direction vector in :meth:`~.mobject_update_utils.always_shift` (:pr:`839`) - Add ``disable_ligatures`` to :class:`~.Text` (via :pr:`804`) - Make scene caching aware of order of Mobjects (:pr:`845`) - Fix :class:`~.CairoText` to work with new config structure (:pr:`858`) - Added missing argument to classes inheriting from :class:`~.Matrix` (:pr:`859`) - Fixed: ``z_index`` of mobjects contained in others as submobjects is now properly respected (:pr:`872`) - Let :meth:`~.ParametricSurface.set_fill_by_checkboard` return the modified surface to allow method chaining (:pr:`883`) - Mobjects added during an updater are added to ``Scene.moving_mobjects`` (:pr:`838`) - Pass background color to JS renderer (:pr:`876`) - Small fixes to docstrings. Tiny cleanups. Remove ``digest_mobject_attrs``. (:pr:`834`) - Added closed shape detection in :class:`~.DashedVMobject` in order to achieve an even dash pattern (:pr:`884`) - Fix Spelling in docstrings and variables across the library (:pr:`890`) Other changes ============= - Change library name to manim (:pr:`811`) - Docker: use local files when building an image (:pr:`803`) - Let ffmpeg render partial movie files directly instead of temp files (:pr:`817`) - ``manimce`` to ``manim`` & capitalizing Manim in readme (:pr:`794`) - Added flowchart for different docstring categories (:pr:`828`) - Improve example in module docstring of :mod:`~.animation.creation` + explicitly document buff parameter in :meth:`~.Mobject.arrange` (:pr:`825`) - Disable CI pipeline for Python 3.6 (:pr:`823`) - Update URLs in docs (:pr:`832`) - Move upcoming changelog to GitHub-wiki (:pr:`822`) - Change badges in readme (:pr:`854`) - Exclude generated gRPC files from source control (:pr:`868`) - Added linguist-generated attribute to ``.gitattributes`` (:pr:`877`) - Cleanup: removed inheritance from ``object`` for some classes, refactor some imports (:pr:`795`) - Change several ``str.format()`` to ``f``-strings (:pr:`867`) - Update javascript renderer (:pr:`830`) - Bump version number to 0.2.0, update changelog (:pr:`894`) ================================================ FILE: docs/source/changelog/0.20.0-changelog.md ================================================ --- short-title: v0.20.0 description: Changelog for v0.20.0 --- # v0.20.0 Date : February 20, 2026 ## What's Changed ### Breaking Changes 🚨 * Fix `ImageMobject` 3D rotation/flipping and remove resampling algorithms `lanczos` (`antialias`), `box` and `hamming` by {user}`chopan050` in {pr}`4266` * Fix `YELLOW_C` and add `PURE_CYAN`, `PURE_MAGENTA` and `PURE_YELLOW` by {user}`chopan050` in {pr}`4562` ### Highlights 🌟 * Rewrite MathTex to make it more robust regarding splitting by {user}`henrikmidtiby` in {pr}`4515` The MathTex implementation has been updated to make it more robust and fix a number of issues. A beneficial side effect is that named groups in svg files can now be accessed through SVGMobject. * Add new Animation Builder `Mobject.always` by {user}`JasonGrace2282` in {pr}`4594` This new feature is a convenience wrapper around `add_updater` that allows adding updaters to a mobject in an intuitive and easy-to-read way. Example usage in a scene: ```python d = Dot() s = Square() d.always.next_to(s, UP) self.add(s, d) self.play(s.animate.to_edge(LEFT)) ``` ### New Features ✨ * Add a `seed` config option + `--seed` CLI option for reproducible randomness in rendered scenes by {user}`arnaud-ma` in {pr}`4532` ### Enhancements 🚀 * Enable `strict=True` for `zip()` where safe by {user}`Oll-iver` in {pr}`4547` ### Bug Fixes 🐛 * using `color` instead of `fill_color` with MathTeX for node labels by {user}`Schefflera-Arboricola` in {pr}`4501` * fix: infinite recursion caused by accessing color of a highlighted Ta… by {user}`BHearron` in {pr}`4435` * Prevent potential `UnboundLocalError` in `PolarPlane` by {user}`RinZ27` in {pr}`4557` * Fixed division by 0 in `turn_animation_into_updater` by {user}`SoldierSacha` in {pr}`4567` * Fix TOCTOU Race Conditions when creating directories by {user}`SoldierSacha` in {pr}`4587` * Resolve more race conditions potentially happening during directory creation by {user}`SoldierSacha` in {pr}`4589` * Fix `c2p`/`coords_to_point` method call with single flat list or 1D array input by {user}`danielalanbates` in {pr}`4596` ### Documentation 📚 * Enable rendered documentation of `RandomColorGenerator` by {user}`arnaud-ma` in {pr}`4533` * Remove pin to Python 3.13 in installation docs by {user}`chopan050` in {pr}`4534` * Fix broken aquabeam OpenGL link using Wayback Machine by {user}`behackl` in {pr}`4545` * Add type annotations and docstrings in `opengl_renderer.py` by {user}`arnaud-ma` in {pr}`4537` * docs: improve `TransformFromCopy` docstring by {user}`GoThrones` in {pr}`4597` ### Infrastructure & Build 🔨 * Install missing dependencies in release pipeline by {user}`behackl` in {pr}`4531` ### Code Quality & Refactoring 🧹 * Rework and consolidate release changelog script, add previously skipped changelog entries by {user}`behackl` in {pr}`4568` * Remove `__future__.annotations` from required imports by {user}`JasonGrace2282` in {pr}`4571` * Cleaned up `mypy.ini` by {user}`henrikmidtiby` in {pr}`4584` * Add `py.typed` to declare manim as having type hints by {user}`Timmmm` in {pr}`4553` * Fix assertion in `ImageMobjectFromCamera.interpolate_color()` by {user}`chopan050` in {pr}`4593` * Reduce dependency on scipy - replace `scipy.special.comb` with `math.comb` by {user}`fmuenkel` in {pr}`4598` ### Type Hints 📝 * Add type annotations to `rotation.py` by {user}`fmuenkel` in {pr}`4535` * Add type annotations to `opengl_compatibility.py` by {user}`fmuenkel` in {pr}`4585` * Add type annotations to `image_mobject.py` by {user}`henrikmidtiby` in {pr}`4458` * Add type annotations to `opengl_image_mobject.py` by {user}`fmuenkel` in {pr}`4536` * Add type annotations to `point_cloud_mobject.py` by {user}`fmuenkel` in {pr}`4586` ## New Contributors * {user}`arnaud-ma` made their first contribution in {pr}`4533` * {user}`Schefflera-Arboricola` made their first contribution in {pr}`4501` * {user}`BHearron` made their first contribution in {pr}`4435` * {user}`RinZ27` made their first contribution in {pr}`4557` * {user}`SoldierSacha` made their first contribution in {pr}`4567` * {user}`Oll-iver` made their first contribution in {pr}`4547` * {user}`GoThrones` made their first contribution in {pr}`4597` * {user}`danielalanbates` made their first contribution in {pr}`4596` **Full Changelog**: [Compare view](https://github.com/ManimCommunity/manim/compare/v0.19.2...v0.20.0) ================================================ FILE: docs/source/changelog/0.20.1-changelog.md ================================================ --- short-title: v0.20.1 description: Changelog for v0.20.1 --- # v0.20.1 Date : February 27, 2026 ## What's Changed ### Enhancements 🚀 * Cleanup `TipableVMobject`: avoid mutable default and fix `assign_tip_attr` typo by {user}`josiest` in {pr}`4503` * enhancement: optimize Docker image build and runtime footprint by {user}`behackl` in {pr}`4604` ### Bug Fixes 🐛 * fix: MathTex double-brace splitting no longer fires on natural LaTeX `}}` by {user}`behackl` in {pr}`4602` * Fix creation or animation of a zero-length `DashedLine` by {user}`SORVER` in {pr}`4606` * Fix moving-object detection for nested AnimationGroups with z-indexed mobjects by {user}`Merzlikin-Matvey` in {pr}`4389` * Fix unintended propagation of `kwargs` in `LaggedStartMap` by {user}`irvanalhaq9` in {pr}`4613` ### Documentation 📚 * Documentation: manual installation of manim as a local package by {user}`u7920349` in {pr}`4456` * Add alt text to all images in `README.md` by {user}`VerisimilitudeX` in {pr}`4064` ### Code Quality & Refactoring 🧹 * Fix publish release workflow by {user}`behackl` in {pr}`4600` * Silence pydub ffmpeg/avconv import warning when ffmpeg CLI is absent by {user}`behackl` in {pr}`4603` ### Type Hints 📝 * Add type annotations to `manim/_config/utils.py` by {user}`henrikmidtiby` in {pr}`4230` ## New Contributors * {user}`SORVER` made their first contribution in {pr}`4606` * {user}`josiest` made their first contribution in {pr}`4503` * {user}`u7920349` made their first contribution in {pr}`4456` * {user}`Merzlikin-Matvey` made their first contribution in {pr}`4389` * {user}`VerisimilitudeX` made their first contribution in {pr}`4064` **Full Changelog**: [Compare view](https://github.com/ManimCommunity/manim/compare/v0.20.0...v0.20.1) ================================================ FILE: docs/source/changelog/0.3.0-changelog.rst ================================================ ****** v0.3.0 ****** :Date: February 1, 2021 The changes since Manim Community release v0.2.0 are listed below. New Features ============ - :pr:`945`: :meth:`~.Graph.change_layout` method for :class:`~.Graph` mobject - :pr:`943`: IPython %%manim magic - :pr:`970`: Added ``--version`` command line flag - :pr:`948`: Allow passing a code string to :class:`~.Code` - :pr:`917`: Allow overriding new-style method animations - :pr:`756`: Allow setting frame_height and frame_width via config file - :pr:`939`: Added custom font files support - :pr:`892`: Added ManimCommunity colors - :pr:`922`: Tree layout for Graph mobject - :pr:`935`: Added code of conduct - :pr:`916`: Multi-column layout for partite graphs - :pr:`742`: Units: Pixels, Munits, Percent in :mod:`~.utils.unit` - :pr:`893`: Convenience method :meth:`~.Graph.from_networkx` for creating a graph from a networkx graph Bugfixes and Enhancements ========================= - :pr:`988`: Fix Windows CI pipeline by adding missing LaTeX package - :pr:`961`: Added typings and docs for vectorized mobjects and bezier related functions - :pr:`977`: JupyterLab docker image and documentation for manim and IPython - :pr:`985`: Fix variable name for webgl renderer - :pr:`954`: Fix edges lagging behind vertices in animations of graphs - :pr:`980`: Allow usage of custom Pygments styles in Code - :pr:`952`: Allow passing tween information to the WebGL frontend - :pr:`978`: Fix ``possible_paths`` not printing in ``code_mobject`` - :pr:`976`: Update ``ManimPango`` - :pr:`967`: Automatically import plugins - :pr:`971`: Make ManimCommunity look consistent - :pr:`957`: Raise ``NotImplementedError`` when trying to chain overridden method animations - :pr:`947`: Several fixes and improvements for :class:`~.PointCloundDot` - :pr:`923`: Documentation: move installation instructions for developers to page for developers - :pr:`964`: Added unit test for :class:`~.NumberLine`'s unit vector - :pr:`960`: Magnitude of :class:`~.NumberLine`'s unit vector should be ``unit_size``, not 1 - :pr:`958`: Fix code formatting in ``utils/debug.py`` - :pr:`953`: Update license year - :pr:`944`: Interpolate stroke opacity in :class:`~.FadeIn` and update ``stroke_opacity`` and ``fill_opacity`` in :meth:`~.VMobject.set_stroke` and :meth:`~.VMobject.set_fill` - :pr:`865`: Rename ``get_submobject_index_labels`` to ``index_labels`` - :pr:`941`: Added keyword arguments ``x_min``, ``x_max``, ``y_min``, ``y_max`` to :class:`~.ThreeDAxes` - :pr:`886`: Let the render progress bar show details about the rendered animation again - :pr:`936`: Fix :class:`~.BulletedList` TeX environment problem and add a typing to ``get_module`` - :pr:`938`: Remove dependency on progressbar - :pr:`937`: Change 'brew cask install' to 'brew install --cask' for CI pipeline - :pr:`933`: Make matrix work with lists again - :pr:`932`: Correctly parse ``log_dir`` option - :pr:`920`: Raise error if markup in :class:`~.MarkupText` is invalid - :pr:`929`: Raise an error if a :class:`~.Matrix` object is created with < 2-dimensional input - :pr:`907`: Make Scene.add_sound work again (when running with ``--disable_caching``) - :pr:`906`: Allow new-style method animation to be used in animation groups - :pr:`908`: Removed deprecated command line arguments from documentation - :pr:`903`: Tiny grammar improvements - :pr:`904`: Added blank line between imports and class example - :pr:`898`: CI: fix publish workflow ================================================ FILE: docs/source/changelog/0.4.0-changelog.rst ================================================ ****** v0.4.0 ****** :Date: March 3, 2021 The changes since Manim Community release v0.3.0 are listed below. Breaking Changes ================ - :pr:`915`: Manim's SVG engine has been reworked and is able to handle a wider variations of SVG files. In particular: fill and stroke properties are now retained from the original files. Breaking change: ``VMobjectFromSVGPathstring`` is deprecated and has been renamed to ``SVGPathMobject``. New Features ============ - :pr:`1026`: Add 3D Mobjects: :class:`~.Cone`, :class:`~.Cylinder`, :class:`~.Line3D`, :class:`~.Arrow3D` and :class:`~.Torus` - :pr:`1047`: Add documentation and examples for :class:`~.Matrix` - :pr:`1044`: ``register_font`` is available for macOS - :pr:`995`: Add generic :func:`~.Mobject.set` method and compatibility layer between properties and ``get_*``/``set_*`` methods Bugfixes and Enhancements ========================= - :pr:`981`: Fixed hot reload functionality for the WebGL renderer on Windows - :pr:`1053`: Repair links to source code in stable version of documentation - :pr:`1067`: Add ManimPango to ReadTheDocs requirements - :pr:`1058`: Replace ```` syntax by Pango's ```` for coloring parts of :class:`~.MarkupText` and allow using colors for underline, overline and strikethrough in MarkupText - :pr:`1063`: Fix documentation related to ``.animate`` - :pr:`1065`: Remove duplicate word 'vector' - :pr:`1060`: Update Linux installation instructions to mention the installation of Pango - :pr:`1050`: Ensure that the user-supplied stroke color and width gets applied to :class:`~.Cross` - :pr:`1059`: More descriptive error when accessing an unhandled mobject attribute - :pr:`1048`: Use absolute path in ``make_and_open_docs.py`` - :pr:`1000`: Remove ``MovingCameraScene.setup`` and ``MovingCameraScene.camera_frame`` - :pr:`1051`: Corrections for setting stroke related attributes on :class:`~.VMobject` - :pr:`1043`: Make :class:`~.CubicBezier` explicitly accept four points - :pr:`1046`: Use any version of ``importlib-metadata`` - :pr:`1030`: Parse ``.log`` file and try to print LaTeX errors if compilation fails - :pr:`1015`: Documentation: Add more explicit instructions related to ``tlmgr`` - :pr:`1028`: Documentation: Update installation guide on mac with Apple Silicon - :pr:`1032`: Remove ``Square.side_length`` property - :pr:`1031`: Fix link to wikipedia vector graphics page - :pr:`1021`: Documentation: Added example to :class:`~.CubicBezier` - :pr:`1017`: Added ``progress_bar`` to ``digest_args`` to fix the ``--progress_bar`` CLI flag - :pr:`1018`: Remove redundancy in :class:`~.FunctionGraph` arguments - :pr:`1024`: Migrate ``width`` / ``height`` / ``depth`` to properties - :pr:`1022`: Fix ``-p`` flag when passing ``-s`` - :pr:`1008`: CI pipeline: fix release asset upload - :pr:`983`: Make sure last frame for animations with updaters is correct - :pr:`984`: Add manim version to CLI output, append version name for generated ``.gif`` and ``.png`` files, add version to metadata of rendered videos, change dark blue terminal text to default green - :pr:`993`: Fix setting Mobject color to a gradient by passing a list of colors in :meth:`~.VMobject.set_color` - :pr:`1003`: Fix animation :class:`~.GrowArrow` - :pr:`1010`: Disable STDIN interaction for ffmpeg concat. - :pr:`969`: Fix the ``--tex_template`` CLI flag - :pr:`989`: Fix the ``manim cfg export`` subcommand - :pr:`1005`: Fix the feature where ``-`` is used as the filename - :pr:`998`: Allow using hexadecimal color codes with 3 characters - :pr:`996`: Changed the message of ``manim --version`` to not include "Edition" ================================================ FILE: docs/source/changelog/0.5.0-changelog.rst ================================================ ****** v0.5.0 ****** :Date: April 02, 2021 Contributors ============ A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Abel Aebker + * Abhijith Muthyala * AntonBallmaier + * Aron * Benjamin Hackl * Bogdan Stăncescu + * Darylgolden * Devin Neal * GameDungeon + * Hugues Devimeux * Jason Villanueva * Kapil Sachdeva * KingWampy * Lionel Ray + * Mark Miller * Mohammad Al-Fetyani + * Naveen M K * Niklas Dewally + * Oliver + * Roopesh + * Seb Pearce + * aebkea + * friedkeenan * hydrobeam + * kolibril13 * sparshg * tfglynn + The patches included in this release have been reviewed by the following contributors. * Abel Aebker * Abhijith Muthyala * Benjamin Hackl * Bogdan Stăncescu * Devin Neal * Hugues Devimeux * Jason Villanueva * Kapil Sachdeva * KingWampy * Leo Torres * Lionel Ray * Mark Miller * Mohammad Al-Fetyani * Naveen M K * Oliver * Ricky Chon * vector67 Pull requests merged ==================== A total of 64 pull requests were merged for this release. Highlights ---------- * :pr:`1075`: Add OpenGL Renderer Adds an OpenGLRenderer, OpenGLCamera, OpenGL-enabled Mobjects, and a ``--use_opengl_renderer`` flag. When this flag is passed, you can pass the ``-p`` flag to preview animations, the ``-w`` flag to generate video, and the ``-q`` flag to specify render quality. If you don't pass either the ``-p`` or the ``-w`` flag, nothing will happen. Scenes rendered with the OpenGL renderer must *only* use OpenGL-enabled Mobjects. Deprecated classes and functions -------------------------------- * :pr:`1124`: Deprecated :class:`ShowCreation` in favor of :class:`Create` 1. Deprecated :class:`ShowCreation` in favor of :class:`Create` across the library with the exception of the `show_creation` boolean variable `vector_space_scene.py` 2. Added a deprecation warning in the original :class:`ShowCreation` class. * :pr:`1110`: Deprecated SmallDot + OpenGLSmallDot `SmallDot` isn't necessary and a deprecation warning will be raised. This will be removed in a future release. New features ------------ * :pr:`1037`: Added new fade and transform animations (:class:`~.TransformMatchingShapes`, :class:`~.TransformMatchingTex`, :class:`~.FadeTransform`) from 3b1b/manim Added new Fade animation: :class:`~FadeOutToPoint` Added :class:`~FadeTransform` and :class:`~FadeTransformPieces` for transforming mobjects and submobjects with a fade Added :class:`~TransformMatchingShapes` and :class:`~TransformMatchingTex` for transforming mobjects and tex that have matching parts * :pr:`1097`: Added 3D Mobject :class:`~.Dot3D` * :pr:`1074`: Added jupyter media_width option to the config * :pr:`1107`: Added :class:`~.Unwrite` animation class to complement :class:`~.Write` Added :class:`Unwrite` which inherits from :class:`~.Write`. It automatically reverses the animation of :class:`~.Write` by passing the reversed rate function, but it also takes an additional boolean parameter `reverse` which, if `False`, renders the animation from left to right (assuming text oriented in the usual way), but if `True`, it renders right to left. * :pr:`1085`: Added :class:`~.Angle` and :class:`~.RightAngle` for intersecting lines :class:`~.Angle` and :class:`~.RightAngle` both take two lines as input. If they intersect, or share a common vertex, an angle is drawn between them. Users can customize the look of the angle and also use a dotted right angle. Enhancements ------------ * :pr:`1144`: Improved quality of GIFs * :pr:`1157`: Refresh triangulation on call to :meth:`~.OpenGLVMobject.apply_points_function` Rotate called apply_points_function, which was previous not subclassed by OpenGLMobject - now it is. Then, the vertex normals can be updated too. Additionally, the old_points matrix would change after rotating, making the old points / new points test irrelevant. This is addressed with a .copy call. * :pr:`1151`: Added parametric function support to :class:`OpenGLSurface` * :pr:`1139`: In-Code `config["preview"]` Support * :pr:`1123`: Added caching, skipping, and user-specified background colors to the OpenGL renderer OpenGL play logic has been improved to support caching and skipping with `-n` argument ( it is now similar to Cairo play logic). A random bug was fixed in OpenGLSurface and OpenGL background color can now be changed via `background_color` argument. * :pr:`1118`: Allow passing animation arguments with .animate syntax Users will now be able to do things like `obj.animate(run_time=2).method(arg)` if they want to specify animation arguments for an individual `.animate` call, and can still not specify any arguments like `obj.animate.method(arg)`. Passing animation arguments is only allowed directly after `.animate` is accessed, if passed elsewhere then a `ValueError` is raised. * :pr:`718`: Rotating the numbers in y axis In Axes, the y axis will be rotated 90deg but the numbers are also rotated and shouldn't be. Fixes this issue. * :pr:`1070`: Raise FileNotFoundError when unable to locate the .cfg file specified via ``--config_file`` Raising the error will stop script execution and let the user know that there are problems with the `--config_file` location instead of reverting back to the default configuration. Fixed bugs ---------- * :pr:`1224`: Fixed :class:`~.ShowIncreasingSubsets`, :class:`~.ShowSubmobjectsOneByOne`, and :class:`~.AddTextLetterByLetter` * :pr:`1201`: Prevent crash on :meth:`~.Scene.embed` for empty scenes * :pr:`1192`: Fixed issue when an animation is cached, manim can't merge the partial movie files. * :pr:`1193`: Fixed using :class:`~.Animation` without a child :class:`~.Mobject` in :class:`~.AnimationGroup` `AnimationGroup` may now take `Animation` objects which do not have a child `Mobject`, such as `Wait`. * :pr:`1170`: Fixed minor SVG parsing bugs * :pr:`1159`: Added support for multiple transforms in the same SVG element * :pr:`1156`: Fixed :class:`~.DrawBorderThenFill` to support OpenGL and improved type hints for some functions Fixed a bug in :class:`~.DrawBorderThenFill` that prevented :class:`~.Write` animations from working with :class:`~.OpenGLVMobjects` and slightly improved type hints for some animation functions to include :class:`~.OpenGLVMobject`. * :pr:`1134`: Fixed the `-a` flag. The ``-a`` / ``--write-all`` flag was broken. When used, it would cause Manim to crash just after beginning to render the second scene. * :pr:`1115`: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support Fixed undefined variables and converted :class:`Mobject` to :class:`OpenGLMobject`. Also, fixed assert statement in :class:`ApplyMethod`. * :pr:`1092`: Refactored coordinate_systems.py, fixed bugs, added :class:`~.NumberPlane` test The default behavior of :meth:`~.Mobject.rotate` is to rotate about the center of :class:`~.Mobject`. :class:`~.NumberLine` is symmetric about the point at the number 0 only when ``|x_min|`` == ``|x_max|``. Ideally, the rotation should coincide with the point at number 0 on the line. Added a regression test and additionally fixed some bugs introduced in :pr:`718`. * :pr:`1078`: Removed stray print statements from `__main__.py` Uses rich's print traceback instead and fixes an issue in printing the version twice when `manim --version` is called. * :pr:`1086`: Fixed broken line spacing in :class:`~.Text` The `line_spacing` kwarg was missing when creating :class:`Text` Mobjects; this adds it. * :pr:`1083`: Corrected the shape of :class:`~.Torus` :class:`Torus` draws a surface with an elliptical cross-section when `minor_radius` is different from 1. This PR ensures the cross-section is always a circle. Documentation-related changes ----------------------------- * :pr:`1217`: Copyedited the document on testing in our documentation * :pr:`1206`: Added Docstrings to :class:`~.Mobject` * :pr:`1218`: Removed BezierSpline from the example gallery * :pr:`1219`: Updated Dockerfile (include dependencies for building documentation), moved documentation to main README * :pr:`1209`: Added :ref_methods: to the manim directive This allows class methods to be linked in the documentation. Checkout the `example references `_ below the code to see how this is used! * :pr:`1204`: Added rotation example to example gallery * :pr:`1137`: Added GitHub Wiki pages on adding testing/documentation to Sphinx Docs * :pr:`1114`: Added examples for :class:`~.Ellipse`, :class:`~.Polygon`, :class:`~.RegularPolygon`, :class:`~.Triangle` and :class:`~.RoundedRectangle` * :pr:`1195`: Removed SmallDot from example * :pr:`1130`: Added pre-commit to run black and flake8, updated contributing documentation accordingly * :pr:`1138`: Moved previous version changelogs to separate files; Added a Script to generate future changelogs This script quickly generates a changelog for whoever is making the release. * :pr:`1190`: Added note in contributing guide to read the latest version of the documentation * :pr:`1188`: Added sounds example to docs * :pr:`1165`: Added documentation for installing Manim on Colab * :pr:`1128`: Added examples for :class:`~.DashedLine`, :class:`~.TangentLine`, :class:`~.Elbow`, :class:`~.Arrow`, :class:`~.Vector`, :class:`~.DoubleArrow` * :pr:`1177`: Replace links to the latest version of the documentation to the stable version * :pr:`1077`: Added details to :func:`~.Mobject.get_critical_point` * :pr:`1154`: Fixed some typing hints. (ints to floats) * :pr:`1036`: Added :class:`~.SurroundingRectangle` to the example gallery * :pr:`1103`: Added documentation and examples for Square, Dot, Circle and Rectangle * :pr:`1101`: Added documentation to :class:`~.Mobject` * :pr:`1088`: Added new svg files to documentation and imports In particular, SVGPathMobject, VMobjectFromPathstring, and the style_utils functions to manim's namespace. * :pr:`1076`: Improve documentation for GraphScene Updated `coords_to_point` and `point_to_coords` under `manim/scene/graph_scene.py` as the dosctring of each function confusingly described the opposite of what it is supposed to do. Changes concerning the testing system ------------------------------------- * :pr:`1160`: Enable CI testing for OpenGL * :pr:`1100`: Rewrote test cases to use sys.executable in the command instead of "python" Tests would fail due to `capture()` not spawning a subshell in the correct environment, so when python was called, the test would be unable to find necessary packages. * :pr:`1079`: Removed the hardcoded value, `manim`, in `test_version.py` Changes to our development infrastructure ----------------------------------------- * :pr:`1213`: Updated TinyTex dependencies * :pr:`1187`: Add CodeCov to Github Workflow * :pr:`1166`: CI: Use poetry's cache dir rather than pip * :pr:`1071`: Enable pytest-cov based code coverage - Include pytest-cov as a python module as part of developer dependencies - In updating poetry to include pytest-cov, manimpango moved from version 0.2.3 to 0.2.4, and libpango1.0-dev needed to be installed in Ubuntu. - Add to the CI workflow (`ci.yml`) to create and upload test coverage. * :pr:`1073`: Removed "one line summary" from PULL_REQUEST_TEMPLATE.md Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1167`: Merge :class:`~.OpenGLMobject` and :class:`~.Mobject` * :pr:`1164`: Fixed single PEP8 style in `cairo_renderer.py` * :pr:`1140`: Flake8 Compat & Code Cleanup * :pr:`1019`: Refactored :meth:`~.Scene.play` - Removed the _**three**_ decorators of :meth:`~.Scene.play`, in particular: caching logic and file writer logic are now included within :meth:`~.Scene.play` (it wasn't possible before, because `scene.wait` and `scene.play` were two different things). - Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame). - Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`. - Now when calling play without animation, it raises `ValueError` instead of just a warning. - Fixed :pr:`874` by modifying `renderer.update_skipping_status` - `renderer` starts the animation with `scene.begin_animations` (`scene.compile_animation_data` used to do this) - The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later. - Added a bunch of cool tests thanks to mocks, and thanks to the new syntax `scene.render` ================================================ FILE: docs/source/changelog/0.6.0-changelog.rst ================================================ ****** v0.6.0 ****** :Date: May 02, 2021 Contributors ============ A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Abel Aebker * Abhijith Muthyala * Adam Ryczkowski + * Alex Lembcke + * Anton Ballmaier * Aron * Benjamin Hackl * Darylgolden * Deniz Hasler + * Devin Neal * Elisha Hollander + * Erik Tastepe + * Jan-Hendrik Müller * Jason Villanueva * Laith Bahodi * Mark Miller * Mohammad Al-Fetyani * Naveen M K * Newell Jensen + * Nidhal Baccouri + * Nikhil Garuda + * Peilonrayz + * Raghav Goel * Ricky Chon + * friedkeenan * kamilczerwinski22 + * sparshg The patches included in this release have been reviewed by the following contributors. * Aathish Sivasubrahmanian * Abel Aebker * Abhijith Muthyala * Adam Ryczkowski * Alex Lembcke * Anton Ballmaier * Aron * Benjamin Hackl * Darylgolden * Deniz Hasler * Devin Neal * Elisha Hollander * GameDungeon * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * KingWampy * Laith Bahodi * Mark Miller * Mohammad Al-Fetyani * Naveen M K * Nidhal Baccouri * Nikhil Garuda * Oliver * Philipp Imhof * Raghav Goel * Ricky Chon * friedkeenan * sparshg Pull requests merged ==================== A total of 112 pull requests were merged for this release. Breaking changes ---------------- * :pr:`1347`: Restructure vector_field module and add documentation :class`~.VectorField` is renamed to :class:`~.ArrowVectorField` and a new class :class:`~.VectorField` is added as a superclass for :class:`~.ArrowVectorField` and :class:`~.StreamLines`. :class:`~.AnimatedStreamLines` is removed. It's functionality is moved to :class:`~.StreamLines`. Added a lot of new options when working with vector fields. :class:`~.ShowPassingFlashWithThinningStrokeWidth` was moved to the indication module. * :pr:`1161`: Upgrades to CoordinateSystem and graphing. Breaking changes were introduced to :class:`~.Axes`, :class:`~.ThreeDAxes`, :class:`~.NumberPlane` and :class:`~.NumberLine` All the above now use lists to construct their ranges as opposed to explicitly defining these values. `x_range` has replaced `x_min`, `x_max` and defining the step is much easier with `x_step` --> ``x_range`` : ``[x_min, x_max, x_step]``. There were also many upgrades to these classes which improve their functionality and appearance. ``NumberLineOld`` was introduced to continue support for :class:`~.GraphScene`, although we are moving away from GraphScene and intend to deprecate it in a future release. * :pr:`1013`: Refactored the Command Line Interface to use Click instead of Argparse This change breaks the CLI API to organize the structure of Manim Community's commands, options, and arguments. To be more in line with POSIX compliant CLI conventions, options for commands are given *BEFORE* their arguments. In Argparse: ``manim basic.py -p -ql`` With Click: ``manim -p -ql basic.py`` Although this is primarily a refactor and most of the common options are still there, some options have been added/removed. Use the ``manim`` command's ``--help`` option, or simply run the command without providing options/arguments to view the help page with the full list of subcommands/options/arguments. - Added a ``--fps``/``--frame_rate`` option which allows for custom fps that don't have to be integer (i.e. 29.97, 23.98, etc.). Users no longer have to specify the FPS from within a config file. Additionally, the ``--webgl_renderer_fps`` option has been removed. Use ``--fps`` or ``--frame_rate`` instead. - Added a ``--renderer`` option which you can use to select your choice of renderer (e.g. ``--renderer=opengl``). There are currently *THREE* renderers to choose from! - Removed the ``--background_color`` option. Reassigned the ``--background_color`` option's shorthand ``-c`` to ``--config_file``. - Removed the ``--leave_progress_bars`` option. Use ``--progress_bars=leave`` instead. - Removed the deprecated render quality flags, in particular: ``-l``, ``-m``, ``-h``, ``-k``. - Removed the ``--sound`` option. It lost support long ago with the removal of SoX. Deprecated classes and functions -------------------------------- * :pr:`1431`: Fix CLI bugs - Fixed conflict with ``-f`` which was previously assigned to both ``--show_in_file_browser`` and ``--format`` by removing ``-f`` from ``--format``. A warning is issued that ``-f`` will soon move to ``--format``. - Added back in flags to render the files as gif/last frame. Deprecated them in favor of ``--format``. - Fixed the broken ``--output_file``/``-o`` option. - Fixed an issue where the ``-qh`` quality option was interpreted as ``-q`` ``-h``, prompting the help page. * :pr:`1354`: Refactored a few functions in space_ops.py, deprecated :func:`~.angle_between` * :pr:`1370`: Remove TexMobject and TextMobject TexMobject and TextMobject have been deprecated for a while, they are now fully removed. Use Tex or MathTex instead. * :pr:`1349`: Removed the deprecated ``SmallDot`` mobject * :pr:`1259`: Removed deprecated CairoText class New features ------------ * :pr:`1386`: Implement utility methods for adding/removing vertices and edges of graphs; allow custom mobjects as vertices * :pr:`1385`: Added :meth:`~.Axes.get_line_graph` for plotting a line graph Added :meth:`~.Axes.get_line_graph` that returns a line graph from lists of points along x, y and z (optional) axes. * :pr:`1381`: Hot reloading for the OpenGL renderer Rerun scene when the input file is modified * :pr:`1383`: Overhaul of the :mod:`~.animation.indication` module interfaces - Added class `Circumscribe` combining functionality of `CircleIndicate`, `AnimationOnSurroundingRectangle`, `ShowPassingFlashAround`, `ShowCreationThenDestructionAround`, `ShowCreationThenFadeAround`, which have all been deprecated. - Changes to `Flash`: `flash_radius` parameter now defines inner radius of the animation. Added new parameter `time_width`. - `ShowCreationThenDestruction` has been deprecated in favor of `ShowPassingFlash` - Changes to `ApplyWave`: New implementation giving more flexibility with new parameters `wave_func`, `time_width` and`ripples` - Renamed `WiggleOutThenIn` to `Wiggle` (`WiggleOutThenIn` has been deprecated) - Added documentation and examples to all the above - Other minor enhancements and bug-fixes * :pr:`1348`: Added :class:`~.Polyhedron`, and platonic solids :class:`~.Tetrahedron`, :class:`~.Octahedron`, :class:`~.Icosahedron` and :class:`~.Dodecahedron` * :pr:`1285`: Add :meth:`~.Scene.interactive_embed` for OpenGL rendering :meth:`~.Scene.interactive_embed` allows interaction with Scene via mouse and keyboard as well as dynamic commands via an iPython terminal. * :pr:`1261`: Render image automatically if no animation is played in a scene - If no animations in scene and asked to preview/render a video, preview/render an image instead of raising a confusing error. * :pr:`1200`: Add text and SVG mobjects to OpenGL Added OpenGL-compatible text and SVG mobjects Enhancements ------------ * :pr:`1398`: Fix and enhance `Mobject.arrange_in_grid` `arrange_in_grid` now actually arranges submobjects in a grid. Added new parameters `buff`, `cell_alignment`, `row_alignments`, `col_alignments`, `row_heights`, `col_widths`, `flow_order`. * :pr:`1407`: Fix bug and rename :meth:`vector_coordinate_label` to :meth:`~.Vector.coordinate_label` and move it to :class:`geometry.py` * :pr:`1380`: Allow image objects as background images * :pr:`1391`: Add `path_arc` support to `.animate` syntax The parameter `path_arc` of :class:`~.Transform` now works with the `.animate` syntax * :pr:`1364`: Added :meth:`~.Mobject.match_points` - Added :func:`~.Mobject.match_points`, which transforms the points, positions and submobjects of a Mobject to match that of the other while keeping style unchanged. * :pr:`1363`: Change of TeX compiler and output file format * :pr:`1359`: Make FILE a required argument * Make `FILE` a required argument, `manim/cli/render/commands.py`:L30 * :pr:`1304`: Improve Tex string splitting at double braces: only split for double brace groups * :pr:`1340`: Add OpenGL support to the new transform animations Made `FadeTransform`, `FadeTransformPieces`, `TransformMatchingShapes` and `TransformMatchingTex` compatible with OpenGL rendering. * :pr:`1343`: Make TexTemplate() simple, but keep Tex()'s default template TexTemplate() now returns a simple tex template. * :pr:`1321`: Add OpenGL support to :class:`~.AnimationGroup` * :pr:`1302`: Raise appropriate errors in :meth:`~.VMobject.point_from_proportion` - Raise an error if the ``alpha`` argument is not between 0 and 1. - Raise an error if the :class:`~.VMobject` has no points. * :pr:`1315`: Fix performance issues with :meth:`~.VMobject.get_arc_length`, stemming from :pr:`1274` * :pr:`1320`: Add `jpeg` extension to the default image extensions * :pr:`1234`: Added new method :meth:`~.Mobject.get_midpoint` Implemented :meth:`~.Mobject.get_midpoint` to return the point that is the middle of the stroke line of an mobject. * :pr:`1237`: Notify user if they are using an outdated version of Manim * :pr:`1308`: Improved :class:`~.ManimBanner` animations * :pr:`1275`: Add SVG element support to :class:`~.SVGMobject` * :pr:`1238`: Add parameter ``about_point`` for :meth:`~.Mobject.rotate` * :pr:`1260`: Change Brace from Tex to SVG (#1258) * :pr:`1122`: Support for specifying the interpolation algorithms for individual ImageMobjects * :pr:`1283`: Set default value of keyword ``random_seed`` in :class:`~.Scene` to ``None`` (was 0 and fixed before) * :pr:`1220`: Added sanity checks to :meth:`~.Mobject.add_to_back` for Mobjects Add Mobject `add_to_back` sanity checks: - Raises ValueError when Mobject tries to add itself - Raises TypeError when a non-Mobject is added - Filters out incoming duplicate submobjects if at least one instance of that submobject exists in the list * :pr:`1249`: Set corners of :class:`~.Rectangle` in counterclockwise direction This improves the look of transformations between rectangles and other simple mobjects. * :pr:`1248`: Add Copy function to TexTemplate Fixed bugs ---------- * :pr:`1368`: Added a check to ensure checking for the latest version was successful * :pr:`1413`: Prevent duplication of the same mobject when adding to submobjects via :meth:`~.Mobject.add_to_back` Fixes #1412 * :pr:`1395`: SVG transforms now handle exponent notation (6.02e23) * :pr:`1355`: Rewrite `put_start_and_end_on` to work in 3D * :pr:`1346`: Fixed errors introduced by stray print in :class:`~.MathTex` * :pr:`1305`: Automatically remove long tick marks not within the range of the :class:`~NumberLine` * :pr:`1296`: Fix random pipeline TeX failures * :pr:`1274`: Fix :meth:`~.VMobject.point_from_proportion` to account for the length of curves. - Add :meth:`~.VMobject.get_nth_curve_function_with_length` and associated functions. - Change :meth:`~.VMobject.point_from_proportion` to use these functions to account for curve length. Documentation-related changes ----------------------------- * :pr:`1430`: Un-deprecated GraphScene (will be deprecated later), fixed an old-style call to NumberPlane - More work is required in order to fully replace `GraphScene` via `Axes`, thus `GraphScene` is not deprecated yet. - Fixed one example in which the old `NumberPlane` syntax was used. * :pr:`1425`: Added a "How to Cite Manim" section to the Readme * :pr:`1387`: Added Guide to Contribute Examples from GitHub Wiki to Documentation Added a Guide * :pr:`1424`: Fixed all current docbuild warnings * :pr:`1389`: Adding Admonitions Tutorial to docs * :pr:`1341`: Reduce complexity of ThreeDSurfacePlot example * :pr:`1362`: Quick reference to modules * :pr:`1376`: Add flake8 and isort in docs added 'flake8' and 'isort' usages to docs * :pr:`1360`: Grammatical error corrections in documentation changed a few sentences in docs/source * :pr:`1351`: Some more typehints * :pr:`1358`: Fixed link to installation instructions for developers * :pr:`1338`: Added documentation guidelines for type hints * :pr:`1342`: Multiple ValueTracker example for docs * :pr:`1210`: Added tutorial chapter on coordinates of an mobject * :pr:`1335`: Added import statements to examples in documentation * :pr:`1245`: Added filled angle Example * :pr:`1328`: Docs: Update Brace example * :pr:`1326`: Improve documentation of :class:`~.ManimMagic` (in particular: fix documented order of CLI flags) * :pr:`1323`: Blacken Docs Strings * :pr:`1300`: Added typehints for :class:`~.ValueTracker` * :pr:`1301`: Added further docstrings and typehints to :class:`~.Mobject` * :pr:`1298`: Add double backquotes for rst code samples (value_tracker.py) * :pr:`1297`: Change docs to use viewcode extension instead of linkcode Switched ``sphinx.ext.linkcode`` to ``sphinx.ext.viewcode`` and removed ``linkcode_resolve`` in ``conf.py``. * :pr:`1246`: Added docstrings for :class:`~.ValueTracker` * :pr:`1251`: Switch documentation from guzzle-sphinx-theme to furo * :pr:`1232`: Further docstrings and examples for :class:`~.Mobject` * :pr:`1291`: Grammar improvements in README.md * :pr:`1269`: Add documentation about :meth:`~.set_color_by_tex` * :pr:`1284`: Updated readme by providing the correct link to the example_scenes * :pr:`1029`: Added example jupyter notebook into the examples folders * :pr:`1279`: Added sphinx requirements to pyproject.toml New contributors who wanted to build the sphinx documentation had an extra step that could be removed by making use of ``poetry install``. This removes the developer's need for ``pip install -r requirements.txt``. * :pr:`1268`: Added documentation explaining the differences between manim versions * :pr:`1247`: Added warning for the usage of `animate` * :pr:`1242`: Added an example for the manim colormap * :pr:`1239`: Add TinyTex installation instructions * :pr:`1231`: Improve changelog generation script Changes concerning the testing system ------------------------------------- * :pr:`1299`: Red pixels (different value) now appear over green pixels (same value) in GraphicalUnitTest Changes to our development infrastructure ----------------------------------------- * :pr:`1436`: Cache poetry venv with `pyproject.toml` hash in key Cache poetry venv with `pyproject.toml` hash in key * :pr:`1435`: CI: Update poetry cache when new version is released Fix `test_version` failure in CI when using cached poetry venv * :pr:`1427`: Add URL's to pyproject.toml * :pr:`1421`: Updated changelog generator's labels and removed pre-commit bot from changelog * :pr:`1339`: CI: Fix macOS installation error from creating file in read-only file system * :pr:`1257`: CI: Caching ffmpeg, tinytex dependencies and poetry venv CI: Caching ffmpeg, tinytex dependencies and poetry venv * :pr:`1294`: Added mixed-line-ending to .pre-commit-config.yaml * :pr:`1278`: Fixed flake8 errors and removed linter/formatter workflows * :pr:`1270`: Added isort to pre_commit file * :pr:`1263`: CI: Turn off experimental installer for poetry to fix installation errors - Turn off experimental installer for poetry to prevent manim installation errors for packages. - Downgrade py39 to py38 for flake checks as `pip` does not enjoy py39, along with `poetry`. * :pr:`1255`: CI: Fix macOS pipeline failure Update `ci.yml` to update and upgrade brew if necessary before installing dependencies, and remove the unsupported `dvisvgm.86_64-darwin` package. * :pr:`1254`: Removed the comment warning that GitHub doesn't allow uploading video in the issue templates. * :pr:`1216`: Use actions/checkout for cloning repository; black-checks * :pr:`1235`: Fixed version of decorator at <5.0.0 Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1411`: Change `Union[float, int]` to just `float` according to PEP 484 * :pr:`1241`: Type Annotations: Fixing errors showing up in static type checking tool mypy * :pr:`1319`: Fix mean/meant typo Fix typo in docs * :pr:`1313`: Singular typo fix on the Quickstart page in documentation * :pr:`1292`: Remove unnecessary imports from files Imports reduced in a bunch of files * :pr:`1295`: Fix grammar and typos in the CODE OF CONDUCT * :pr:`1293`: Minor fixes - reduce lines Remove unnecessary lines * :pr:`1281`: Remove all Carriage Return characters in our files * :pr:`1178`: Format Imports using Isort * :pr:`1233`: Fix deprecation warning for ``--use_opengl_renderer`` and ``--use_webgl_renderer`` * :pr:`1282`: Fix typing hints in vectorized_mobject.py based on mypy New releases ------------ * :pr:`1434`: Prepare v0.6.0 ================================================ FILE: docs/source/changelog/0.7.0-changelog.rst ================================================ ****** v0.7.0 ****** :Date: June 01, 2021 Contributors ============ A total of 45 people contributed to this release. People with a '+' by their names authored a patch for the first time. * André + * Anton Ballmaier * Benjamin Hackl * Clar Fon * Darylgolden * Devin Neal * Hugues Devimeux * Iced-Tea3 + * Jan-Hendrik Müller * Jason Villanueva * Jerónimo Squartini + * KingWampy * Laith Bahodi * Max Stoumen + * Mohammad Al-Fetyani * Naveen M K * NeoPlato * Newell Jensen * Nikhil Garuda * Nikhil Sharma + * PaulCMurdoch + * Philipp Imhof * Raghav Goel * Robert West + * Ryan McCauley + * Skaft + * SwiddisZwei + * e4coder + * friedkeenan * malte-v + * ralphieraccoon * sparshg The patches included in this release have been reviewed by the following contributors. * Aathish Sivasubrahmanian * Abhijith Muthyala * Anton Ballmaier * Aron * Benjamin Hackl * Darylgolden * Devin Neal * GameDungeon * Hugues Devimeux * Iced-Tea3 * Jan-Hendrik Müller * Jason Villanueva * Jerónimo Squartini * KingWampy * Laith Bahodi * Mark Miller * Mohammad Al-Fetyani * Naveen M K * Nikhil Garuda * Oliver * Philipp Imhof * Raghav Goel * Ricky Chon * Ryan McCauley * Skaft * SwiddisZwei * e4coder * friedkeenan * ralphieraccoon * sparshg Pull requests merged ==================== A total of 87 pull requests were merged for this release. Breaking changes ---------------- * :pr:`1521`: Improve :class:`~.Animation` docs - Improve documentation of the :class:`~.Animation` class. - Unify the signature of ``get_all_mobjects``. Now it always returns a sequence of :class:`Mobjects <.Mobject>`. This breaks using ``FadeTransform.get_all_mobjects`` as ``Group``. * :pr:`1470`: Drop support for Python 3.6 Manim won't work on Python 3.6 anymore. Highlights ---------- * :pr:`1447`: Added :class:`~.PolarPlane` for polar coordinates. * :pr:`1490`: Added :class:`~.Polygram`, rework the polygon inheritance tree, and add :class:`~.Star` - Add :class:`~.Polygram`, a generalized :class:`~.Polygon` that allows for disconnected sets of edges. - Make :class:`~.Polygon` inherit from :class:`~.Polygram`. - Add :func:`~.regular_vertices` - Add :class:`~.RegularPolygram`. - Make :class:`~.RegularPolygon` inherit from :class:`~.RegularPolygram`. - Add :class:`~.Star`. * :pr:`1462`: OpenGL: Added :class:`~.Shader`, :class:`~.Mesh`, and :class:`~.FullScreenQuad` Add Shader and Mesh objects * :pr:`1418`: Added project management commands - ``manim init`` - quickly sets up default files for a manim project. - ``manim new project`` - lets the user set project settings. It also creates the project inside a new folder of name - ``manim new scene`` - used to quickly insert new scenes into files. If ``file name`` is not provided ``main.py`` is used as default. Deprecated classes and functions -------------------------------- * :pr:`1598`: Update examples to use :class:`~.Axes` and deprecate :class:`~.GraphScene` :class:`~.GraphScene` has been deprecated and its functionality has been shifted to :class:`~.Axes`. See the updated example gallery for sample usage. * :pr:`1454`: Fading module enhancements Moved functionality of all Fading classes to :class:`~.FadeIn` and :class:`~.FadeOut`. All other fading classes have been deprecated. * :pr:`1375`: Deleted the deprecated ``ShowCreation`` in favor of :class:`~.Create` New features ------------ * :pr:`1566`: Added the ability to add gridlines to a :class:`~.Rectangle` * :pr:`1548`: Added :class:`~.ArcBrace`, a subclass of :class:`~.Brace`. * :pr:`1559`: Update VGroup to support item assignment (#1530) Support indexed item-assignment for VGroup * :pr:`1518`: Allow fading multiple Mobjects in one Animation * :pr:`1422`: Added :func:`~.override_animation` decorator * :pr:`1504`: Color module enhancements - Replaced ``BLUE_E`` with what was previously ``DARK_BLUE`` and removed ``DARK_BLUE`` - Added alias ``LIGHTER_GRAY`` for ``GRAY_A`` - Added ``PURE_RED``, ``PURE_BLUE`` and renamed ``GREEN_SCREEN`` to ``PURE_GREEN`` - All gray colors are now also available using British spelling (including ``GREY_BROWN``) - Replaced color example in the docs. It can now be used as a quick reference for all color names. * :pr:`1272`: Implement metaclass approach in geometry module to make mobjects compatible with cairo and opengl rendering * :pr:`1404`: Added two deprecation decorators Added two function decorators ``deprecated`` and ``deprecated_params`` as a consistent way of deprecating code. Enhancements ------------ * :pr:`1572`: OpenGL compatibility via metaclass: :class:`~.TracedPath`, :class:`~.ParametricFunction`, :class:`~.Brace`, :class:`~.VGroup` * :pr:`1472`: Porting methods from :class:`~.GraphScene` to :class:`~.CoordinateSystem` * :pr:`1589`: OpenGL compatibility via metaclass: :class:`~.ValueTracker` * :pr:`1564`: Add extra notes for TeX compilation errors Add hint to use custom ``TexTemplate`` on TeX compilation errors * :pr:`1584`: Added a check for ``0`` in :meth:`~.round_corners` * :pr:`1586`: Add OpenGLMobject support to all ``isinstance`` occurrences This PR increases the support for OpenGL in the remaining animation classes and in other places where appropriate. * :pr:`1577`: Added new metaclass ConvertToOpenGL (replacing MetaVMobject), restore IntelliSense * :pr:`1562`: Improved VectorField's Nudge Accuracy Per Step Implemented the Runge-Kutta algorithm in VectorField's nudge function. This increases the accuracy as an object moves along a vector field. This also increases efficiency as the nudge function requires less loops to achieve accuracy than the previous implementation. * :pr:`1480`: Add logging info to tex errors * :pr:`1567`: Compatibility Fixes with ManimPango v0.3.0 - ManimPango v0.3.0+ is required for Manim now. - Show errors from Pango when Markup isn't correct * :pr:`1512`: OpenGL compatibility via metaclass: graph * :pr:`1511`: OpenGL compatibility via metaclass: svg_mobject, text_mobject, tex_mobject * :pr:`1502`: Added ``center`` parameter to :class:`~.Sphere` and ``point`` parameter to :class:`~.Dot3D` * :pr:`1486`: Update of ``rate_functions`` Changed the picture for the non standard rate functions. * :pr:`1495`: Ported value_tracker to OpenGL * :pr:`1382`: Expand documentation, testing, and functionality of ValueTrackers; remove ExponentialValueTracker Added more documentation and inline operators to ValueTracker and ComplexValueTracker. Brought coverage for value_tracker.py to 100%. Removed ExponentialValueTracker. * :pr:`1475`: Add SVG elliptical arc support Fixed bugs ---------- * :pr:`1574`: Fixed error when processing SVG with omitted elliptical arc command * :pr:`1596`: Fix indexing for non-whitespace tex arg separator Fixes #1568 Fix issue when setting the arg_separator of a Tex object as a non-whitespace character(s). The method `break_up_by_substrings(self)` was not accounting for the separator when setting the index. * :pr:`1588`: Fixed multiple animations being saved in the same file * :pr:`1571`: Fix tests after introducing parallelization * :pr:`1545`: Fix outdated parameters for :class:`LinearTransformationScene` and add an example + typing. * :pr:`1513`: Fixed rotation of gradients while rotating a VMobject - Fixed the direction of gradient which remained the same while rotating VMobjects - Added ``rotate_sheen_direction()`` method in VMobject * :pr:`1570`: Output errors to stderr * :pr:`1560`: Declare ``*.npz`` ``*.wav`` ``*.png`` as binary in ``.gitattributes`` * :pr:`1211`: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene Refactored internal scene-caching mechanism and fixed bug when an inconsistent hash was produced when copying a mobject. * :pr:`1527`: Improved handling of substring isolation within sqrt, and fixed a bug with transform_mismatch for the matching shape transforms * :pr:`1526`: Fix fading * :pr:`1523`: Fix multiple FadeIn / Out only working on VMobjects Documentation-related changes ----------------------------- * :pr:`1599`: Added example for :class:`~.Annulus` * :pr:`1415`: New example for gallery and some docs refinements * :pr:`1509`: Copyedited Documentation Added a link to Manim Community GitHub page in ``for_dev.rst``. Fixed :meth:`~.Mobject.get_start` and added ``roll`` link in ``building_blocks-rst`` Added language to code blocks in ``configuration.rst`` * :pr:`1384`: Added typings to space_ops.py Added Typehints to most of the functions * :pr:`1500`: Example for :meth:`~.apply_complex_function` * :pr:`1551`: Fixed the typo for Admonitions * :pr:`1550`: Restructuring of Contribution Section * :pr:`1541`: Fixing broken links and other minor doc things * :pr:`1516`: Update docs to use ``t_range`` instead of ``t_min`` and ``t_max`` in :class:`~.ParametricFunction` * :pr:`1508`: Update troubleshooting docs * :pr:`1485`: Added :class:`~.Title` example for the docs * :pr:`1439`: Cleaning ``Sequence`` typehints * :pr:`1440`: Added Scoop installation docs (Windows) * :pr:`1452`: Refine typehints at :class:`~.Angle` * :pr:`1458`: Refine docs of :class:`~.Text` ( add ``disable_ligatures=True`` for t2c) * :pr:`1449`: Added :class:`~.PointCloudDot` example * :pr:`1473`: Added easy example for :meth:`~.arrange_in_grid` * :pr:`1402`: Added typestring parser checker * :pr:`1451`: Reduce complexity of AngleExample * :pr:`1441`: Add inheritance diagrams to reference page Added inheritance diagrams to the reference page as a quick navigation method. * :pr:`1457`: Fixing broken doc links * :pr:`1445`: Remove $ from tutorial commands Changes concerning the testing system ------------------------------------- * :pr:`1556`: Try pytest-xdist for parallelization in tests Changes to our development infrastructure ----------------------------------------- * :pr:`1505`: Add docs reference to PR template Added documentation link to the Pull Request Template. * :pr:`1499`: Updated Discord links in the docs to point towards a standardized redirect * :pr:`1461`: Build the docs - Logging * :pr:`1481`: pyproject.toml: poetry_core -> poetry-core * :pr:`1477`: Update RDT sphinx package to version 3.5.3 * :pr:`1460`: Create CONTRIBUTING.md * :pr:`1453`: manim_directive: fix image links in docs - Windows Use POSIX path on Windows to link images so documentation can build locally. Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1465`: Added typings and description to some functions in :mod:`~.coordinate_systems`. * :pr:`1552`: Removed unwanted parameters in geometry Removed ``anchors_span_full_range``, ``close_new_points``, ``anchors_span_full_range``, ``preserve_tip_size_when_scaling``, ``mark_paths_closed`` and ``close_new_points`` * :pr:`1597`: Removed hilite_me and insert_line_numbers_in_html from global name space * :pr:`1535`: Update dependencies and fix tests * :pr:`1544`: Adding spell checker as a pre-commit hook * :pr:`1542`: Swapping a pango markup link in docs * :pr:`1531`: Don't use deprecated methods in deprecation.py * :pr:`1492`: Remove stray print statements introduced in #1404 * :pr:`1471`: Fix Some Warnings from lgtm Changes that needed to be reverted again ---------------------------------------- * :pr:`1606`: Bring back ``DARK_BLUE`` New releases ------------ * :pr:`1601`: Preparation for v0.7.0: added changelog and bumped version number ================================================ FILE: docs/source/changelog/0.8.0-changelog.rst ================================================ ****** v0.8.0 ****** :Date: July 02, 2021 Contributors ============ A total of 37 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Benjamin Hackl * Bill Shillito + * Darigov Research + * Darylgolden * Devin Neal * Iced-Tea3 * Jan-Hendrik Müller * Jason Villanueva * KingWampy * Laith Bahodi * MathInvariance + * Max Stoumen * Mehmet Ali Özer + * Michael Pilosov + * Mohammad Al-Fetyani * Naveen M K * Nikhil Garuda * Oliver * PaulCMurdoch * Philipp Imhof * PipedQuintes + * Raghav Goel * Ryan McCauley * Ujjayanta + * Vagrid + * andrehisatsuga + * friedkeenan * peaceheis + * yit6 + The patches included in this release have been reviewed by the following contributors. * Abhijith Muthyala * Anton Ballmaier * Aron * Benjamin Hackl * Clar Fon * Darylgolden * Devin Neal * Jan-Hendrik Müller * Jason Villanueva * KingWampy * Laith Bahodi * Mark Miller * MathInvariance * Mohammad Al-Fetyani * Naveen M K * Nikhil Garuda * Oliver * Philipp Imhof * Raghav Goel * Ryan McCauley * Ujjayanta * Vagrid * friedkeenan Pull requests merged ==================== A total of 76 pull requests were merged for this release. Deprecated classes and functions -------------------------------- * :pr:`1616`: Remove all functions and classes that were deprecated until ``v0.6.0`` New features ------------ * :pr:`1716`: Rewrite stroke and fill shaders Rewrite vectorized mobject shaders to be compatible with transformation matrices. * :pr:`1695`: Add option to justify text with :class:`~.MarkupText` A new parameter ``justify`` is added to :class:`~.MarkupText`. It can be used to justify a paragraph of text. * :pr:`1660`: Added support for ``.webm`` and transparency of videos in Jupyter notebooks - Added support for generating ``webm`` videos via the command line flag ``--format=webm`` - Added transparency support for Jupyter notebooks * :pr:`1553`: Add dearpygui integration Enhancements ------------ * :pr:`1728`: Improved positioning and size of the OpenGL window; added some configuration options * :pr:`1733`: Let OpenGLMobject.copy return a deep copy by default * :pr:`1735`: Metaclass compatibility for `coordinate_system.py`, `Code` and `ParametricSurface` * :pr:`1585`: OpenGL compatibility via metaclass for :class:`~.Matrix`, :class:`~.DecimalNumber`, :class:`~.Variable` * :pr:`1713`: Exit the command line interface gracefully if no scene was chosen * :pr:`1652`: Refactored :class:`~.Mobject` and :class:`~.Scene` to no longer inherit from the abstract base class ``Container`` - Moved tests in ``test_container.py`` for :class:`Container` that test :class:`~.Scene` and :class:`~.Mobject` to their own files. - Corrected various instances of incorrectly passed keyword arguments, or unused keyword arguments. * :pr:`1693`: Made the default arrowhead size for :class:`~.Arrow3D` smaller * :pr:`1678`: Allow some rate functions to assume values outside of [0, 1]; introduce clamping decorators - Fixed animations so that certain rate functions (``running_start``, ``wiggle``, ``ease_in_back``, ``ease_out_back``, ``ease_in_out_back``, ``ease_in_elastic``, ``ease_out_elastic``, and ``ease_out_elastic``) can go outside the range from 0 to 1. - Fixed lag ratios so that they're spaced out evenly within the time interval and the rate functions are applied to each animation individually, rather than having the rate function determine when the animation starts. - Fixed faulty code for ``ease_in_out_expo``, ``ease_in_bounce``, ``ease_out_bounce``, and ``ease_in_out_bounce``. * :pr:`1649`: Made video file names in Jupyter notebook more readable * :pr:`1667`: Determine the default number of decimal places for :class:`~.NumberLine` labels automatically from the step size As an example: If the step size is set to 0.5, labels will now show at least one decimal place. * :pr:`1608`: Color file paths in terminal; remove curly braces surrounding the file path in "Partial movie file written in..." messages * :pr:`1632`: OpenGL compatibility via metaclass: :class:`~.Group` Fixed bugs ---------- * :pr:`1740`: Fix pillow to <8.3.0 * :pr:`1729`: Fix bug when using :class:`~.Text` with the OpenGL renderer * :pr:`1675`: Fixed ignored fill and stroke colors for :class:`~.SVGMobject` * :pr:`1664`: Fixed accidental displacement in :class:`~.Axes` caused by ``include_numbers`` / ``numbers_to_include`` * :pr:`1670`: Fixed missing ``numpy`` import in OpenGL shader example * :pr:`1636`: Fixed bugs and added examples to methods and classes in :mod:`manim.mobject.matrix` * :pr:`1614`: Fix tick issues and improve tick placement for :class:`~.NumberLine` * :pr:`1593`: Un-flip output of ``get_frame()`` when using the OpenGL renderer * :pr:`1619`: Fix output of automatically detected LaTeX errors * :pr:`1595`: Fixed a few CLI and rendering bugs - Corrected issue where gifs were being logged with an incorrect extension - Fixed issue where videos were output when format was set to png - Added logging for png output - Added precedence handling when the ``write_to_movie`` flag would conflict with ``--format`` - Fixed issue that caused png image output to be ignored when caching was enabled * :pr:`1635`: Added missing numpy import for :mod:`manim.mobject.probability` * :pr:`1634`: Fixed OpenGL examples for MacOS Renamed deprecated ``gl_FragColor`` to ``fragColor``. Documentation-related changes ----------------------------- * :pr:`1732`: Remove reference to ``--plugins`` flag * :pr:`1734`: Fix inheritance graph background color * :pr:`1698`: Added an example for :class:`~.PMobject` * :pr:`1690`: Added an example for :class:`~.CoordinateSystem` * :pr:`1510`: Add a tutorial for using :class:`~.Text` and :class:`~.Tex` * :pr:`1685`: Added an example and parameter description for :class:`~.AnnularSector` * :pr:`1687`: Updated imports in ``geometry.py`` and added example to :class:`~.Arrow` * :pr:`1681`: Added an example for :class:`~.NumberLine` * :pr:`1697`: Added an example for :class:`~.PGroup` * :pr:`1594`: Several improvements to the documentation design and layout * :pr:`1696`: Added an example for :class:`~.DashedVMobject` * :pr:`1637`: Added an example for :class:`~.FunctionGraph` * :pr:`1626`: Added an example for :class:`~.Prism` * :pr:`1712`: Added a second example for :class:`~.DoubleArrow` * :pr:`1710`: Update copyright year in documentation to 2020-2021 * :pr:`1708`: Fixed link to interactive example notebook * :pr:`1657`: Added an example for :class:`~.ParametricSurface` * :pr:`1642`: Added examples and docstrings for :class:`~.BarChart` * :pr:`1700`: Added an example for :meth:`~.Mobject.scale` * :pr:`1689`: Added an example for :class:`~.SurroundingRectangle` * :pr:`1627`: Added an example for :class:`~.Sphere` * :pr:`1569`: Added example to demonstrate differences between :class:`~.Transform` and :class:`~.ReplacementTransform` * :pr:`1647`: Added an example for :class:`~.Sector` * :pr:`1673`: Updated documentation examples for :class:`~.Text` and :class:`~.MarkupText`: set ``weight=BOLD`` instead of ``style`` * :pr:`1650`: Added an example for :class:`~.ArcBetweenPoints` * :pr:`1628`: Added an example for :class:`~.NumberPlane` * :pr:`1646`: Added an example for :class:`~.Underline` * :pr:`1659`: Added more details to the Google Colab installation instructions * :pr:`1658`: Updated python requirement in the documentation * :pr:`1639`: Added an example for :class:`~.SampleSpace` * :pr:`1640`: Added an example for :class:`~.Point` * :pr:`1643`: Fixed ``RightArcAngleExample`` for :class:`~.Angle` in documentation * :pr:`1617`: Visually improved an example in our tutorial * :pr:`1641`: Added an example for :class:`~.ComplexPlane` * :pr:`1644`: Added an example for :class:`~.BackgroundRectangle` * :pr:`1633`: Added an example for :class:`~.Integer` * :pr:`1630`: Added an example for :class:`~.Arc` * :pr:`1631`: Added an example for :class:`~.BulletedList` * :pr:`1620`: Fixed reference to command line interface help command Changes to our development infrastructure ----------------------------------------- * :pr:`1623`: CI: branch rename: master -> main * :pr:`1621`: Revert default template and add new templates * :pr:`1573`: PR template for the manim hackathon Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1720`: Renamed incorrect references of ``master`` to ``main`` * :pr:`1692`: Removed redundant warning in CLI parsing * :pr:`1651`: Small code cleanup for :class:`~.Polygram` * :pr:`1610`: Changed one image extension to lowercase letters New releases ------------ * :pr:`1738`: Preparation for v0.8.0: added changelog and bumped version number ================================================ FILE: docs/source/changelog/0.9.0-changelog.rst ================================================ ****** v0.9.0 ****** :Date: August 02, 2021 Contributors ============ A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time. * Alex Lembcke * Benjamin Hackl * Darylgolden * Devin Neal * Harivinay + * Hugues Devimeux * Jared Hughes + * Jason Villanueva * Kadatatlu Kishore + * KingWampy * LED Me Explain + * Laith Bahodi * Mohammad Al-Fetyani * Noam Zaks * Oliver * PaulCMurdoch * Raghav Prabhakar + * Ryan McCauley * Suhail Sherif + * Taektiek + * Udeshya Dhungana + * UraniumCronorum + * Vinh H. Pham (Vincent) + * ccn + * icedcoffeeee + * sahilmakhijani + * sparshg The patches included in this release have been reviewed by the following contributors. * Abhijith Muthyala * Alex Lembcke * Benjamin Hackl * Darylgolden * Devin Neal * Harivinay * Hugues Devimeux * Jan-Hendrik Müller * Jason Villanueva * KingWampy * Laith Bahodi * Lino * Mohammad Al-Fetyani * Oliver * Raghav Goel * Suhail Sherif * icedcoffeeee * sahilmakhijani * sparshg Pull requests merged ==================== A total of 55 pull requests were merged for this release. Highlights ---------- * :pr:`1677`: Added a new :class:`~.Table` mobject This brings easy-to-use and customizable tables to Manim. Several examples for this new mobject can be found at :mod:`the module documentation page <.mobject.table>` and its subpages. Deprecated classes and functions -------------------------------- * :pr:`1848`: Deprecated parameters for :class:`~.DashedLine` and :class:`~.DashedVMobject` - ``dash_spacing`` is an unused parameter - ``positive_space_ratio`` has been replaced with the shorter name ``dashed_ratio`` * :pr:`1773`: Remove all classes and functions that were deprecated until ``v0.7.0`` and ``v0.8.0`` The classes ``FadeInFrom``, ``FadeOutAndShift``, ``FadeOutToPoint``, ``FadeInFromPoint``, ``FadeInFromLarge``, ``VFadeIn``, ``VFadeOut``, ``VFadeInThenOut`` have been removed, use :class:`~.FadeIn` or :class:`~.FadeOut` with appropriate keyword arguments instead. The classes ``CircleIndicate``, ``ShowCreationThenDestruction``, ``AnimationOnSurroundingRectangle``, ``ShowPassingFlashAround``, ``ShowCreationThenDestructionAround``, ``ShowCreationThenFadeAround``, ``WiggleOutThenIn``, ``TurnInsideOut`` have been removed. Use :class:`~.Circumscribe`, :class:`~.ShowPassingFlash`, or :class:`~.Wiggle` instead. The classes ``OpenGLTexMobject`` and ``OpenGLTextMobject`` have been removed, use :class:`~.MathTex` and :class:`~.Tex` instead. Also, ``VMobjectFromSVGPathstring`` has been removed, use :class:`~.SVGPathMobject` instead. Finally, the utility functions ``get_norm`` and ``cross`` have been removed (use the corresponding Numpy methods instead), and the function ``angle_between`` has been replaced with ``angle_between_vectors``. * :pr:`1731`: Deprecated :class:`~.ParametricSurface` parameters - ``u_min`` and ``u_max`` have been replaced by ``u_range``. - ``v_min`` and ``v_max`` have been replaced by ``v_range``. New features ------------ * :pr:`1780`: Allow non-numerical values to be added to :class:`~.NumberLine` and :class:`~.Axes` - Added :meth:`.NumberLine.add_labels` method to :class:`~.NumberLine` which accepts a dictionary of positions/values. - :meth:`.CoordinateSystem.add_coordinates` now accepts a dictionary too. * :pr:`1719`: Added a :class:`~.Broadcast` animation * :pr:`1765`: Added a static method :meth:`.Circle.from_three_points` for defining a circle from three points - Added a new :func:`~.perpendicular_bisector` function in ``space_ops.py`` * :pr:`1686`: Added :meth:`.ParametricSurface.set_fill_by_value` This method enables a color gradient to be applied to a :class:`~.ParametricSurface`, including the ability to define at which points the colors should be centered. Enhancements ------------ * :pr:`1833`: Added OpenGL compatibility for :class:`~.VDict`, :meth:`~.Axes.get_line_graph` and :class:`~.FocusOn` * :pr:`1760`: Added ``window_size`` flag to manually adjust the size of the OpenGL window Accepts a tuple in the form: ``x,y``. * :pr:`1823`: Reworked :class:`~.DashedVMobject` Rewritten the logic to generate dashes * :pr:`1808`: OpenGL renderer updates - Adds model matrices to all OpenGLVMobjects - Improved performance on vectorized mobject shaders - Added updaters that are part of the scene rather than a mobject * :pr:`1787`: Made :class:`~.DecimalNumber` apply color to the ellipsis Made color apply to the dots when `show_ellipsis` is set to true in `DecimalNumber` * :pr:`1775`: Let :class:`~.Create` work on :class:`~.OpenGLSurface` * :pr:`1757`: Added warning when there is a large number of items to hash. * :pr:`1774`: Add the ``reverse`` parameter to :class:`~.Write` Fixed bugs ---------- * :pr:`1722`: Fixed ``remover=True`` for :class:`~.AnimationGroup` * :pr:`1727`: Fixed some hot reload issues and compatibility with IDEs - Fixed interactive embed issue where it would fail when running on non-tty terminals - Fixed issue where file observer would error after the second run as the first observer was not closed * :pr:`1844`: Fixed the oversized :class:`~.Code` window with the OpenGL renderer * :pr:`1821`: Fixed issues concerning ``frame_center`` in :class:`~.ThreeDScene` - Changing ``frame_center`` in a :class:`~.ThreeDScene` now actually changes the camera position. - An animation with only ``frame_center`` animated will now be rendered properly. - A black dot is not created at the origin once ``frame_center`` is animated. * :pr:`1826`: Fixed scaling issue with :meth:`.BarChart.change_bar_values` * :pr:`1839`: Allow passing arguments to ``.animate`` with the OpenGL renderer * :pr:`1791`: :meth:`~.Mobject.set_z_index` now sets all submobjects' ``z_index`` value * :pr:`1792`: Fixed bug that caused dry runs to fail when using the PNG format * :pr:`1790`: Fixed an import from ``manimlib`` * :pr:`1782`: Fixed :class:`~.Tex` not working properly with the OpenGL renderer * :pr:`1783`: Fixed :meth:`~.OpenGLMobject.shuffle` function and added :meth:`~.Mobject.invert` to OpenGL * :pr:`1786`: Fixed :class:`~.DecimalNumber` not working properly when the number of digits changes * :pr:`1763`: Fixed not being able to set some CLI flags in the configuration file * :pr:`1776`: :meth:`.CoordinateSystem.get_riemann_rectangles` now uses the graph's range instead of the axes range If no range specified, `get_riemann_rectangles` generates the rectangles only where the area is correctly bounded * :pr:`1770`: Rewrote :meth:`.OpenGLMobject.put_start_and_end_on` to work correctly in 3D * :pr:`1736`: Fixed :class:`~.LinearTransformationScene` crashing on multiple animations Documentation-related changes ----------------------------- * :pr:`1852`: Fixed docs for :meth:`.Coordinate_system.add_coordinates` and moved :class: `~.Code` example * :pr:`1807`: Updated installation instructions - Added a warning about the incompatibility of different versions of Manim in the README - Modified the admonition warning in the documentation - Removed duplicated information from the README (``pip install manim`` is already covered in the docs) * :pr:`1739`: Added a section on creating a custom animation to the "Manim's building blocks" tutorial * :pr:`1835`: Updated documentation with information about reworked graphical unit test system * :pr:`1845`: Improve ``ThreeDSurfacePlot`` example in example gallery * :pr:`1842`: Removed instructions on installing Poetry from Developer Installation documentation, reference Poetry's documentation instead * :pr:`1829`: Switch the order of Scoop and Chocolatey in the docs for the Windows Installation * :pr:`1827`: Added ``robots.txt`` to prevent old versions of documentation from showing in search results * :pr:`1819`: Removed mention of ``-h`` CLI flag from documentation * :pr:`1813`: Removed unused variables from tutorial * :pr:`1815`: Added codespell to the list of used linters in the contribution guidelines * :pr:`1778`: Improve sidebar structure of the documentation's reference manual * :pr:`1749`: Added documentation and example for :meth:`.VMobject.set_fill` * :pr:`1743`: Edited the developer installation instructions to include information on cloning the repository * :pr:`1706`: Rework example for :class:`~.Variable` Changes concerning the testing system ------------------------------------- * :pr:`1836`: Converted all the graphical tests to the new syntax * :pr:`1802`: Refactored graphical unit testing system, and implemented multi frames tests This PR introduces a new ``@frames_comparison`` decorator which allows writing simple ``construct``-like functions as tests. Control data for new tests can be easily generated by calling ``pytest --set_test``. Changes to our development infrastructure ----------------------------------------- * :pr:`1830`: Be more concise about the documentation URL in the PR template Code quality improvements and similar refactors ----------------------------------------------- * :pr:`1851`: Renamed ``Tabular`` to :class:`~.Table` * :pr:`1817`: Remove pillow version requirement * :pr:`1806`: Fixed spelling mistake * :pr:`1745`: Updated the BibTeX template in the README to Manim v0.9.0 New releases ------------ * :pr:`1850`: Bump version number to ``v0.9.0`` and generate changelog ================================================ FILE: docs/source/changelog.rst ================================================ ######### Changelog ######### This page contains a list of changes made between releases. .. toctree:: :maxdepth: 1 changelog/0.20.1-changelog changelog/0.20.0-changelog changelog/0.19.2-changelog changelog/0.19.1-changelog changelog/0.19.0-changelog changelog/0.18.1-changelog changelog/0.18.0.post0-changelog changelog/0.18.0-changelog changelog/0.17.3-changelog changelog/0.17.2-changelog changelog/0.17.1-changelog changelog/0.17.0-changelog changelog/0.16.0-changelog changelog/0.15.2-changelog changelog/0.15.1-changelog changelog/0.15.0-changelog changelog/0.14.0-changelog changelog/0.13.1-changelog changelog/0.13.0-changelog changelog/0.12.0-changelog changelog/0.11.0-changelog changelog/0.10.0-changelog changelog/0.9.0-changelog changelog/0.8.0-changelog changelog/0.7.0-changelog changelog/0.6.0-changelog changelog/0.5.0-changelog changelog/0.4.0-changelog changelog/0.3.0-changelog changelog/0.2.0-changelog changelog/0.1.1-changelog changelog/0.1.0-changelog ================================================ FILE: docs/source/conf.py ================================================ # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html from __future__ import annotations import os import sys from datetime import datetime from pathlib import Path import manim from manim.utils.docbuild.module_parsing import parse_module_attributes # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath(".")) # -- Project information ----------------------------------------------------- project = "Manim" copyright = f"2020-{datetime.now().year}, The Manim Community Dev Team" # noqa: A001 author = "The Manim Community Dev Team" # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx_copybutton", "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.doctest", "sphinx.ext.extlinks", "sphinx.ext.viewcode", "sphinxext.opengraph", "manim.utils.docbuild.manim_directive", "manim.utils.docbuild.autocolor_directive", "manim.utils.docbuild.autoaliasattr_directive", "sphinx.ext.graphviz", "sphinx.ext.inheritance_diagram", "sphinxcontrib.programoutput", "myst_parser", "sphinx_design", "sphinx_reredirects", ] # Automatically generate stub pages when using the .. autosummary directive autosummary_generate = True myst_enable_extensions = ["colon_fence", "amsmath", "deflist"] # redirects (for moved / deleted pages) redirects = { "installation/linux": "uv.html", "installation/macos": "uv.html", "installation/windows": "uv.html", } # generate documentation from type hints ALIAS_DOCS_DICT = parse_module_attributes()[0] autodoc_typehints = "description" autodoc_type_aliases = { alias_name: f"~manim.{module}.{alias_name}" for module, module_dict in ALIAS_DOCS_DICT.items() for category_dict in module_dict.values() for alias_name in category_dict } autoclass_content = "both" # controls whether functions documented by the autofunction directive # appear with their full module names add_module_names = False # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # Custom section headings in our documentation napoleon_custom_sections = ["Tests", ("Test", "Tests")] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. html_extra_path = ["robots.txt"] exclude_patterns: list[str] = [] # -- Options for internationalization ---------------------------------------- # Set the destination directory of the localized po files locale_dirs = ["../i18n/"] # Splits the text in more pot files. gettext_compact = False # Remove useless metadata from po files. gettext_last_translator = "" gettext_language_team = "" # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "furo" html_favicon = str(Path("_static/favicon.ico")) # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] html_theme_options = { "source_repository": "https://github.com/ManimCommunity/manim/", "source_branch": "main", "source_directory": "docs/source/", "light_logo": "manim-logo-sidebar.svg", "dark_logo": "manim-logo-sidebar-dark.svg", "light_css_variables": { "color-content-foreground": "#000000", "color-background-primary": "#ffffff", "color-background-border": "#ffffff", "color-sidebar-background": "#f8f9fb", "color-brand-content": "#1c00e3", "color-brand-primary": "#192bd0", "color-link": "#c93434", "color-link--hover": "#5b0000", "color-inline-code-background": "#f6f6f6;", "color-foreground-secondary": "#000", }, "dark_css_variables": { "color-content-foreground": "#ffffffd9", "color-background-primary": "#131416", "color-background-border": "#303335", "color-sidebar-background": "#1a1c1e", "color-brand-content": "#2196f3", "color-brand-primary": "#007fff", "color-link": "#51ba86", "color-link--hover": "#9cefc6", "color-inline-code-background": "#262626", "color-foreground-secondary": "#ffffffd9", }, } html_title = f"Manim Community v{manim.__version__}" # This specifies any additional css files that will override the theme's html_css_files = ["custom.css"] latex_engine = "lualatex" # external links extlinks = { "issue": ("https://github.com/ManimCommunity/manim/issues/%s", "#%s"), "pr": ("https://github.com/ManimCommunity/manim/pull/%s", "PR #%s"), "user": ("https://github.com/%s", "@%s"), } # opengraph settings ogp_site_name = "Manim Community | Documentation" ogp_site_url = "https://docs.manim.community/" ogp_social_cards = { "image": "_static/logo.png", } # inheritance_graph settings inheritance_graph_attrs = { "concentrate": True, "size": '""', "splines": "ortho", "nodesep": 0.1, "ranksep": 0.2, } inheritance_node_attrs = { "penwidth": 0, "shape": "box", "width": 0.05, "height": 0.05, "margin": 0.05, } inheritance_edge_attrs = { "penwidth": 1, } html_js_files = ["responsiveSvg.js"] graphviz_output_format = "svg" ================================================ FILE: docs/source/contributing/development.md ================================================ # Manim Development Process ## For first-time contributors 1. Install git: For instructions see . 2. Fork the project: Go to and click the "fork" button to create a copy of the project for you to work on. You will need a GitHub account. This will allow you to make a "Pull Request" (PR) to the ManimCommunity repo later on. 3. Clone your fork to your local computer: ```shell git clone https://github.com//manim.git ``` GitHub will provide both a SSH (`git@github.com:/manim.git`) and HTTPS (`https://github.com//manim.git`) URL for cloning. You can use SSH if you have SSH keys setup. :::{WARNING} Do not clone the ManimCommunity repository. You must clone your own fork. ::: 4. Change the directory to enter the project folder: ```shell cd manim ``` 5. Add the upstream repository, ManimCommunity: ```shell git remote add upstream https://github.com/ManimCommunity/manim.git ``` 6. Now, `git remote -v` should show two remote repositories named: - `origin`, your forked repository - `upstream` the ManimCommunity repository 7. Install the Python project management tool `uv`, as recommended in our {doc}`installation guide for users `. 8. Let `uv` create a virtual environment for your development installation by running ```shell uv sync ``` In case you need (or want) to install some of the optional dependency groups defined in our [`pyproject.toml`](https://github.com/ManimCommunity/manim/blob/main/pyproject.toml), run `uv sync --all-extras`, or pass the `--extra` flag with the name of a group, for example `uv sync --extra jupyterhub`. 9. Install Pre-Commit: ```shell uv run pre-commit install ``` This will ensure during development that each of your commits is properly formatted against our linter and formatters. You are now ready to work on Manim! ## Develop your contribution 1. Checkout your local repository's main branch and pull the latest changes from ManimCommunity, `upstream`, into your local repository: ```shell git switch main git pull --rebase upstream main ``` 2. Create a branch for the changes you want to work on rather than working off of your local main branch: ```shell git switch -c upstream/main ``` This ensures you can easily update your local repository's main with the first step and switch branches to work on multiple features. 3. Write some awesome code! You're ready to make changes in your local repository's branch. You can add local files you've changed within the current directory with `git add .`, or add specific files with ```shell git add ``` and commit these changes to your local history with `git commit`. If you have installed pre-commit, your commit will succeed only if none of the hooks fail. :::{tip} When crafting commit messages, it is highly recommended that you adhere to [these guidelines](https://www.conventionalcommits.org/en/v1.0.0/). ::: 4. Add new or update existing tests. Depending on your changes, you may need to update or add new tests. For new features, it is required that you include tests with your PR. Details of our testing system are explained in the {doc}`testing guide `. 5. Update docstrings and documentation: Update the docstrings (the text in triple quotation marks) of any functions or classes you change and include them with any new functions you add. See the {doc}`documentation guide ` for more information about how we prefer our code to be documented. The content of the docstrings will be rendered in the {doc}`reference manual <../reference>`. :::{tip} Use the {mod}`manim directive for Sphinx ` to add examples to the documentation! ::: As far as development on your local machine goes, these are the main steps you should follow. (polishing-changes-and-submitting-a-pull-request)= ## Polishing Changes and Submitting a Pull Request As soon as you are ready to share your local changes with the community so that they can be discussed, go through the following steps to open a pull request. A pull request signifies to the ManimCommunity organization, "Here are some changes I wrote; I think it's worthwhile for you to maintain them." :::{note} You do not need to have everything (code/documentation/tests) complete to open a pull request (PR). If the PR is still under development, please mark it as a draft. Community developers will still be able to review the changes, discuss yet-to-be-implemented changes, and offer advice; however, the more complete your PR, the quicker it will be merged. ::: 1. Update your fork on GitHub to reflect your local changes: ```shell git push -u origin ``` Doing so creates a new branch on your remote fork, `origin`, with the contents of your local repository on GitHub. In subsequent pushes, this local branch will track the branch `origin` and `git push` is enough. 2. Make a pull request (PR) on GitHub. In order to make the ManimCommunity development team aware of your changes, you can make a PR to the ManimCommunity repository from your fork. :::{WARNING} Make sure to select `ManimCommunity/manim` instead of `3b1b/manim` as the base repository! ::: Choose the branch from your fork as the head repository - see the screenshot below. ```{image} /_static/pull-requests.png :align: center ``` Please make sure you follow the template (this is the default text you are shown when first opening the 'New Pull Request' page). Your changes are eligible to be merged if: 1. there are no merge conflicts 2. the tests in our pipeline pass 3. at least one (two for more complex changes) Community Developer approves the changes You can check for merge conflicts between the current upstream/main and your branch by executing `git pull upstream main` locally. If this generates any merge conflicts, you need to resolve them and push an updated version of the branch to your fork of the repository. Our pipeline consists of a series of different tests that ensure that Manim still works as intended and that the code you added sticks to our coding conventions. - **Code style**: We use the code style imposed by [Black](https://black.readthedocs.io/en/stable/), [isort](https://pycqa.github.io/isort/) and [flake8](https://flake8.pycqa.org/en/latest/). The GitHub pipeline makes sure that the (Python) files changed in your pull request also adhere to this code style. If this step of the pipeline fails, fix your code formatting automatically by running `black ` and `isort `. To fix code style problems, run `flake8 ` for a style report, and then fix the problems manually that were detected by `flake8`. - **Tests**: The pipeline runs Manim's test suite on different operating systems (the latest versions of Ubuntu, macOS, and Windows) for different versions of Python. The test suite consists of two different kinds of tests: integration tests and doctests. You can run them locally by executing `uv run pytest` and `uv run pytest --doctest-modules manim`, respectively, from the root directory of your cloned fork. - **Documentation**: We also build a version of the documentation corresponding to your pull request. Make sure not to introduce any Sphinx errors, and have a look at the built HTML files to see whether the formatting of the documentation you added looks as you intended. You can build the documentation locally by running `make html` from the `docs` directory. Make sure you have [Graphviz](https://graphviz.org/) installed locally in order to build the inheritance diagrams. See {doc}`docs` for more information. Finally, if the pipeline passes and you are satisfied with your changes: wait for feedback and iterate over any requested changes. You will likely be asked to edit or modify your PR in one way or another during this process. This is not an indictment of your work, but rather a strong signal that the community wants to merge your changes! Once approved, your changes may be merged! ### Further useful guidelines 1. When submitting a PR, please mention explicitly if it includes breaking changes. 2. When submitting a PR, make sure that your proposed changes are as general as possible, and ready to be taken advantage of by all of Manim's users. In particular, leave out any machine-specific configurations, or any personal information it may contain. 3. If you are a maintainer, please label issues and PRs appropriately and frequently. 4. When opening a new issue, if there are old issues that are related, add a link to them in your new issue (even if the old ones are closed). 5. When submitting a code review, it is highly recommended that you adhere to [these general guidelines](https://conventionalcomments.org/). 6. If you find stale or inactive issues that seem to be irrelevant, please post a comment saying 'This issue should be closed', and a community developer will take a look. 7. Please do as much as possible to keep issues, PRs, and development in general as tidy as possible. You can find examples for the `docs` in several places: the {doc}`Example Gallery <../examples>`, {doc}`Tutorials <../tutorials/index>`, and {doc}`Reference Classes <../reference>`. **Thank you for contributing!** ================================================ FILE: docs/source/contributing/docs/admonitions.rst ================================================ ================== Adding Admonitions ================== Adding Blocks for Tip, Note, Important etc. (Admonitions) --------------------------------------------------------- The following directives are called Admonitions. You can use them to point out additional or important information. Here are some examples: See also ~~~~~~~~ .. code-block:: rest .. seealso:: Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser` .. seealso:: Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser` .. index:: reST directives; note Note ~~~~ .. code-block:: rest .. note:: A note .. note:: A note Tip ~~~ .. code-block:: rest .. tip:: A tip .. tip:: A tip You may also use the admonition **hint**, but this is very similar and **tip** is more commonly used in the documentation. Important ~~~~~~~~~ .. code-block:: rest .. important:: Some important information which should be considered. .. important:: Some important information which should be considered. Warning ~~~~~~~ .. code-block:: rest .. warning:: Some text pointing out something that people should be warned about. .. warning:: Some text pointing out something that people should be warned about. You may also use the admonitions **caution** or even **danger** if the severity of the warning must be stressed. Attention ~~~~~~~~~ .. code-block:: rest .. attention:: A attention .. attention:: A attention You can find further information about Admonitions here: https://pradyunsg.me/furo/reference/admonitions/ ================================================ FILE: docs/source/contributing/docs/docstrings.rst ================================================ ================= Adding Docstrings ================= A docstring is a string literal that is used right after the definition of a module, function, class, or method. They are used to document our code. This page will give you a set of guidelines to write efficient and correct docstrings. Formatting the Docstrings ------------------------- Please begin the description of the class/function in the same line as the 3 quotes: .. code:: py def do_this(): """This is correct. (...) """ def dont_do_this(): """ This is incorrect. (...) """ NumPy Format ------------ The Manim Community uses numpy format for the documentation. Use the numpy format for sections and formatting - see https://numpydoc.readthedocs.io/en/latest/format.html. This includes: 1. The usage of ``Attributes`` to specify ALL ATTRIBUTES that a class can have and a brief (or long, if needed) description. Also, ``__init__`` parameters should be specified as ``Parameters`` **on the class docstring**, *rather than under* ``__init__``. Note that this can be omitted if the parameters and the attributes are the same (i.e., dataclass) - priority should be given to the ``Attributes`` section, in this case, which must **always be present**, unless the class specifies no attributes at all. (See more on Parameters in number 2 of this list.) Example: .. code:: py class MyClass: """My cool class. Long or short (whatever is more appropriate) description here. Parameters ---------- name The class's name. id The class's id. mobj The mobject linked to this instance. Defaults to `Mobject()` \ (is set to that if `None` is specified). Attributes ---------- name The user's name. id The user's id. singleton Something. mobj The mobject linked to this instance. """ def __init__(name: str, id: int, singleton: MyClass, mobj: Mobject = None): ... 2. The usage of ``Parameters`` on functions to specify how every parameter works and what it does. This should be excluded if the function has no parameters. Note that you **should not** specify the default value of the parameter on the type. On the documentation render, this is already specified on the function's signature. If you need to indicate a further consequence of value omission or simply want to specify it on the docs, make sure to **specify it in the parameter's DESCRIPTION**. See an example on list item 4. .. note:: When documenting varargs (args and kwargs), make sure to document them by listing the possible types of each value specified, like this: :: Parameters ---------- args The args specified can be either an int or a float. kwargs The kwargs specified can only be a float. Note that, if the kwargs expect specific values, those can be specified in a section such as ``Other Parameters``: :: Other Parameters ---------------- kwarg_param_1 Parameter documentation here (etc) 3. The usage of ``Returns`` to indicate what is the type of this function's return value and what exactly it returns (i.e., a brief - or long, if needed - description of what this function returns). Can be omitted if the function does not explicitly return (i.e., always returns ``None`` because ``return`` is never specified, and it is very clear why this function does not return at all). In all other cases, it should be specified. See an example on list item 4. 4. The usage of ``Examples`` in order to specify an example of usage of a function **is highly encouraged** and, in general, should be specified for *every function* unless its usage is **extremely obvious**, which can be debatable. Even if it is, it's always a good idea to add an example in order to give a better orientation to the documentation user. Use the following format for Python code: .. code:: rst :: # python code here .. note:: Also, if this is a video- or animation-related change, please try to add an example GIF or video if possible for demonstration purposes. Make sure to be as explicit as possible in your documentation. We all want the users to have an easier time using this library. Example: .. code:: py def my_function( thing: int, other: np.ndarray, name: str, *, d: "SomeClassFromFarAway", test: Optional[int] = 45 ) -> "EpicClassInThisFile": # typings are optional for now """My cool function. Builds and modifies an :class:`EpicClassInThisFile` instance with the given parameters. Parameters ---------- thing Specifies the index of life. other Specifies something cool. name Specifies my name. d Sets thing D to this value. test Defines the number of times things should be tested. \ Defaults to 45, because that is almost the meaning of life. Returns ------- :class:`EpicClassInThisFile` The generated EpicClass with the specified attributes and modifications. Examples -------- Normal usage:: my_function(5, np.array([1, 2, 3]), "Chelovek", d=SomeClassFromFarAway(cool=True), test=5) """ # code... pass ================================================ FILE: docs/source/contributing/docs/examples.rst ================================================ =============== Adding Examples =============== This is a page for adding examples to the documentation. Here are some guidelines you should follow before you publish your examples. Guidelines for examples ----------------------- Everybody is welcome to contribute examples to the documentation. Since straightforward examples are a great resource for quickly learning manim, here are some guidelines. What makes a great example -------------------------- .. note:: As soon as a new version of manim is released, the documentation will be a snapshot of that version. Examples contributed after the release will only be shown in the latest documentation. * Examples should be ready to copy and paste for use. * Examples should be brief yet still easy to understand. * Examples don't require the ``from manim import *`` statement, this will be added automatically when the docs are built. * There should be a balance of animated and non-animated examples. - As manim makes animations, we can include lots of animated examples; however, our RTD has a maximum 20 minutes to build. Animated examples should only be used when necessary, as last frame examples render faster. - Lots of examples (e.g. size of a plot-axis, setting opacities, making texts, etc.) will also work as images. It is a lot more convenient to see the end product immediately instead of waiting for an animation to reveal it. * Please ensure the examples run on the current main branch when you contribute an example. * If the functions used are confusing for people, make sure to add comments in the example to explain what they do. How examples are structured --------------------------- * Examples can be organized into chapters and subchapters. - When you create examples, the beginning example chapter should focus on only one functionality. When the functionality is simple, multiple ideas can be illustrated under a single example. - As soon as simple functionalities are explained, the chapter may include more complex examples which build on the simpler ideas. Writing examples ~~~~~~~~~~~~~~~~ When you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in ``rst`` format and use the manim directive (see :mod:`manim.utils.docbuild.manim_directive` ), ``.. manim::``. Every example is in its own block, and looks like this: .. code:: rst Formulas ======== .. manim:: Formula1 :save_last_frame: class Formula1(Scene): def construct(self): t = MathTex(r"\int_a^b f'(x) dx = f(b) - f(a)") self.add(t) self.wait(1) In the building process of the docs, all ``rst`` files are scanned, and the manim directive (``.. manim::``) blocks are identified as scenes that will be run by the current version of manim. Here is the syntax: * ``.. manim:: [SCENE_NAME]`` has no indentation and ``SCENE_NAME`` refers to the name of the class below. * The flags are followed in the next line (no blank line here!), with the indentation level of one tab. All possible flags can be found at :mod:`manim.utils.docbuild.manim_directive`. In the example above, the ``Formula1`` following ``.. manim::`` is the scene that the directive expects to render; thus, in the python code, the class has the same name: ``class Formula1(Scene)``. .. note:: Sometimes, when you reload an example in your browser, it has still the old website somewhere in its cache. If this is the case, delete the website cache, or open a new incognito tab in your browser, then the latest docs should be shown. **Only for locally built documentation:** If this still doesn't work, you may need to delete the contents of ``docs/source/references`` before rebuilding the documentation. ================================================ FILE: docs/source/contributing/docs/references.rst ================================================ ================= Adding References ================= Reference to types in documentation ----------------------------------- Always specify types with the correct **role** (see https://www.sphinx-doc.org/en/1.7/domains.html#python-roles) for the sake of proper rendering. E.g.: Use ``:class:`int``` to refer to an int type, and in general ``:class:``​`` to refer to a certain class (see ``Path specification`` below). See after for more specific instructions. Path specifications ~~~~~~~~~~~~~~~~~~~ 1. If it's on stdlib: Use ```` directly. If it's a class, just the name is enough. If it's a method (``:meth:``) or attribute (``:attr:``), dotted names may be used (e.g. ``:meth:`str.to_lower`​``). Example: ``:class:`int`​``, ``:class:`str`​``, ``:class:`float`​``, ``:class:`bool`​`` 2. If it's on the same file as the docstring or, for methods and attributes, under the same class, then the name may also be specified directly. Example: ``:class:`MyClass`​`` referring to a class in the same file; ``:meth:`push`​`` referring to a method in the same class; ``:meth:`MyClass.push`​`` referring to a method in a different class in the same file; ``:attr:`color`​`` referring to an attribute in the same class; ``:attr:`MyClass.color`​`` referring to an attribute in a different class in the same file. 3. If it's on a different file, then you may either use the full dotted name (e.g. ``~manim.animations.Animation``) or simply use the shortened way (``~.Animation``). Note that, if there is ambiguity, then the full dotted name must be used where the actual class can't be deduced. Also, note the ``~`` before the path - this is so that it displays just ``Animation`` instead of the full location in the rendering. It can be removed for disambiguation purposes only. Example: ``:class:`~.Animation`​``, ``:meth:`~.VMobject.set_color`​``, ``:attr:`~.VMobject.color`​`` 4. If it's a class from a different module, specify the full dotted syntax. Example: ``:class:`numpy.ndarray`​`` for a numpy ndarray. Reference type specifications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **The following instructions refer to types of attributes, parameters, and return values.** When specifying a type mid-text, it does not necessarily have to be typeset. However, if it's a class name, a method, or an enum's attribute/variant, then it is recommended to be typeset at least on the first occurrence of the name so that the users can quickly jump to the related documentation. 1. Class names should be wrapped in ``:class:`path_goes_here`​``. See examples in the subsection above. 2. Method names should be wrapped in ``:meth:`path_goes_here`​``. See examples in the subsection above. 3. Attribute names should be wrapped in ``:attr:`path_goes_here`​``. See examples in the subsection above. 4. If ``None`` can also be specified, use ``Optional[type]``, where ``type`` must follow the guidelines in the current section. Example: ``Optional[:class:`str`]`` means you can either specify a ``str`` or ``None``. 5. If more than one type is possible, use ``Union[type_1, type_2, (...), type_n]``, where all the ``type_n`` must follow the guidelines in the current section. Note that, if one of these types is ``None``, then the Union should be wrapped with ``Optional`` instead. Example: ``Union[:class:`str`, :class:`int`]`` for either ``str`` or ``int``. ``Optional[Union[:class:`int`, :class:`bool`]]`` for either ``int``, ``bool`` or ``None``. 6. **Dictionaries:** Use ``Dict[key_type, value_type]``, where ``key_type`` and ``value_type`` must follow the guidelines in the current section. Example: ``Dict[:class:`str`, :class:`~.Mobject`]`` is a dictionary that maps strings to Mobjects. ``Dict[:class:`str`, Union[:class:`int`, :class:`MyClass`]]`` is a dictionary that maps a string to either an int or an instance of ``MyClass``. 7. **If the parameter is a list:** Note that it is very rare to require the parameter to be exactly a ``list`` type. One could usually specify a ``tuple`` instead, for example. So, in order to cover all cases, consider: 1. If the parameter only needs to be an ``Iterable``, i.e., if the function only requires being able to iterate over this parameter's value (e.g. can be a ``list``, ``tuple``, ``str``, but also ``zip()``, ``iter()`` and so on), then specify ``Iterable[type_here]``, where ``type_here`` is the type of the iterable's yielded elements and should follow the format in the present section (``Type specifications``). Example: ``Iterable[:class:`str`]`` for any iterable of strings; ``Iterable[:class:`~.Mobject`]`` for an iterable of Mobjects; etc. 2. If you require being able to index the parameter (i.e. ``x[n]``) or retrieve its length (i.e. ``len(x)``), or even just pass it to a function that requires any of those, then specify ``Sequence``, which allows any list-like object to be specified (e.g. ``list``, ``tuple``...) Example: ``Sequence[:class:`str`]`` for a sequence of strings; ``Sequence[Union[:class:`str`, :class:`int`]]`` for a sequence of integers or strings. 3. If you EXPLICITLY REQUIRE it to be a ``list`` for some reason, then use ``List[type]``, where ``type`` is the type that any element in the list will have. It must follow the guidelines in the current section. 8. **If the return type is a list or tuple:** Specify ``List[type]`` for a list, ``Tuple[type_a, type_b, (...), type_n]`` for a tuple (if the elements are all different) or ``Tuple[type, ...]`` (if all elements have the same type). Each ``type_n`` on those representations corresponds to elements in the returned list/tuple and must follow the guidelines in the current section. Example: ``List[Optional[:class:`str`]]`` for a list that returns elements that are either a ``str`` or ``None``; ``Tuple[:class:`str`, :class:`int`]`` for a tuple of type ``(str, int)``; ``Tuple[:class:`int`, ...]`` for a tuple of variable length with only integers. ================================================ FILE: docs/source/contributing/docs/types.rst ================================================ =================== Choosing Type Hints =================== In order to provide the best user experience, it's important that type hints are chosen correctly. With the large variety of types provided by Manim, choosing which one to use can be difficult. This guide aims to aid you in the process of choosing the right type for the scenario. The first step is figuring out which category your type hint fits into. Coordinates ----------- Coordinates encompass two main categories: points, and vectors. Points ~~~~~~ The purpose of points is pretty straightforward: they represent a point in space. For example: .. code-block:: python def print_point2D(coord: Point2DLike) -> None: x, y = coord print(f"Point at {x=},{y=}") def print_point3D(coord: Point3DLike) -> None: x, y, z = coord print(f"Point at {x=},{y=},{z=}") def print_point_array(coords: Point2DLike_Array | Point3DLike_Array) -> None: for coord in coords: if len(coord) == 2: # it's a Point2DLike print_point2D(coord) else: # it's a Point3DLike print_point3D(coord) def shift_point_up(coord: Point3DLike) -> Point3D: result = np.asarray(coord) result += UP print(f"New point: {result}") return result Notice that the last function, ``shift_point_up()``, accepts a :class:`~.Point3DLike` as a parameter and returns a :class:`~.Point3D`. A :class:`~.Point3D` always represents a NumPy array consisting of 3 floats, whereas a :class:`~.Point3DLike` can represent anything resembling a 3D point: either a NumPy array or a tuple/list of 3 floats, hence the ``Like`` word. The same happens with :class:`~.Point2D`, :class:`~.Point2D_Array` and :class:`~.Point3D_Array`, and their ``Like`` counterparts :class:`~.Point2DLike`, :class:`~.Point2DLike_Array` and :class:`~.Point3DLike_Array`. The rule for typing functions is: **make parameter types as broad as possible, and return types as specific as possible.** Therefore, for functions which are intended to be called by users, **we should always, if possible, accept** ``Like`` **types as parameters and return NumPy, non-** ``Like`` **types.** The main reason is to be more flexible with users who might want to pass tuples or lists as arguments rather than NumPy arrays, because it's more convenient. The last function, ``shift_point_up()``, is an example of it. Internal functions which are *not* meant to be called by users may accept non-``Like`` parameters if necessary. Vectors ~~~~~~~ Vectors share many similarities to points. However, they have a different connotation. Vectors should be used to represent direction. For example, consider this slightly contrived function: .. code-block:: python M = TypeVar("M", bound=Mobject) # allow any mobject def shift_mobject(mob: M, direction: Vector3D, scale_factor: float = 1) -> M: return mob.shift(direction * scale_factor) Here we see an important example of the difference. ``direction`` should not be typed as a :class:`~.Point3D`, because it represents a direction along which to shift a :class:`~.Mobject`, not a position in space. As a general rule, if a parameter is called ``direction`` or ``axis``, it should be type hinted as some form of :class:`~.VectorND` or :class:`~.VectorNDLike`. Colors ------ The interface Manim provides for working with colors is :class:`.ManimColor`. The main color types Manim supports are RGB, RGBA, and HSV. You will want to add type hints to a function depending on which type it uses. If any color will work, you will need something like: .. code-block:: python if TYPE_CHECKING: from manim.utils.color import ParsableManimColor # type hint stuff with ParsableManimColor Béziers ------- Manim internally represents a :class:`.Mobject` by a collection of points. In the case of :class:`.VMobject`, the most commonly used subclass of :class:`.Mobject`, these points represent Bézier curves, which are a way of representing a curve using a sequence of points. .. note:: To learn more about Béziers, take a look at https://pomax.github.io/bezierinfo/ Manim supports two different renderers, which each have different representations of Béziers: Cairo uses cubic Bézier curves, while OpenGL uses quadratic Bézier curves. Type hints like :class:`~.typing.BezierPoints` represent a single bezier curve, and :class:`~.typing.BezierPath` represents multiple Bézier curves. A :class:`~.typing.Spline` is when the Bézier curves in a :class:`~.typing.BezierPath` forms a single connected curve. Manim also provides more specific type aliases when working with quadratic or cubic curves, and they are prefixed with their respective type (e.g. :class:`~.typing.CubicBezierPoints`, is a :class:`~.typing.BezierPoints` consisting of exactly 4 points representing a cubic Bézier curve). Functions --------- Throughout the codebase, many different types of functions are used. The most obvious example is a rate function, which takes in a float and outputs a float (``Callable[[float], float]``). Another example is for overriding animations. One will often need to map a :class:`.Mobject` to an overridden :class:`.Animation`, and for that we have the :class:`~.typing.FunctionOverride` type hint. :class:`~.typing.PathFuncType` and :class:`~.typing.MappingFunction` are more niche, but are related to moving objects along a path, or applying functions. If you need to use it, you'll know. Images ------ There are several representations of images in Manim. The most common is the representation as a NumPy array of floats representing the pixels of an image. This is especially common when it comes to the OpenGL renderer. This is the use case of the :class:`~.typing.PixelArray` type hint. Sometimes, Manim may use ``PIL.Image.Image``, which is not the same as :class:`~.typing.PixelArray`. In this case, use the ``PIL.Image.Image`` typehint. Of course, if a more specific type of image is needed, it can be annotated as such. ================================================ FILE: docs/source/contributing/docs/typings.rst ================================================ ================== Typing Conventions ================== .. warning:: This section is still a work in progress. Adding type hints to functions and parameters --------------------------------------------- Manim is currently in the process of adding type hints into the library. In this section, you will find information about the standards used and some general guidelines. If you've never used type hints before, this is a good place to get started: https://realpython.com/python-type-checking/#hello-types. Typing standards ~~~~~~~~~~~~~~~~ Manim uses `mypy`_ to type check its codebase. You will find a list of configuration values in the ``mypy.ini`` configuration file. To be able to use the newest typing features not available in the lowest supported Python version, make use of `typing_extensions`_. To be able to use the new Union syntax (``|``) and builtins subscripting, use the ``from __future__ import annotations`` import. .. _mypy: https://mypy-lang.org/ .. _typing_extensions: https://pypi.org/project/typing-extensions/ Typing guidelines ~~~~~~~~~~~~~~~~~ * Manim has a dedicated :mod:`~.typing` module where type aliases are provided. Most of them may seem redundant, in particular the ones related to ``numpy``. This is in anticipation of the support for shape type hinting (`related issue `_). Besides the pending shape support, using the correct type aliases will help users understand which shape should be used. * For typings of generic collections, check out `this `_ link. * Always use a type hint of ``None`` for functions that does not return a value (this also applies to ``__init__``), e.g.: .. code:: py def height(self, value) -> None: self.scale_to_fit_height(value) * For variables representing paths, use the ``StrPath`` or ``StrOrBytesPath`` type alias defined in the :mod:`~.typing` module. * ``*args`` and ``**kwargs`` shouldn't be left untyped (in most cases you can use ``Any``). * Following `PEP 484 `_, use ``float`` instead of ``int | float``. * Use ``x | y`` instead of ``Union[x, y]`` * Mobjects have the typehint ``Mobject``, e.g.: .. code:: py def match_color(self, mobject: "Mobject"): """Match the color with the color of another :class:`~.Mobject`.""" return self.set_color(mobject.get_color()) * Always parametrize generics (``list[int]`` instead of ``list``, ``type[Any]`` instead of ``type``, etc.). This also applies to callables. .. code:: py rate_func: Callable[[float], float] = lambda t: smooth(1 - t) * Use ``TypeVar`` when you want to "link" type hints as being the same type. Consider ``Mobject.copy``, which returns a new instance of the same class. It would be type-hinted as: .. code:: py T = TypeVar("T") def copy(self: T) -> T: ... * Use ``typing.Iterable`` whenever the function works with *any* iterable, not a specific type. * Prefer ``numpy.typing.NDArray`` over ``numpy.ndarray`` .. code:: py import numpy as np if TYPE_CHECKING: import numpy.typing as npt def foo() -> npt.NDArray[float]: return np.array([1, 0, 1]) * If a method returns ``self``, use ``typing_extensions.Self``. .. code:: py if TYPE_CHECKING: from typing_extensions import Self class CustomMobject: def set_color(self, color: ManimColor) -> Self: ... return self * If the function returns a container of a specific length each time, consider using ``tuple`` instead of ``list``. .. code:: py def foo() -> tuple[float, float, float]: return (0, 0, 0) * If a function works with a parameter as long as said parameter has a ``__getitem__``, ``__iter___`` and ``__len__`` method, the typehint of the parameter should be ``collections.abc.Mapping``. If it also supports ``__setitem__`` and/or ``__delitem__``, it should be marked as ``collections.abc.MutableMapping``. * Typehinting something as ``object`` means that only attributes available on every Python object should be accessed, like ``__str__`` and so on. On the other hand, literally any attribute can be accessed on a variable with the ``Any`` typehint - it's more freeing than the ``object`` typehint, and makes mypy stop typechecking the variable. Note that whenever possible, try to keep typehints as specific as possible. * If objects are imported purely for type hint purposes, keep it under an ``if typing.TYPE_CHECKING`` guard, to prevent them from being imported at runtime (helps library performance). Do not forget to use the ``from __future__ import annotations`` import to avoid having runtime ``NameError`` exceptions. .. code:: py from typing import TYPE_CHECKING if TYPE_CHECKING: from manim.typing import Vector3D # type stuff with Vector3D Missing Sections for typehints are: ----------------------------------- * Mypy and numpy import errors: https://realpython.com/python-type-checking/#running-mypy * Explain ``mypy.ini`` (see above link) ================================================ FILE: docs/source/contributing/docs.rst ================================================ ==================== Adding Documentation ==================== Building the documentation -------------------------- When you clone the Manim repository from GitHub, you can access the ``docs/`` folder which contains the necessary files to build the documentation. To build the docs locally, open a CLI, enter the ``docs/`` folder with the ``cd`` command and execute the following depending on your OS: - Windows: ``./make.bat html`` - macOS and Linux: ``make html`` The first time you build the docs, the process will take several minutes because it needs to generate all the ``.rst`` (reST: reStructured Text) files from scratch by reading and parsing all the Manim content. The process becomes much shorter the next time, as it rebuilds only the parts which have changed. Sphinx library and extensions ----------------------------- Manim uses `Sphinx `_ for building the docs. It also makes use of Sphinx extensions such as: - `Autodoc: `_ imports Manim's Python source code, extracts its docstrings and generates documentation from them. - `Autosummary: `_ a complement to Autodoc which adds a special directive ``autosummary``, used in Manim to automatically document classes, methods, attributes, functions, module-level variables and exceptions. Autosummary makes use of `Jinja templates `_, which Manim defines for autosummarizing classes and modules inside ``docs/source/_templates/``. - `Graphviz extension for Sphinx: `_ embeds graphs generated by the `Graphviz `_ module, which must be installed in order to render the inheritance diagrams in the :doc:`/reference`. - `Napoleon: `_ enables Sphinx to read Google style docstrings and, in particular for Manim, `NumPy style docstrings `_ - see :doc:`docs/docstrings` for more information. Sphinx theme ------------ The theme used for this website is `Furo `_. Custom Sphinx directives ------------------------ Manim implements **custom directives** for use with Autodoc and Autosummary, which are defined in :mod:`~.docbuild`: .. currentmodule:: manim.utils.docbuild .. autosummary:: :toctree: ../reference autoaliasattr_directive autocolor_directive manim_directive Index ----- .. toctree:: :maxdepth: 2 docs/admonitions docs/docstrings docs/examples docs/references docs/typings docs/types ================================================ FILE: docs/source/contributing/internationalization.rst ================================================ ==================== Internationalization ==================== Thank you for your interest in localizing Manim! Please read the instructions below to get started. You are also encouraged, though not required, to join our `Discord server `__. Signing up ========== You will first need to create an account for our project. Go to our `project homepage `__ and click the sign up button at the top right hand corner. Follow the instructions to create an account. After creating an account, you should return back to our homepage. Click the Manim project to contribute translations for the main library. Contributing ============ .. important:: Keep in mind that Manim is still a work in progress. Tutorials and documentation are always subject to change. When a developer implements a new feature, they are not forced to respect any translations. This means that parts of the translation might become outdated over time. That being said, improving the documentation and making it more accessible is still highly encouraged. And even if your work gets outdated and requires change, you or someone else can simply adjust the translation. Your efforts are not in vain! Voting ------ To ensure that our translations are of good quality, we use crowdsourcing and voting to approve good translations and reject bad ones. The current threshold for a translation being accepted is 3 votes; this may change as we gauge the level of activity in the community and the quality of translations. To vote on translations, first click on a language you would like to help with, then click the "translate all" button. You should then enter the translation editor. Next to the search bar, you will see a funnel-like icon - click it and select the "Need to Be Voted" option to see translations that need to be voted on. You can then select a string on the left sidebar, view the translations at the bottom and vote with the + and - icons for good and poor translations respectively. Translations ------------ You can also help with contributing translations directly. Follow the steps above to enter the translation editor (instead of clicking "Translate all", you may also choose to translate strings from a specific file by clicking them). Crowdin's on-screen tutorial should guide you through the process. Translation guidelines ====================== In general, follow the conventions for technical writing in your target language. You may want to refer to similar, high quality sources (eg. Python's documentation in your language) for guidance. Note that code blocks, code literals, names and pseudonyms should be left unchanged. Proofreading ============ For certain languages with a significant number of speakers within the Manim Community, an additional step of proofreading is used after crowdsourcing to further ensure the quality of our translations. Proofreaders are trusted community members who will look over and give the final approval on translations. If you would like to be a proofreader, please email translations@manim.community with the answers to the following questions: 1. What is your Crowdin username? 2. What is your Discord username (optional)? 3. What is your GitHub username (optional)? 4. List the languages you speak, and your level of fluency with them. 5. What language(s) are you applying to be a proofreader for? 6. Do you have any previous experience with translations? 7. If yes, give us more details. 8. How will you ensure the quality of translations, should you become a proofreader? Please note that you don't need to have prior translation experience to be a proofreader, just a commitment to maintaining a good quality of translations. Errors ====== Source errors ------------- If you spot an error with a source string, report it to us by opening an :issue:`issue ` on GitHub. Refrain from translating the string until the issue is resolved. ================================================ FILE: docs/source/contributing/performance.rst ================================================ ===================== Improving performance ===================== One of Manim's main flaws as an animation library is its slow performance. As of time of writing (January 2022), the library is still very unoptimized. As such, we highly encourage contributors to help out in optimizing the code. Profiling ========= Before the library can be optimized, we first need to identify the bottlenecks in performance via profiling. There are numerous Python profilers available for this purpose; some examples include cProfile and Scalene. Running an animation as a script -------------------------------- Most instructions for profilers assume you can run the python file directly as a script from the command line. While Manim animations are usually run from the command-line, we can run them as scripts by adding something like the following to the bottom of the file: .. code-block:: python with tempconfig({"quality": "medium_quality", "disable_caching": True}): scene = SceneName() scene.render() Where ``SceneName`` is the name of the scene you want to run. You can then run the file directly, and can thus follow the instructions for most profilers. An example: profiling with cProfile and SnakeViz ------------------------------------------------- Install SnakeViz: .. code-block:: bash pip install snakeviz cProfile is included with in Python's standard library and does not need to be installed. Suppose we want to profile ``SquareToCircle``. Then we add and save the following code to ``square_to_circle.py``: .. code-block:: python from manim import * class SquareToCircle(Scene): def construct(self): s = Square() c = Circle() self.add(s) self.play(Transform(s, c)) with tempconfig({"quality": "medium_quality", "disable_caching": True}): scene = SquareToCircle() scene.render() Now run the following in the terminal: .. code-block:: bash python -m cProfile -o square_to_circle.txt square_to_circle.py This will create a file called ``square_to_circle.txt``. Now, we can run SnakeViz on the profile file: .. code-block:: bash snakeviz square_to_circle.txt A browser window or tab will open with a visualization of the profile, which should look something like this: .. image:: /_static/snakeviz.png ================================================ FILE: docs/source/contributing/testing.rst ================================================ ============ Adding Tests ============ If you are adding new features to manim, you should add appropriate tests for them. Tests prevent manim from breaking at each change by checking that no other feature has been broken and/or been unintentionally modified. .. warning:: The full tests suite requires Cairo 1.18 in order to run all tests. However, Cairo 1.18 may not be available from your package manager, like ``apt``, and it is very likely that you have an older version installed, e.g., 1.16. If you run tests with a version prior to 1.18, many tests will be skipped. Those tests are not skipped in the online CI. If you want to run all tests locally, you need to install Cairo 1.18 or above. You can do so by compiling Cairo from source: 1. download ``cairo-1.18.0.tar.xz`` from `here `_. and uncompress it; 2. open the INSTALL file and follow the instructions (you might need to install ``meson`` and ``ninja``); 3. run the tests suite and verify that the Cairo version is correct. How Manim tests --------------- Manim uses pytest as its testing framework. To start the testing process, go to the root directory of the project and run pytest in your terminal. Any errors that occur during testing will be displayed in the terminal. Some useful pytest flags: - ``-x`` will make pytest stop at the first failure it encounters - ``-s`` will make pytest display all the print messages (including those during scene generation, like DEBUG messages) - ``--skip_slow`` will skip the (arbitrarily) slow tests - ``--show_diff`` will show a visual comparison in case a unit test is failing. How it Works ~~~~~~~~~~~~ At the moment there are three types of tests: #. Unit Tests: Tests for most of the basic functionalities of manim. For example, there a test for ``Mobject``, that checks if it can be added to a Scene, etc. #. Graphical unit tests: Because ``manim`` is a graphics library, we test frames. To do so, we create test scenes that render a specific feature. When pytest runs, it compares the result of the test to the control data, either at 6 fps or just the last frame. If it matches, the tests pass. If the test and control data differ, the tests fail. You can use ``--show_diff`` flag with ``pytest`` to visually see the differences. The ``extract_frames.py`` script lets you see all the frames of a test. #. Videos format tests: As Manim is a video library, we have to test videos as well. Unfortunately, we cannot directly test video content as rendered videos can differ slightly depending on the system (for reasons related to ffmpeg). Therefore, we only compare video configuration values, exported in .json. Architecture ------------ The ``manim/tests`` directory looks like this: :: . ├── conftest.py ├── control_data │ ├── graphical_units_data │ │ ├── creation │ │ │ ├── DrawBorderThenFillTest.npy │ │ │ ├── FadeInFromDownTest.npy │ │ │ ├── FadeInFromLargeTest.npy │ │ │ ├── FadeInFromTest.npy │ │ │ ├── FadeInTest.npy │ │ │ ├── ... │ │ ├── geometry │ │ │ ├── AnnularSectorTest.npy │ │ │ ├── AnnulusTest.npy │ │ │ ├── ArcBetweenPointsTest.npy │ │ │ ├── ArcTest.npy │ │ │ ├── CircleTest.npy │ │ │ ├── CoordinatesTest.npy │ │ │ ├── ... │ │ ├── graph │ │ │ ├── ... | | | | ... │ └── videos_data │ ├── SquareToCircleWithDefaultValues.json │ └── SquareToCircleWithlFlag.json ├── helpers │ ├── graphical_units.py │ ├── __init__.py │ └── video_utils.py ├── __init__.py ├── test_camera.py ├── test_config.py ├── test_copy.py ├── test_vectorized_mobject.py ├── test_graphical_units │ ├── conftest.py │ ├── __init__.py │ ├── test_creation.py │ ├── test_geometry.py │ ├── test_graph.py │ ├── test_indication.py │ ├── test_movements.py │ ├── test_threed.py │ ├── test_transform.py │ └── test_updaters.py ├── test_logging │ ├── basic_scenes.py │ ├── expected.txt │ ├── testloggingconfig.cfg │ └── test_logging.py ├── test_scene_rendering │ ├── conftest.py │ ├── __init__.py │ ├── simple_scenes.py │ ├── standard_config.cfg │ └── test_cli_flags.py └── utils ├── commands.py ├── __init__.py ├── testing_utils.py └── video_tester.py ... The Main Directories -------------------- - ``control_data/``: The directory containing control data. ``control_data/graphical_units_data/`` contains the expected and correct frame data for graphical tests, and ``control_data/videos_data/`` contains the .json files used to check videos. - ``test_graphical_units/``: Contains graphical tests. - ``test_scene_rendering/``: For tests that need to render a scene in some way, such as tests for CLI flags (end-to-end tests). - ``utils/``: Useful internal functions used by pytest. .. note:: fixtures are not contained here, they are in ``conftest.py``. - ``helpers/``: Helper functions for developers to setup graphical/video tests. Adding a New Test ----------------- Unit Tests ~~~~~~~~~~ Pytest determines which functions are tests by searching for files whose names begin with "test\_", and then within those files for functions beginning with "test" and classes beginning with "Test". These kinds of tests must be in ``tests/`` (e.g. ``tests/test_container.py``). Graphical Unit Test ~~~~~~~~~~~~~~~~~~~ The test must be written in the correct file (i.e. the file that corresponds to the appropriate category the feature belongs to) and follow the structure of unit tests. For example, to test the ``Circle`` VMobject which resides in ``manim/mobject/geometry.py``, add the CircleTest to ``test/test_geometry.py``. The name of the module is indicated by the variable __module_test__, that **must** be declared in any graphical test file. The module name is used to store the graphical control data. .. important:: You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a parameter named ``scene`` that will be used like ``self`` in a standard ``construct`` method. Here's an example in ``test_geometry.py``: .. code:: python from manim import * from manim.utils.testing.frames_comparison import frames_comparison __module_test__ = "geometry" @frames_comparison def test_circle(scene): circle = Circle() scene.play(Animation(circle)) The decorator can be used with or without parentheses. **By default, the test only tests the last frame. To enable multi-frame testing, you have to set ``last_frame=False`` in the parameters.** .. code:: python @frames_comparison(last_frame=False) def test_circle(scene): circle = Circle() scene.play(Animation(circle)) You can also specify, when needed, which base scene you need (ThreeDScene, for example) : .. code:: python @frames_comparison(last_frame=False, base_scene=ThreeDScene) def test_circle(scene): circle = Circle() scene.play(Animation(circle)) Feel free to check the documentation of ``@frames_comparison`` for more. Note that tests name must follow the syntax ``test_``, otherwise pytest will not recognize it as a test. .. warning:: If you run pytest now, you will get a ``FileNotFound`` error. This is because you have not created control data for your test. To create the control data for your test, you have to use the flag ``--set_test`` along with pytest. For the example above, it would be .. code-block:: bash pytest test_geometry.py::test_circle --set_test -s (``-s`` is here to see manim logs, so you can see what's going on). If you want to see all the control data frames (e.g. to make sure your test is doing what you want), use the ``extract_frames.py`` script. The first parameter is the path to a ``.npz`` file and the second parameter is the directory you want the frames created. The frames will be named ``frame0.png``, ``frame1.png``, etc. .. code-block:: bash python scripts/extract_frames.py tests/test_graphical_units/control_data/plot/axes.npz output Please make sure to add the control data to git as soon as it is produced with ``git add ``. Videos tests ~~~~~~~~~~~~ To test videos generated, we use the decorator ``tests.utils.videos_tester.video_comparison``: .. code:: python @video_comparison( "SquareToCircleWithlFlag.json", "videos/simple_scenes/480p15/SquareToCircle.mp4" ) def test_basic_scene_l_flag(tmp_path, manim_cfg_file, simple_scenes_path): scene_name = "SquareToCircle" command = [ "python", "-m", "manim", simple_scenes_path, scene_name, "-l", "--media_dir", str(tmp_path), ] out, err, exit_code = capture(command) assert exit_code == 0, err .. note:: ``assert exit*\ code == 0, err`` is used in case of the command fails to run. The decorator takes two arguments: json name and the path to where the video should be generated, starting from the ``media/`` dir. Note the fixtures here: - tmp_path is a pytest fixture to get a tmp_path. Manim will output here, according to the flag ``--media_dir``. - ``manim_cfg_file`` fixture that return a path pointing to ``test_scene_rendering/standard_config.cfg``. It's just to shorten the code, in the case multiple tests need to use this cfg file. - ``simple_scenes_path`` same as above, except for ``test_scene_rendering/simple_scene.py`` You have to generate a ``.json`` file first to be able to test your video. To do that, use ``helpers.save_control_data_from_video``. For instance, a test that will check if the l flag works properly will first require rendering a video using the -l flag from a scene. Then we will test (in this case, SquareToCircle), that lives in ``test_scene_rendering/simple_scene.py``. Change directories to ``tests/``, create a file (e.g. ``create\_data.py``) that you will remove as soon as you're done. Then run: .. code:: python save_control_data_from_video("", "SquareToCircleWithlFlag.json") Running this will save ``control_data/videos_data/SquareToCircleWithlFlag.json``, which will look like this: .. code:: json { "name": "SquareToCircleWithlFlag", "config": { "codec_name": "h264", "width": 854, "height": 480, "avg_frame_rate": "15/1", "duration": "1.000000", "nb_frames": "15" } } If you have any questions, please don't hesitate to ask on `Discord `_, in your pull request, or in an issue. ================================================ FILE: docs/source/contributing.rst ================================================ ############ Contributing ############ .. important:: Manim is currently undergoing a major refactor. In general, contributions implementing new features will not be accepted in this period. Other contributions unrelated to cleaning up the codebase may also take a longer period of time to be reviewed. This guide may quickly become outdated quickly; we highly recommend joining our `Discord server `__ to discuss any potential contributions and keep up to date with the latest developments. Thank you for your interest in contributing to Manim! However you have decided to contribute or interact with the community, please always be civil and respect other members of the community. If you haven't read our :doc:`code of conduct`, do so here. Manim is Free and Open Source Software (FOSS) for mathematical animations. As such, **we welcome everyone** who is interested in mathematics, pedagogy, computer animations, open-source, software development, and beyond. Manim accepts many kinds of contributions, some are detailed below: * Code maintenance and development * DevOps * Documentation * Developing educational content & narrative documentation * Plugins to extend Manim functionality * Testing (graphical, unit & video) * Website design and development * Translating documentation and docstrings To get an overview of what our community is currently working on, check out `our development project board `__. .. note:: Please ensure that you are reading the latest version of this guide by ensuring that "latest" is selected in the version switcher. Contributing can be confusing, so here are a few guides: .. toctree:: :maxdepth: 3 contributing/development contributing/docs contributing/testing contributing/performance contributing/internationalization ================================================ FILE: docs/source/examples.rst ================================================ ############### Example Gallery ############### This gallery contains a collection of best practice code snippets together with their corresponding video/image output, illustrating different functionalities all across the library. These are all under the MIT license, so feel free to copy & paste them to your projects. Enjoy this taste of Manim! .. tip:: This gallery is not the only place in our documentation where you can see explicit code and video examples: there are many more in our :doc:`reference manual ` -- see, for example, our documentation for the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`, and many more. Check out our `interactive Jupyter environment `_ which allows running the examples online, without requiring a local installation. Also, visit our `Twitter `_ for more *manimations*! Basic Concepts ============== .. manim:: ManimCELogo :save_last_frame: :ref_classes: MathTex Circle Square Triangle class ManimCELogo(Scene): def construct(self): self.camera.background_color = "#ece6e2" logo_green = "#87c2a5" logo_blue = "#525893" logo_red = "#e07a5f" logo_black = "#343434" ds_m = MathTex(r"\mathbb{M}", fill_color=logo_black).scale(7) ds_m.shift(2.25 * LEFT + 1.5 * UP) circle = Circle(color=logo_green, fill_opacity=1).shift(LEFT) square = Square(color=logo_blue, fill_opacity=1).shift(UP) triangle = Triangle(color=logo_red, fill_opacity=1).shift(RIGHT) logo = VGroup(triangle, square, circle, ds_m) # order matters logo.move_to(ORIGIN) self.add(logo) .. manim:: BraceAnnotation :save_last_frame: :ref_classes: Brace :ref_methods: Brace.get_text Brace.get_tex class BraceAnnotation(Scene): def construct(self): dot = Dot([-2, -1, 0]) dot2 = Dot([2, 1, 0]) line = Line(dot.get_center(), dot2.get_center()).set_color(ORANGE) b1 = Brace(line) b1text = b1.get_text("Horizontal distance") b2 = Brace(line, direction=line.copy().rotate(PI / 2).get_unit_vector()) b2text = b2.get_tex("x-x_1") self.add(line, dot, dot2, b1, b2, b1text, b2text) .. manim:: VectorArrow :save_last_frame: :ref_classes: Dot Arrow NumberPlane Text class VectorArrow(Scene): def construct(self): dot = Dot(ORIGIN) arrow = Arrow(ORIGIN, [2, 2, 0], buff=0) numberplane = NumberPlane() origin_text = Text('(0, 0)').next_to(dot, DOWN) tip_text = Text('(2, 2)').next_to(arrow.get_end(), RIGHT) self.add(numberplane, dot, arrow, origin_text, tip_text) .. manim:: GradientImageFromArray :save_last_frame: :ref_classes: ImageMobject class GradientImageFromArray(Scene): def construct(self): n = 256 imageArray = np.uint8( [[i * 256 / n for i in range(0, n)] for _ in range(0, n)] ) image = ImageMobject(imageArray).scale(2) image.background_rectangle = SurroundingRectangle(image, color=GREEN) self.add(image, image.background_rectangle) .. manim:: BooleanOperations :ref_classes: Union Intersection Exclusion Difference class BooleanOperations(Scene): def construct(self): ellipse1 = Ellipse( width=4.0, height=5.0, fill_opacity=0.5, color=BLUE, stroke_width=10 ).move_to(LEFT) ellipse2 = ellipse1.copy().set_color(color=RED).move_to(RIGHT) bool_ops_text = MarkupText("Boolean Operation").next_to(ellipse1, UP * 3) ellipse_group = Group(bool_ops_text, ellipse1, ellipse2).move_to(LEFT * 3) self.play(FadeIn(ellipse_group)) i = Intersection(ellipse1, ellipse2, color=GREEN, fill_opacity=0.5) self.play(i.animate.scale(0.25).move_to(RIGHT * 5 + UP * 2.5)) intersection_text = Text("Intersection", font_size=23).next_to(i, UP) self.play(FadeIn(intersection_text)) u = Union(ellipse1, ellipse2, color=ORANGE, fill_opacity=0.5) union_text = Text("Union", font_size=23) self.play(u.animate.scale(0.3).next_to(i, DOWN, buff=union_text.height * 3)) union_text.next_to(u, UP) self.play(FadeIn(union_text)) e = Exclusion(ellipse1, ellipse2, color=YELLOW, fill_opacity=0.5) exclusion_text = Text("Exclusion", font_size=23) self.play(e.animate.scale(0.3).next_to(u, DOWN, buff=exclusion_text.height * 3.5)) exclusion_text.next_to(e, UP) self.play(FadeIn(exclusion_text)) d = Difference(ellipse1, ellipse2, color=PINK, fill_opacity=0.5) difference_text = Text("Difference", font_size=23) self.play(d.animate.scale(0.3).next_to(u, LEFT, buff=difference_text.height * 3.5)) difference_text.next_to(d, UP) self.play(FadeIn(difference_text)) Animations ========== .. manim:: PointMovingOnShapes :ref_classes: Circle Dot Line GrowFromCenter Transform MoveAlongPath Rotating class PointMovingOnShapes(Scene): def construct(self): circle = Circle(radius=1, color=BLUE) dot = Dot() dot2 = dot.copy().shift(RIGHT) self.add(dot) line = Line([3, 0, 0], [5, 0, 0]) self.add(line) self.play(GrowFromCenter(circle)) self.play(Transform(dot, dot2)) self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear) self.play(Rotating(dot, about_point=[2, 0, 0]), run_time=1.5) self.wait() .. manim:: MovingAround :ref_methods: Mobject.shift VMobject.set_fill Mobject.scale Mobject.rotate class MovingAround(Scene): def construct(self): square = Square(color=BLUE, fill_opacity=1) self.play(square.animate.shift(LEFT)) self.play(square.animate.set_fill(ORANGE)) self.play(square.animate.scale(0.3)) self.play(square.animate.rotate(0.4)) .. manim:: MovingAngle :ref_classes: Angle :ref_methods: Mobject.rotate class MovingAngle(Scene): def construct(self): rotation_center = LEFT theta_tracker = ValueTracker(110) line1 = Line(LEFT, RIGHT) line_moving = Line(LEFT, RIGHT) line_ref = line_moving.copy() line_moving.rotate( theta_tracker.get_value() * DEGREES, about_point=rotation_center ) a = Angle(line1, line_moving, radius=0.5, other_angle=False) tex = MathTex(r"\theta").move_to( Angle( line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False ).point_from_proportion(0.5) ) self.add(line1, line_moving, a, tex) self.wait() line_moving.add_updater( lambda x: x.become(line_ref.copy()).rotate( theta_tracker.get_value() * DEGREES, about_point=rotation_center ) ) a.add_updater( lambda x: x.become(Angle(line1, line_moving, radius=0.5, other_angle=False)) ) tex.add_updater( lambda x: x.move_to( Angle( line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False ).point_from_proportion(0.5) ) ) self.play(theta_tracker.animate.set_value(40)) self.play(theta_tracker.animate.increment_value(140)) self.play(tex.animate.set_color(RED), run_time=0.5) self.play(theta_tracker.animate.set_value(350)) .. tip:: You can use multiple ValueTrackers simultaneously. .. manim:: MovingDots class MovingDots(Scene): def construct(self): d1,d2=Dot(color=BLUE),Dot(color=GREEN) dg=VGroup(d1,d2).arrange(RIGHT,buff=1) l1=Line(d1.get_center(),d2.get_center()).set_color(RED) x=ValueTracker(0) y=ValueTracker(0) d1.add_updater(lambda z: z.set_x(x.get_value())) d2.add_updater(lambda z: z.set_y(y.get_value())) l1.add_updater(lambda z: z.become(Line(d1.get_center(),d2.get_center()))) self.add(d1,d2,l1) self.play(x.animate.set_value(5)) self.play(y.animate.set_value(4)) self.wait() .. manim:: MovingGroupToDestination class MovingGroupToDestination(Scene): def construct(self): group = VGroup(Dot(LEFT), Dot(ORIGIN), Dot(RIGHT, color=RED), Dot(2 * RIGHT)).scale(1.4) dest = Dot([4, 3, 0], color=YELLOW) self.add(group, dest) self.play(group.animate.shift(dest.get_center() - group[2].get_center())) self.wait(0.5) .. manim:: MovingFrameBox :ref_modules: manim.mobject.svg.tex_mobject :ref_classes: MathTex SurroundingRectangle class MovingFrameBox(Scene): def construct(self): text=MathTex( "\\frac{d}{dx}f(x)g(x)=","f(x)\\frac{d}{dx}g(x)","+", "g(x)\\frac{d}{dx}f(x)" ) self.play(Write(text)) framebox1 = SurroundingRectangle(text[1], buff = .1) framebox2 = SurroundingRectangle(text[3], buff = .1) self.play( Create(framebox1), ) self.wait() self.play( ReplacementTransform(framebox1,framebox2), ) self.wait() .. manim:: RotationUpdater :ref_methods: Mobject.add_updater Mobject.remove_updater class RotationUpdater(Scene): def construct(self): def updater_forth(mobj, dt): mobj.rotate_about_origin(dt) def updater_back(mobj, dt): mobj.rotate_about_origin(-dt) line_reference = Line(ORIGIN, LEFT).set_color(WHITE) line_moving = Line(ORIGIN, LEFT).set_color(YELLOW) line_moving.add_updater(updater_forth) self.add(line_reference, line_moving) self.wait(2) line_moving.remove_updater(updater_forth) line_moving.add_updater(updater_back) self.wait(2) line_moving.remove_updater(updater_back) self.wait(0.5) .. manim:: PointWithTrace :ref_classes: Rotating :ref_methods: VMobject.set_points_as_corners Mobject.add_updater class PointWithTrace(Scene): def construct(self): path = VMobject() dot = Dot() path.set_points_as_corners([dot.get_center(), dot.get_center()]) def update_path(path): previous_path = path.copy() previous_path.add_points_as_corners([dot.get_center()]) path.become(previous_path) path.add_updater(update_path) self.add(path, dot) self.play(Rotating(dot, angle=PI, about_point=RIGHT, run_time=2)) self.wait() self.play(dot.animate.shift(UP)) self.play(dot.animate.shift(LEFT)) self.wait() Plotting with Manim =================== .. manim:: SinAndCosFunctionPlot :save_last_frame: :ref_modules: manim.mobject.coordinate_systems :ref_classes: MathTex :ref_methods: Axes.plot Axes.get_vertical_line_to_graph Axes.input_to_graph_point Axes.get_axis_labels class SinAndCosFunctionPlot(Scene): def construct(self): axes = Axes( x_range=[-10, 10.3, 1], y_range=[-1.5, 1.5, 1], x_length=10, axis_config={"color": GREEN}, x_axis_config={ "numbers_to_include": np.arange(-10, 10.01, 2), "numbers_with_elongated_ticks": np.arange(-10, 10.01, 2), }, tips=False, ) axes_labels = axes.get_axis_labels() sin_graph = axes.plot(lambda x: np.sin(x), color=BLUE) cos_graph = axes.plot(lambda x: np.cos(x), color=RED) sin_label = axes.get_graph_label( sin_graph, "\\sin(x)", x_val=-10, direction=UP / 2 ) cos_label = axes.get_graph_label(cos_graph, label="\\cos(x)") vert_line = axes.get_vertical_line( axes.i2gp(TAU, cos_graph), color=YELLOW, line_func=Line ) line_label = axes.get_graph_label( cos_graph, r"x=2\pi", x_val=TAU, direction=UR, color=WHITE ) plot = VGroup(axes, sin_graph, cos_graph, vert_line) labels = VGroup(axes_labels, sin_label, cos_label, line_label) self.add(plot, labels) .. manim:: ArgMinExample class ArgMinExample(Scene): def construct(self): ax = Axes( x_range=[0, 10], y_range=[0, 100, 10], axis_config={"include_tip": False} ) labels = ax.get_axis_labels(x_label="x", y_label="f(x)") t = ValueTracker(0) def func(x): return 2 * (x - 5) ** 2 graph = ax.plot(func, color=MAROON) initial_point = [ax.coords_to_point(t.get_value(), func(t.get_value()))] dot = Dot(point=initial_point) dot.add_updater(lambda x: x.move_to(ax.c2p(t.get_value(), func(t.get_value())))) x_space = np.linspace(*ax.x_range[:2],200) minimum_index = func(x_space).argmin() self.add(ax, labels, graph, dot) self.play(t.animate.set_value(x_space[minimum_index])) self.wait() .. manim:: GraphAreaPlot :save_last_frame: :ref_modules: manim.mobject.coordinate_systems :ref_methods: Axes.plot Axes.get_vertical_line_to_graph Axes.get_area Axes.get_axis_labels class GraphAreaPlot(Scene): def construct(self): ax = Axes( x_range=[0, 5], y_range=[0, 6], x_axis_config={"numbers_to_include": [2, 3]}, tips=False, ) labels = ax.get_axis_labels() curve_1 = ax.plot(lambda x: 4 * x - x ** 2, x_range=[0, 4], color=BLUE_C) curve_2 = ax.plot( lambda x: 0.8 * x ** 2 - 3 * x + 4, x_range=[0, 4], color=GREEN_B, ) line_1 = ax.get_vertical_line(ax.input_to_graph_point(2, curve_1), color=YELLOW) line_2 = ax.get_vertical_line(ax.i2gp(3, curve_1), color=YELLOW) riemann_area = ax.get_riemann_rectangles(curve_1, x_range=[0.3, 0.6], dx=0.03, color=BLUE, fill_opacity=0.5) area = ax.get_area(curve_2, [2, 3], bounded_graph=curve_1, color=GREY, opacity=0.5) self.add(ax, labels, curve_1, curve_2, line_1, line_2, riemann_area, area) .. manim:: PolygonOnAxes :ref_classes: Axes Polygon class PolygonOnAxes(Scene): def get_rectangle_corners(self, bottom_left, top_right): return [ (top_right[0], top_right[1]), (bottom_left[0], top_right[1]), (bottom_left[0], bottom_left[1]), (top_right[0], bottom_left[1]), ] def construct(self): ax = Axes( x_range=[0, 10], y_range=[0, 10], x_length=6, y_length=6, axis_config={"include_tip": False}, ) t = ValueTracker(5) k = 25 graph = ax.plot( lambda x: k / x, color=YELLOW_D, x_range=[k / 10, 10.0, 0.01], use_smoothing=False, ) def get_rectangle(): polygon = Polygon( *[ ax.c2p(*i) for i in self.get_rectangle_corners( (0, 0), (t.get_value(), k / t.get_value()) ) ] ) polygon.stroke_width = 1 polygon.set_fill(BLUE, opacity=0.5) polygon.set_stroke(YELLOW_B) return polygon polygon = always_redraw(get_rectangle) dot = Dot() dot.add_updater(lambda x: x.move_to(ax.c2p(t.get_value(), k / t.get_value()))) dot.set_z_index(10) self.add(ax, graph, dot) self.play(Create(polygon)) self.play(t.animate.set_value(10)) self.play(t.animate.set_value(k / 10)) self.play(t.animate.set_value(5)) .. manim:: HeatDiagramPlot :save_last_frame: :ref_modules: manim.mobject.coordinate_systems :ref_methods: Axes.plot_line_graph Axes.get_axis_labels class HeatDiagramPlot(Scene): def construct(self): ax = Axes( x_range=[0, 40, 5], y_range=[-8, 32, 5], x_length=9, y_length=6, x_axis_config={"numbers_to_include": np.arange(0, 40, 5)}, y_axis_config={"numbers_to_include": np.arange(-5, 34, 5)}, tips=False, ) labels = ax.get_axis_labels( x_label=Tex(r"$\Delta Q$"), y_label=Tex(r"T[$^\circ C$]") ) x_vals = [0, 8, 38, 39] y_vals = [20, 0, 0, -5] graph = ax.plot_line_graph(x_values=x_vals, y_values=y_vals) self.add(ax, labels, graph) Special Camera Settings ======================= .. manim:: FollowingGraphCamera :ref_modules: manim.scene.moving_camera_scene :ref_classes: MovingCameraScene MoveAlongPath Restore :ref_methods: Axes.plot Mobject.add_updater class FollowingGraphCamera(MovingCameraScene): def construct(self): self.camera.frame.save_state() # create the axes and the curve ax = Axes(x_range=[-1, 10], y_range=[-1, 10]) graph = ax.plot(lambda x: np.sin(x), color=BLUE, x_range=[0, 3 * PI]) # create dots based on the graph moving_dot = Dot(ax.i2gp(graph.t_min, graph), color=ORANGE) dot_1 = Dot(ax.i2gp(graph.t_min, graph)) dot_2 = Dot(ax.i2gp(graph.t_max, graph)) self.add(ax, graph, dot_1, dot_2, moving_dot) self.play(self.camera.frame.animate.scale(0.5).move_to(moving_dot)) def update_curve(mob): mob.move_to(moving_dot.get_center()) self.camera.frame.add_updater(update_curve) self.play(MoveAlongPath(moving_dot, graph, rate_func=linear)) self.camera.frame.remove_updater(update_curve) self.play(Restore(self.camera.frame)) .. manim:: MovingZoomedSceneAround :ref_modules: manim.scene.zoomed_scene :ref_classes: ZoomedScene BackgroundRectangle UpdateFromFunc :ref_methods: Mobject.add_updater ZoomedScene.get_zoomed_display_pop_out_animation class MovingZoomedSceneAround(ZoomedScene): # contributed by TheoremofBeethoven, www.youtube.com/c/TheoremofBeethoven def __init__(self, **kwargs): ZoomedScene.__init__( self, zoom_factor=0.3, zoomed_display_height=1, zoomed_display_width=6, image_frame_stroke_width=20, zoomed_camera_config={ "default_frame_stroke_width": 3, }, **kwargs ) def construct(self): dot = Dot().shift(UL * 2) image = ImageMobject(np.uint8([[0, 100, 30, 200], [255, 0, 5, 33]])) image.height = 7 frame_text = Text("Frame", color=PURPLE, font_size=67) zoomed_camera_text = Text("Zoomed camera", color=RED, font_size=67) self.add(image, dot) zoomed_camera = self.zoomed_camera zoomed_display = self.zoomed_display frame = zoomed_camera.frame zoomed_display_frame = zoomed_display.display_frame frame.move_to(dot) frame.set_color(PURPLE) zoomed_display_frame.set_color(RED) zoomed_display.shift(DOWN) zd_rect = BackgroundRectangle(zoomed_display, fill_opacity=0, buff=MED_SMALL_BUFF) self.add_foreground_mobject(zd_rect) unfold_camera = UpdateFromFunc(zd_rect, lambda rect: rect.replace(zoomed_display)) frame_text.next_to(frame, DOWN) self.play(Create(frame), FadeIn(frame_text, shift=UP)) self.activate_zooming() self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera) zoomed_camera_text.next_to(zoomed_display_frame, DOWN) self.play(FadeIn(zoomed_camera_text, shift=UP)) # Scale in x y z scale_factor = [0.5, 1.5, 0] self.play( frame.animate.scale(scale_factor), zoomed_display.animate.scale(scale_factor), FadeOut(zoomed_camera_text), FadeOut(frame_text) ) self.wait() self.play(ScaleInPlace(zoomed_display, 2)) self.wait() self.play(frame.animate.shift(2.5 * DOWN)) self.wait() self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera, rate_func=lambda t: smooth(1 - t)) self.play(Uncreate(zoomed_display_frame), FadeOut(frame)) self.wait() .. manim:: FixedInFrameMObjectTest :save_last_frame: :ref_classes: ThreeDScene :ref_methods: ThreeDScene.set_camera_orientation ThreeDScene.add_fixed_in_frame_mobjects class FixedInFrameMObjectTest(ThreeDScene): def construct(self): axes = ThreeDAxes() self.set_camera_orientation(phi=75 * DEGREES, theta=-45 * DEGREES) text3d = Text("This is a 3D text") self.add_fixed_in_frame_mobjects(text3d) text3d.to_corner(UL) self.add(axes) self.wait() .. manim:: ThreeDLightSourcePosition :save_last_frame: :ref_classes: ThreeDScene ThreeDAxes Surface :ref_methods: ThreeDScene.set_camera_orientation class ThreeDLightSourcePosition(ThreeDScene): def construct(self): axes = ThreeDAxes() sphere = Surface( lambda u, v: np.array([ 1.5 * np.cos(u) * np.cos(v), 1.5 * np.cos(u) * np.sin(v), 1.5 * np.sin(u) ]), v_range=[0, TAU], u_range=[-PI / 2, PI / 2], checkerboard_colors=[RED_D, RED_E], resolution=(15, 32) ) self.renderer.camera.light_source.move_to(3*IN) # changes the source of the light self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(axes, sphere) .. manim:: ThreeDCameraRotation :ref_classes: ThreeDScene ThreeDAxes :ref_methods: ThreeDScene.begin_ambient_camera_rotation ThreeDScene.stop_ambient_camera_rotation class ThreeDCameraRotation(ThreeDScene): def construct(self): axes = ThreeDAxes() circle=Circle() self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(circle,axes) self.begin_ambient_camera_rotation(rate=0.1) self.wait() self.stop_ambient_camera_rotation() self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES) self.wait() .. manim:: ThreeDCameraIllusionRotation :ref_classes: ThreeDScene ThreeDAxes :ref_methods: ThreeDScene.begin_3dillusion_camera_rotation ThreeDScene.stop_3dillusion_camera_rotation class ThreeDCameraIllusionRotation(ThreeDScene): def construct(self): axes = ThreeDAxes() circle=Circle() self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(circle,axes) self.begin_3dillusion_camera_rotation(rate=2) self.wait(PI/2) self.stop_3dillusion_camera_rotation() .. manim:: ThreeDSurfacePlot :save_last_frame: :ref_classes: ThreeDScene Surface class ThreeDSurfacePlot(ThreeDScene): def construct(self): resolution_fa = 24 self.set_camera_orientation(phi=75 * DEGREES, theta=-30 * DEGREES) def param_gauss(u, v): x = u y = v sigma, mu = 0.4, [0.0, 0.0] d = np.linalg.norm(np.array([x - mu[0], y - mu[1]])) z = np.exp(-(d ** 2 / (2.0 * sigma ** 2))) return np.array([x, y, z]) gauss_plane = Surface( param_gauss, resolution=(resolution_fa, resolution_fa), v_range=[-2, +2], u_range=[-2, +2] ) gauss_plane.scale(2, about_point=ORIGIN) gauss_plane.set_style(fill_opacity=1,stroke_color=GREEN) gauss_plane.set_fill_by_checkerboard(ORANGE, BLUE, opacity=0.5) axes = ThreeDAxes() self.add(axes,gauss_plane) Advanced Projects ================= .. manim:: OpeningManim :ref_classes: Tex MathTex Write FadeIn LaggedStart NumberPlane Create :ref_methods: NumberPlane.prepare_for_nonlinear_transform class OpeningManim(Scene): def construct(self): title = Tex(r"This is some \LaTeX") basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}") VGroup(title, basel).arrange(DOWN) self.play( Write(title), FadeIn(basel, shift=DOWN), ) self.wait() transform_title = Tex("That was a transform") transform_title.to_corner(UP + LEFT) self.play( Transform(title, transform_title), LaggedStart(*[FadeOut(obj, shift=DOWN) for obj in basel]), ) self.wait() grid = NumberPlane() grid_title = Tex("This is a grid", font_size=72) grid_title.move_to(transform_title) self.add(grid, grid_title) # Make sure title is on top of grid self.play( FadeOut(title), FadeIn(grid_title, shift=UP), Create(grid, run_time=3, lag_ratio=0.1), ) self.wait() grid_transform_title = Tex( r"That was a non-linear function \\ applied to the grid" ) grid_transform_title.move_to(grid_title, UL) grid.prepare_for_nonlinear_transform() self.play( grid.animate.apply_function( lambda p: p + np.array( [ np.sin(p[1]), np.sin(p[0]), 0, ] ) ), run_time=3, ) self.wait() self.play(Transform(grid_title, grid_transform_title)) self.wait() .. manim:: SineCurveUnitCircle :ref_classes: MathTex Circle Dot Line VGroup :ref_methods: Mobject.add_updater Mobject.remove_updater :ref_functions: always_redraw class SineCurveUnitCircle(Scene): # contributed by heejin_park, https://infograph.tistory.com/230 def construct(self): self.show_axis() self.show_circle() self.move_dot_and_draw_curve() self.wait() def show_axis(self): x_start = np.array([-6,0,0]) x_end = np.array([6,0,0]) y_start = np.array([-4,-2,0]) y_end = np.array([-4,2,0]) x_axis = Line(x_start, x_end) y_axis = Line(y_start, y_end) self.add(x_axis, y_axis) self.add_x_labels() self.origin_point = np.array([-4,0,0]) self.curve_start = np.array([-3,0,0]) def add_x_labels(self): x_labels = [ MathTex(r"\pi"), MathTex(r"2 \pi"), MathTex(r"3 \pi"), MathTex(r"4 \pi"), ] for i in range(len(x_labels)): x_labels[i].next_to(np.array([-1 + 2*i, 0, 0]), DOWN) self.add(x_labels[i]) def show_circle(self): circle = Circle(radius=1) circle.move_to(self.origin_point) self.add(circle) self.circle = circle def move_dot_and_draw_curve(self): orbit = self.circle origin_point = self.origin_point dot = Dot(radius=0.08, color=YELLOW) dot.move_to(orbit.point_from_proportion(0)) self.t_offset = 0 rate = 0.25 def go_around_circle(mob, dt): self.t_offset += (dt * rate) # print(self.t_offset) mob.move_to(orbit.point_from_proportion(self.t_offset % 1)) def get_line_to_circle(): return Line(origin_point, dot.get_center(), color=BLUE) def get_line_to_curve(): x = self.curve_start[0] + self.t_offset * 4 y = dot.get_center()[1] return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 ) self.curve = VGroup() self.curve.add(Line(self.curve_start,self.curve_start)) def get_curve(): last_line = self.curve[-1] x = self.curve_start[0] + self.t_offset * 4 y = dot.get_center()[1] new_line = Line(last_line.get_end(),np.array([x,y,0]), color=YELLOW_D) self.curve.add(new_line) return self.curve dot.add_updater(go_around_circle) origin_to_circle_line = always_redraw(get_line_to_circle) dot_to_curve_line = always_redraw(get_line_to_curve) sine_curve_line = always_redraw(get_curve) self.add(dot) self.add(orbit, origin_to_circle_line, dot_to_curve_line, sine_curve_line) self.wait(8.5) dot.remove_updater(go_around_circle) ================================================ FILE: docs/source/faq/general.md ================================================ # FAQ: General Usage ## Why does Manim say that "there are no scenes inside that module"? There are two main reasons why this error appears: if you have edited the file containing your `Scene` class and forgot to save it, or if you have accidentally passed the name of a wrong file to `manim`, this is a likely outcome. Check that you have spelled everything correctly. Otherwise, you are likely mixing up Manim versions. See {ref}`this FAQ answer ` for an explanation regarding why there are different versions. Under the assumption that you are trying to use the `manim` executable from the terminal to run a scene that has been written for the community version (i.e., there is `from manim import *`, or more specifically `from manim import Scene`), then this error indicates that the `manim` executable has been overwritten by the one provided by `manimgl` (unfortunately, both `manim` and `manimgl` provide a `manim` executable). You can check whether this is the case by running `manim --version`, the output of the community maintained version starts with `Manim Community v...`. If this is not the case, you are running `manimgl`. You can resolve this by either of the following steps: - Un- and reinstalling `manim`, - using the `manimce` executable in place of the `manim` one, - or replacing the call to the executable with a direct call to the Python module via `python -m manim`. --- ## No matter what code I put in my file, Manim only renders a black frame! Why? If you are using the usual pattern to write a `Scene`, i.e., ```python class MyAwesomeScene(Scene): def construct(self): ... # your animation code ``` then double check whether you have spelled `construct` correctly. If the method containing your code is not called `construct` (or if you are not calling a different, custom method from `construct`), Manim will not call your method and simply output a black frame. --- ## What are the default measurements for Manim's scene? The scene measures 8 units in height and has a default ratio of 16:9, which means that it measures {math}`8 \cdot 16 / 9 = 14 + 2/9` units in width. The origin is in the center of the scene, which means that, for example, the upper left corner of the scene has coordinates `[-7-1/9, 4, 0]`. --- ## How do I find out which keyword arguments I can pass when creating a `Mobject`? Let us consider a specific example, like the {class}`.Circle` class. When looking at its documentation page, only two specific keyword arguments are listed (`radius`, and `color`). Besides these concrete arguments, there is also a catchall `**kwargs` argument which captures all other arguments that are passed to `Circle`, and passes them on to the base class of {class}`.Circle`, {class}`.Arc`. The same holds for {class}`.Arc`: some arguments are explicitly documented, and there is again a catchall `**kwargs` argument that passes unprocessed arguments to the next base class -- and so on. The most important keyword arguments relevant to styling your mobjects are the ones that are documented for the base classes {class}`.VMobject` and {class}`.Mobject`. --- ## Can Manim render a video with transparent background? Yes: simply pass the CLI flag `-t` (or its long form `--transparent`). Note that the default video file format does not support transparency, which is why Manim will output a `.mov` instead of a `.mp4` when rendering with a transparent background. Other movie file formats that support transparency can be obtained by passing `--format=webm` or `--format=gif`. --- ## I have watched a video where a creator ran command X, but it does not work for me. Why? The video you have been watching is likely outdated. If you want to follow along, you either need to use the same version used in the video, or modify the code (in many cases it is just a method having been renamed etc.) accordingly. Check the video description, in some cases creators point out whether changes need to be applied to the code shown in the video. --- ## When using `Tex` or `MathTex`, some letters are missing. How can I fix this? It is possible that you have to (re)build some fonts used by LaTeX. For some distributions, you can do this manually by running ```bash fmtutil -sys --all ``` We recommend consulting the documentation of your LaTeX distribution for more information. --- ## I want to translate some code from `manimgl` to `manim`, what do I do with `CONFIG` dictionaries? The community-maintained version has dropped the use of `CONFIG` dictionaries very early, with {doc}`version v0.2.0 ` released in January 2021. Before that, Manim's classes basically processed `CONFIG` dictionaries by mimicking inheritance (to properly process `CONFIG` dictionaries set by parent classes) and then assigning all of the key-value-pairs in the dictionary as attributes of the corresponding object. In situations where there is not much inheritance going on, or for any custom setting, you should set these attributes yourself. For example, for an old-style `Scene` with custom attributes like ```python class OldStyle(Scene): CONFIG = {"a": 1, "b": 2} ``` should be written as ```python class NewStyle(Scene): a = 1 b = 2 ``` In situations where values should be properly inherited, the arguments should be added to the initialization function of the class. An old-style mobject `Thing` could look like ```python class Thing(VMobject): CONFIG = { "stroke_color": RED, "fill_opacity": 0.7, "my_awesome_argument": 42, } ``` where `stroke_color` and `fill_opacity` are arguments that concern the parent class of `Thing`, and `my_awesome_argument` is a custom argument that only concerns `Thing`. A version without `CONFIG` could look like this: ```python class Thing(VMobject): def __init__( self, stroke_color=RED, fill_opacity=0.7, my_awesome_argument=42, **kwargs ): self.my_awesome_argument = my_awesome_argument super().__init__(stroke_color=stroke_color, fill_opacity=fill_opacity, **kwargs) ``` --- ## My installation does not support converting PDF to SVG, help? This is an issue with `dvisvgm`, the tool shipped with LaTeX that transforms LaTeX output to a `.svg` file that Manim can parse. First, make sure your ``dvisvgm`` version is at least 2.4 by checking the output of ```bash dvisvgm --version ``` If you do not know how to update `dvisvgm`, please refer to your LaTeX distributions documentation (or the documentation of your operating system, if `dvisvgm` was installed as a system package). Second, check whether your ``dvisvgm`` supports PostScript specials. This is needed to convert from PDF to SVG. Run: ```bash dvisvgm -l ``` If the output to this command does **not** contain `ps dvips PostScript specials`, this is a bad sign. In this case, run ```bash dvisvgm -h ``` If the output does **not** contain `--libgs=filename`, this means your `dvisvgm` does not currently support PostScript. You must get another binary. If, however, `--libgs=filename` appears in the help, that means that your `dvisvgm` needs the Ghostscript library to support PostScript. Search for `libgs.so` (on Linux, probably in `/usr/local/lib` or `/usr/lib`) or `gsdll32.dll` (on 32-bit Windows, probably in `C:\windows\system32`) or `gsdll64.dll` (on 64-bit Windows, also probably in `C:\windows\system32`) or `libgsl.dylib` (on MacOS, probably in `/usr/local/lib` or `/opt/local/lib`). Please look carefully, as the file might be located elsewhere, e.g. in the directory where Ghostscript is installed. When you have found the library, try (on MacOS or Linux) ```bash export LIBGS= dvisvgm -l ``` or (on Windows) ```bat set LIBGS= dvisvgm -l ``` You should now see `ps dvips PostScript specials` in the output. Refer to your operating system's documentation to find out how you can set or export the environment variable ``LIBGS`` automatically whenever you open a shell. As a last check, you can run ```bash dvisvgm -V1 ``` (while still having `LIBGS` set to the correct path, of course.) If `dvisvgm` can find your Ghostscript installation, it will be shown in the output together with the version number. If you do not have the necessary library on your system, please refer to your operating system's documentation to find out where you can get it and how you have to install it. If you are unable to solve your problem, check out the [dvisvgm FAQ](https://dvisvgm.de/FAQ/). --- ## Where can I find more resources for learning Manim? In our [Discord server](https://manim.community/discord), we have the community-maintained `#beginner-resources` channel in which links to helpful learning resources are collected. You are welcome to join our Discord and take a look yourself! If you have found some guides or tutorials yourself that are not on our list yet, feel free to add them! ================================================ FILE: docs/source/faq/help.md ================================================ # FAQ: Getting Help ## How do I animate X? Why do I get error Y? Can someone help me? Before asking the community, please make sure that the issue you are having is not already discussed in our {doc}`FAQ section ` sufficiently well so that you can resolve the problem yourself. You can also try to use your favorite search engine, if you are lucky you might find a blog post, a question on [StackOverflow](https://stackoverflow.com/questions/tagged/manim), or a post in the [r/manim subreddit](https://reddit.com/r/manim). If this is not the case, please take a moment to properly prepare your question: the better you manage to explain what exactly it is you are struggling with, the more efficient people will be able to help you. Regardless of the platform you choose in the next step, StackOverflow has a good guide on [asking good questions](https://stackoverflow.com/help/how-to-ask). As soon as you have a good idea of what exactly you want to ask, pick one of the following communication channels: - The community is most active [in our Discord server](https://manim.community/discord/). Click the link to join, then pick one of the `#manim-help` channels in the sidebar, and post your question there. If you are comfortable with using Discord, try to search for your problem using the search function of our server; perhaps people have been talking about it before! - We are also monitoring questions on [StackOverflow](https://stackoverflow.com/questions/tagged/manim) that are tagged with `manim`. - Many people are also active in our [r/manim subreddit](https://reddit.com/r/manim), feel free to post there if you are an avid Redditor -- but be aware that Discord or StackOverflow might be better choices. - And finally, you can also start a new [discussion on GitHub](https://github.com/ManimCommunity/manim/discussions) if you dislike all other options. In all of these channels, please make sure to abide by Manim's {doc}`Code of Conduct ` -- in short, be *excellent* to one another: be friendly and patient, considerate, and respectful. --- ## What should I do if nobody answers my question? Try and see whether your question can be improved: did you include all relevant information (in case of errors: the full stack trace, the code that you were rendering, and the command you used to run Manim?). In case you used a very long example, is it possible to construct a more minimal version that has the same (faulty) behavior? If you posted in one of our help channels on Discord and your question got buried, you are allowed to ping the `@Manim Helper` role to bring it to the attention of the volunteers who are willing to take a look. Please refrain from pinging the role immediately when asking your question for the first time, this is considered impolite. You can also try to post your question to a different channel if you feel that you are not having any success with your initial choice -- but please do not spam your question in all of our communication channels (and in particular for Discord: please don't use multiple help channels at once). In the end, it is as for most open-source projects: our community members are volunteers. If you do not receive a quick answer to your question, it may be because nobody knows the answer, or because your question is not clear enough, or it could be that everyone who can help you with your problem is busy doing other things. --- ## The library does not behave as documented, or something broke in a new release. What should I do? Sounds like you have found a bug. One of the best ways of contributing to the development of Manim is by reporting it! Check our list of known issues and feature requests [in our GitHub repository](https://github.com/ManimCommunity/manim/issues). If the problem you have found is not listed there yet (use the search function; also check whether there is a corresponding closed issue, it is possible that your problem has already been resolved and will be fixed with the next release), please consider the following steps to submit a new issue. ```{note} If you are unsure whether or not you should file a new issue for some odd behavior that you found, feel free to ask the community developers, preferably in one of our `#manim-dev` channels in [our Discord](https://manim.community/discord/). ``` 1. Make sure you are running the latest released version of Manim, your problem might otherwise already be fixed in a more recent version. Check the {doc}`/changelog` for a full list of changes between Manim releases. 2. Choose the correct category for your report when [creating a new issue](https://github.com/ManimCommunity/manim/issues/new/choose). We have dedicated issue templates for *bug reports*, *feature requests*, and *installation issues*. If your report falls into one of these categories, read the issue template carefully! Instructions are given in the `` sections of the text field. If you want to suggest a new feature without concrete implementation details, see {ref}`the instructions given in this answer `. 3. For bug reports: prepare a minimal example that can be used to illustrate the issue. Examples with hundreds of lines are very inefficient and tedious to debug. Your problem needs to be reproducible for others, so please make sure to prepare a suitable example. 4. This is mentioned in the bug report template as well, but it is very important: if you report that some code raises an error, make sure to include the full terminal output, from the command you used to run the library up to and including the last line with the error message. Read carefully: if the message mentions that there is another relevant log file, include this other file as well! --- (creating-suggestions)= ## I have an idea for a really cool feature that should be implemented, where should I share my idea? New suggestions and proposals should be made by [creating a new discussion](https://github.com/ManimCommunity/manim/discussions/new?category=suggestions-and-proposals) in the [*Suggestions and Proposals* category](https://github.com/ManimCommunity/manim/discussions/categories/suggestions-and-proposals) in our GitHub repository. Once the raw idea has been formed into a more concrete, implementable proposal that is supported by the community, and someone has expressed interest in working on the new feature, a corresponding [issue](https://github.com/ManimCommunity/manim/issues) will be created. Do **not** create issues for suggesting new features directly, they will be closed down. ================================================ FILE: docs/source/faq/index.rst ================================================ Frequently Asked Questions ========================== .. toctree:: :caption: Table of Contents :maxdepth: 2 :glob: * ================================================ FILE: docs/source/faq/installation.md ================================================ # FAQ: Installation (different-versions)= ## Why are there different versions of Manim? Manim was originally created by Grant Sanderson as a personal project and for use in his YouTube channel, [3Blue1Brown](https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw). As his channel gained popularity, many grew to like the style of his animations and wanted to use manim for their own projects. However, as manim was only intended for personal use, it was very difficult for other users to install and use it. In late 2019, Grant started working on faster OpenGL rendering in a new branch, known as the `shaders` branch. In mid-2020, a group of developers forked it into what is now the community edition; this is the version documented on this website. In early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository -- and this is what `manimgl` is. The old version, before merging the `shaders` branch is sometimes referred to as `ManimCairo` and is, at this point, only useful for one singular purpose: rendering Grant's old videos locally on your machine. It is still available in his GitHub repository in form of the `cairo-backend` branch. To summarize: - [**Manim**, or **ManimCE**](https://manim.community) refers to the community maintained version of the library. This is the version documented on this website; the package name on PyPI is [`manim`](https://pypi.org/project/manim/). - [ManimGL](https://github.com/3b1b/manim) is the latest released version of the version of the library developed by Grant "3b1b" Sanderson. It has more experimental features and breaking changes between versions are not documented. Check out its documentation [here](https://3b1b.github.io/manim/index.html); on PyPI the package name is [`manimgl`](https://pypi.org/project/manimgl/). - [ManimCairo](https://github.com/3b1b/manim/tree/cairo-backend) is the name that is sometimes used for the old, pre-OpenGL version of `manimgl`. The latest version of it is available [on PyPI as `manimlib`](https://pypi.org/project/manimgl/), but note that if you intend to use it to compile some old project of Grant, you will likely have to install the exact version from the time the project was created from source. --- ## Which version should I use? We recommend the community maintained version especially for beginners. It has been developed to be more stable, better tested and documented (!), and quicker to respond to community contributions. It is also perfectly reasonable to start learning with the community maintained version and then switch to a different version later on. If you do not care so much about documentation or stability, and would like to use the exact same version that Grant is using, then use ManimGL. And as mentioned above, ManimCairo should only be used for (re)rendering old 3Blue1Brown projects (basically 2019 and before). --- ## What are the differences between Manim, ManimGL, ManimCairo? Can I tell for which version a scene was written for? You can! The thing that usually gives it away is the `import` statement at the top of the file; depending on how the code imports Manim you can tell for which version of the code it was written for: - If the code imports from `manim` (i.e., `from manim import *`, `import manim as mn`, etc.), then the code you are reading is supposed to be run with the community maintained version. - If the import reads `import manimlib` (or `from manimlib import *`), you are likely reading a file to be rendered with ManimGL. - And if the import reads `from manimlib.imports import *`, or perhaps even `from big_ol_pile_of_manim_imports import *` you are reading a snippet that is supposed to be rendered with an early, or very early version of ManimCairo, respectively. --- ## How do I know which version of Manim I have installed? Assuming you can run `manim` in your terminal and there is some output, check the first line of the text being produced. If you are using the community maintained version, the first line of any output will be `Manim Community `. If it does not say that, you are likely using ManimGL. You can also check the list of packages you have installed: if typing `python` in your terminal spawns the interpreter that corresponds to the Python installation you use (might also be `py`, or `python3`, depending on your operating system), running `python -m pip list` will print a list of all installed packages. Check whether `manim` or `manimgl` appear in that list. Similarly, you can use `python -m pip install ` and `python -m pip uninstall ` to install and uninstall packages from that list, respectively. --- ## I am following the video guide X to install Manim, but some step fails. What do I do? It is only natural that there are many video guides on installing Manim out there, given that Manim is a library used for creating videos. Unfortunately however, (YouTube) videos can't be updated easily (without uploading a new one, that is) when some step in the installation process changes, and so there are many **severely outdated** resources out there. This is why we strongly recommend following our {doc}`written installation guide ` to guide you through the process. In case you prefer using a video guide regardless, please check whether the creator whose guide you have been watching has made a more recent version available, and otherwise please contact them directly. Asking for help in the community will likely lead to being suggested to follow our written guide. --- ## Why does ManimPango fail to install when running `pip install manim`? This most likely means that pip was not able to use our pre-built wheels of the `manimpango` dependency. Let us know (via [Discord](https://www.manim.community/discord/) or by opening a [new issue on GitHub](https://github.com/ManimCommunity/ManimPango/issues/new)) which architecture you would like to see supported, and we'll see what we can do about it. To fix errors when installing `manimpango`, you need to make sure you have all the necessary build requirements. Check out the detailed instructions given in [the BUILDING section](https://github.com/ManimCommunity/ManimPango#BUILDING) of [ManimPango's README](https://github.com/ManimCommunity/ManimPango). --- (not-on-path)= ## I am using Windows and get the error `X is not recognized as an internal or external command, operable program or batch file` If you have followed {doc}`our local installation instructions ` and have not activated the corresponding virtual environment, make sure to use `uv run manim ...` instead of just `manim` (or activate the virtual environment by following the instructions printed when running `uv venv`). Otherwise there is a problem with the directories where your system is looking for executables (the `PATH` variable). If `python` is recognized, you can try running commands by prepending `python -m`. That is, `manim` becomes `python -m manim`, and `pip` becomes `python -m pip`. Otherwise see [this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121) to get help with editing the `PATH` variable manually. --- ## I have tried using Chocolatey (`choco install manimce`) to install Manim, but it failed! Make sure that you were running the command with administrator permissions, otherwise there can be problems. If this is not the issue, read Chocolatey's output carefully, it should mention a `.log` file containing information why the process failed. You are welcome to take this file (and any other input you feel might be relevant) and submit it to Manim's community to ask for help with your problem. See the {doc}`FAQ on getting help ` for instructions. --- ## On Windows, when typing `python` or `python3` the Windows store is opened, can I fix this? Yes: you can remove these aliases with these steps: 1. Go to the Windows Setting. 2. Under *Apps and Features* you will find application execution aliases. 3. Within this menu, disable the alias(es) that are causing the issue (`python` and/or `python3`). --- ## I am using Anaconda and get an `ImportError` mentioning that some Symbol is not found. This is because Anaconda environments come with their own preinstalled version of `cairo` which is not compatible with the version of `pycairo` required by Manim. Usually it can be fixed by running ```bash conda install -c conda-forge pycairo ``` --- ## How can I fix the error that `manimpango/cmanimpango.c` could not be found when trying to install Manim? This occasionally happens when your system has to build a wheel for [ManimPango](https://github.com/ManimCommunity/ManimPango) locally because there is no compatible version for your architecture available on PyPI. Very often, the problem is resolved by installing Cython (e.g., via `pip3 install Cython`) and then trying to reinstall Manim. If this does not fix it: - Make sure that you have installed all build dependencies mentioned in [ManimPango's README](https://github.com/ManimCommunity/ManimPango), - and if you still run into troubles after that, please reach out to us as described in the {doc}`Getting Help FAQs `. ================================================ FILE: docs/source/faq/internals.md ================================================ # Where can I learn more about Manim's internal structure? Efforts to document the internal structure of Manim is ongoing on our [wiki](https://github.com/ManimCommunity/manim/wiki/Developer-documentation-(WIP)). Keep in mind that since this is a work in progress, the information you find may be incomplete, outdated or even wrong. Still, it should serve as a good starting point. The wiki is open for anyone to edit, feel free to add information or even questions directly on the wiki pages. ================================================ FILE: docs/source/faq/opengl.md ================================================ # FAQ: OpenGL rendering ## Are there any resources on how the OpenGL renderer in the community maintained version can be used? Yes. Unfortunately, at this point, the official online documentation does not contain the relevant base classes like `OpenGLMobject` and `OpenGLVMobject` or specific OpenGL classes like `OpenGLSurface`, but documentation for some of them is available in form of docstrings [in the source code](https://github.com/ManimCommunity/manim/tree/main/manim/mobject/opengl). Furthermore, [this user guide by *aquabeam*](https://web.archive.org/web/20250708135737/https://www.aquabeam.me/manim/opengl_guide/) can be helpful to get started using the OpenGL renderer. --- ## I am trying to run an interactive scene with `--renderer=opengl` and `Scene.interactive_embed`, but an error (`sqlite3.ProgrammingError`) is raised. How can I fix this? This seems to be an issue with a recent IPython release, in our experience it helps to downgrade the installed `IPython` package to `8.0.1`: `pip install IPython==8.0.1`. ================================================ FILE: docs/source/guides/add_voiceovers.rst ================================================ ########################### Adding Voiceovers to Videos ########################### Creating a full-fledged video with voiceovers is a bit more involved than creating purely visual Manim scenes. One has to use `a video editing program `__ to add the voiceovers after the video has been rendered. This process can be difficult and time-consuming, since it requires a lot of planning and preparation. To ease the process of adding voiceovers to videos, we have created `Manim Voiceover `__, a plugin that lets you add voiceovers to scenes directly in Python. To install it, run .. code-block:: bash pip install "manim-voiceover[azure,gtts]" Visit `the installation page `__ for more details on how to install Manim Voiceover. Basic Usage ########### Manim Voiceover lets you ... - Add voiceovers to Manim videos directly in Python, without having to use a video editor. - Record voiceovers with your microphone during rendering through a simple command line interface. - Develop animations with auto-generated AI voices from various free and proprietary services. It provides a very simple API that lets you specify your voiceover script and then record it during rendering: .. code-block:: python from manim import * from manim_voiceover import VoiceoverScene from manim_voiceover.services.recorder import RecorderService # Simply inherit from VoiceoverScene instead of Scene to get all the # voiceover functionality. class RecorderExample(VoiceoverScene): def construct(self): # You can choose from a multitude of TTS services, # or in this example, record your own voice: self.set_speech_service(RecorderService()) circle = Circle() # Surround animation sections with with-statements: with self.voiceover(text="This circle is drawn as I speak.") as tracker: self.play(Create(circle), run_time=tracker.duration) # The duration of the animation is received from the audio file # and passed to the tracker automatically. # This part will not start playing until the previous voiceover is finished. with self.voiceover(text="Let's shift it to the left 2 units.") as tracker: self.play(circle.animate.shift(2 * LEFT), run_time=tracker.duration) To get started with Manim Voiceover, visit the `Quick Start Guide `__. Visit the `Example Gallery `__ to see some examples of Manim Voiceover in action. ================================================ FILE: docs/source/guides/configuration.rst ================================================ Configuration ############# Manim provides an extensive configuration system that allows it to adapt to many different use cases. There are many configuration options that can be configured at different times during the scene rendering process. Each option can be configured programmatically via `the ManimConfig class`_, at the time of command invocation via `command-line arguments`_, or at the time the library is first imported via `the config files`_. The most common, simplest, and recommended way to configure Manim is via the command-line interface (CLI), which is described directly below. Command-line arguments ********************** By far the most commonly used command in the CLI is the ``render`` command, which is used to render scene(s) to an output file. It is used with the following arguments: .. program-output:: manim render --help :ellipsis: 9 However, since Manim defaults to the :code:`render` command whenever no command is specified, the following form is far more common and can be used instead: .. code-block:: bash manim [OPTIONS] FILE [SCENES] An example of using the above form is: .. code-block:: bash manim -qm file.py SceneOne This asks Manim to search for a Scene class called :code:`SceneOne` inside the file ``file.py`` and render it with medium quality (specified by the ``-qm`` flag). Another frequently used flag is ``-p`` ("preview"), which makes manim open the rendered video after it's done rendering. .. note:: The ``-p`` flag does not change any properties of the global ``config`` dict. The ``-p`` flag is only a command-line convenience. Advanced examples ================= To render a scene in high quality, but only output the last frame of the scene instead of the whole video, you can execute .. code-block:: bash manim -sqh SceneName The following example specifies the output file name (with the :code:`-o` flag), renders only the first ten animations (:code:`-n` flag) with a white background (:code:`-c` flag), and saves the animation as a ``.gif`` instead of as a ``.mp4`` file (``--format=gif`` flag). It uses the default quality and does not try to open the file after it is rendered. .. code-block:: bash manim -o myscene --format=gif -n 0,10 -c WHITE SceneName A list of all CLI flags ======================== .. command-output:: manim --help .. command-output:: manim render --help .. command-output:: manim cfg --help .. command-output:: manim plugins --help The ManimConfig class ********************* The most direct way of configuring Manim is through the global ``config`` object, which is an instance of :class:`.ManimConfig`. Each property of this class is a config option that can be accessed either with standard attribute syntax or with dict-like syntax: .. code-block:: pycon >>> from manim import * >>> config.background_color = WHITE >>> config["background_color"] = WHITE .. note:: The former is preferred; the latter is provided for backwards compatibility. Most classes, including :class:`.Camera`, :class:`.Mobject`, and :class:`.Animation`, read some of their default configuration from the global ``config``. .. code-block:: pycon >>> Camera({}).background_color >>> config.background_color = RED # 0xfc6255 >>> Camera({}).background_color :class:`.ManimConfig` is designed to keep internal consistency. For example, setting ``frame_y_radius`` will affect ``frame_height``: .. code-block:: pycon >>> config.frame_height 8.0 >>> config.frame_y_radius = 5.0 >>> config.frame_height 10.0 The global ``config`` object is meant to be the single source of truth for all config options. All of the other ways of setting config options ultimately change the values of the global ``config`` object. The following example illustrates the video resolution chosen for examples rendered in our documentation with a reference frame. .. manim:: ShowScreenResolution :save_last_frame: class ShowScreenResolution(Scene): def construct(self): pixel_height = config["pixel_height"] # 1080 is default pixel_width = config["pixel_width"] # 1920 is default frame_width = config["frame_width"] frame_height = config["frame_height"] self.add(Dot()) d1 = Line(frame_width * LEFT / 2, frame_width * RIGHT / 2).to_edge(DOWN) self.add(d1) self.add(Text(str(pixel_width)).next_to(d1, UP)) d2 = Line(frame_height * UP / 2, frame_height * DOWN / 2).to_edge(LEFT) self.add(d2) self.add(Text(str(pixel_height)).next_to(d2, RIGHT)) The config files **************** As the last example shows, executing Manim from the command line may involve using many flags simultaneously. This may become a nuisance if you must execute the same script many times in a short time period, for example, when making small incremental tweaks to your scene script. For this reason, Manim can also be configured using a configuration file. A configuration file is a file ending with the suffix ``.cfg``. To use a local configuration file when rendering your scene, you must create a file with the name ``manim.cfg`` in the same directory as your scene code. .. warning:: The config file **must** be named ``manim.cfg``. Currently, Manim does not support config files with any other name. The config file must start with the section header ``[CLI]``. The configuration options under this header have the same name as the CLI flags and serve the same purpose. Take, for example, the following config file. .. code-block:: ini [CLI] # my config file output_file = myscene save_as_gif = True background_color = WHITE Config files are parsed with the standard python library ``configparser``. In particular, they will ignore any line that starts with a pound symbol ``#``. Now, executing the following command .. code-block:: bash manim -o myscene -i -c WHITE SceneName is equivalent to executing the following command, provided that ``manim.cfg`` is in the same directory as , .. code-block:: bash manim SceneName .. tip:: The names of the configuration options admissible in config files are exactly the same as the **long names** of the corresponding command- line flags. For example, the ``-c`` and ``--background_color`` flags are interchangeable, but the config file only accepts :code:`background_color` as an admissible option. Since config files are meant to replace CLI flags, all CLI flags can be set via a config file. Moreover, any config option can be set via a config file, whether or not it has an associated CLI flag. See the bottom of this document for a list of all CLI flags and config options. Manim will look for a ``manim.cfg`` config file in the same directory as the file being rendered, and **not** in the directory of execution. For example, .. code-block:: bash manim -o myscene -i -c WHITE SceneName will use the config file found in ``path/to/file.py``, if any. It will **not** use the config file found in the current working directory, even if it exists. In this way, the user may keep different config files for different scenes or projects, and execute them with the right configuration from anywhere in the system. The file described here is called the **folder-wide** config file because it affects all scene scripts found in the same folder. The user config file ==================== As explained in the previous section, a :code:`manim.cfg` config file only affects the scene scripts in its same folder. However, the user may also create a special config file that will apply to all scenes rendered by that user. This is referred to as the **user-wide** config file, and it will apply regardless of where Manim is executed from, and regardless of where the scene script is stored. The user-wide config file lives in a special folder, depending on the operating system. * Windows: :code:`UserDirectory`/AppData/Roaming/Manim/manim.cfg * MacOS: :code:`UserDirectory`/.config/manim/manim.cfg * Linux: :code:`UserDirectory`/.config/manim/manim.cfg Here, :code:`UserDirectory` is the user's home folder. .. note:: A user may have many **folder-wide** config files, one per folder, but only one **user-wide** config file. Different users in the same computer may each have their own user-wide config file. .. warning:: Do not store scene scripts in the same folder as the user-wide config file. In this case, the behavior is undefined. Whenever you use Manim from anywhere in the system, Manim will look for a user-wide config file and read its configuration. Cascading config files ====================== What happens if you execute Manim and it finds both a folder-wide config file and a user-wide config file? Manim will read both files, but if they are incompatible, **the folder-wide file takes precedence**. For example, take the following user-wide config file .. code-block:: ini # user-wide [CLI] output_file = myscene save_as_gif = True background_color = WHITE and the following folder-wide file .. code-block:: ini # folder-wide [CLI] save_as_gif = False Then, executing :code:`manim SceneName` will be equivalent to not using any config files and executing .. code-block:: bash manim -o myscene -c WHITE SceneName Any command-line flags have precedence over any config file. For example, using the previous two config files and executing :code:`manim -c RED SceneName` is equivalent to not using any config files and executing .. code-block:: bash manim -o myscene -c RED SceneName There is also a **library-wide** config file that determines Manim's default behavior and applies to every user of the library. It has the least precedence, so any config options in the user-wide and any folder-wide files will override the library-wide file. This is referred to as the *cascading* config file system. .. warning:: **The user should not try to modify the library-wide file**. Contributors should receive explicit confirmation from the core developer team before modifying it. Order of operations ******************* .. raw:: html
With so many different ways of configuring Manim, it can be difficult to know when each config option is being set. In fact, this will depend on how Manim is being used. If Manim is imported from a module, then the configuration system will follow these steps: 1. The library-wide config file is loaded. 2. The user-wide and folder-wide files are loaded if they exist. 3. All files found in the previous two steps are parsed in a single :class:`ConfigParser` object, called ``parser``. This is where *cascading* happens. 4. :class:`logging.Logger` is instantiated to create Manim's global ``logger`` object. It is configured using the "logger" section of the parser, i.e. ``parser['logger']``. 5. :class:`ManimConfig` is instantiated to create the global ``config`` object. 6. The ``parser`` from step 3 is fed into the ``config`` from step 5 via :meth:`ManimConfig.digest_parser`. 7. Both ``logger`` and ``config`` are exposed to the user. If Manim is being invoked from the command line, all of the previous steps happen, and are complemented by: 8. The CLI flags are parsed and fed into ``config`` via :meth:`~ManimConfig.digest_args`. 9. If the ``--config_file`` flag was used, a new :class:`ConfigParser` object is created with the contents of the library-wide file, the user-wide file if it exists, and the file passed via ``--config_file``. In this case, the folder-wide file, if it exists, is ignored. 10. The new parser is fed into ``config``. 11. The rest of the CLI flags are processed. To summarize, the order of precedence for configuration options, from lowest to highest precedence is: 1. Library-wide config file, 2. user-wide config file, if it exists, 3. folder-wide config file, if it exists OR custom config file, if passed via ``--config_file``, 4. other CLI flags, and 5. any programmatic changes made after the config system is set. A list of all config options **************************** .. code:: ['aspect_ratio', 'assets_dir', 'background_color', 'background_opacity', 'bottom', 'custom_folders', 'disable_caching', 'dry_run', 'ffmpeg_loglevel', 'flush_cache', 'frame_height', 'frame_rate', 'frame_size', 'frame_width', 'frame_x_radius', 'frame_y_radius', 'from_animation_number', `fullscreen`, 'images_dir', 'input_file', 'left_side', 'log_dir', 'log_to_file', 'max_files_cached', 'media_dir', 'media_width', 'movie_file_extension', 'notify_outdated_version', 'output_file', 'partial_movie_dir', 'pixel_height', 'pixel_width', 'plugins', 'preview', 'progress_bar', 'quality', 'right_side', 'save_as_gif', 'save_last_frame', 'save_pngs', 'scene_names', 'show_in_file_browser', 'sound', 'tex_dir', 'tex_template', 'tex_template_file', 'text_dir', 'top', 'transparent', 'upto_animation_number', 'use_opengl_renderer', 'verbosity', 'video_dir', 'window_position', 'window_monitor', 'window_size', 'write_all', 'write_to_movie', 'enable_wireframe', 'force_window'] Accessing CLI command options ***************************** Entering ``manim``, or ``manim --help``, will open the main help page. .. code:: Usage: manim [OPTIONS] COMMAND [ARGS]... Animation engine for explanatory math videos. Options: --version Show version and exit. --help Show this message and exit. Commands: cfg Manages Manim configuration files. init Sets up a new project in current working directory with default settings. It copies files from templates directory and pastes them in the current working dir. new Create a new project or insert a new scene. plugins Manages Manim plugins. render Render SCENE(S) from the input FILE. See 'manim ' to read about a specific subcommand. Made with <3 by Manim Community developers. Each of the subcommands has its own help page which can be accessed similarly: .. code:: manim render manim render --help ================================================ FILE: docs/source/guides/deep_dive.rst ================================================ A deep dive into Manim's internals ================================== **Author:** `Benjamin Hackl `__ .. admonition:: Disclaimer This guide reflects the state of the library as of version ``v0.16.0`` and primarily treats the Cairo renderer. The situation in the latest version of Manim might be different; in case of substantial deviations we will add a note below. Introduction ------------ Manim can be a wonderful library, if it behaves the way you would like it to, and/or the way you expect it to. Unfortunately, this is not always the case (as you probably know if you have played with some manimations yourself already). To understand where things *go wrong*, digging through the library's source code is sometimes the only option -- but in order to do that, you need to know where to start digging. This article is intended as some sort of life line through the render process. We aim to give an appropriate amount of detail describing what happens when Manim reads your scene code and produces the corresponding animation. Throughout this article, we will focus on the following toy example:: from manim import * class ToyExample(Scene): def construct(self): orange_square = Square(color=ORANGE, fill_opacity=0.5) blue_circle = Circle(color=BLUE, fill_opacity=0.5) self.add(orange_square) self.play(ReplacementTransform(orange_square, blue_circle, run_time=3)) small_dot = Dot() small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN)) self.play(Create(small_dot)) self.play(blue_circle.animate.shift(RIGHT)) self.wait() self.play(FadeOut(blue_circle, small_dot)) Before we go into details or even look at the rendered output of this scene, let us first describe verbally what happens in this *manimation*. In the first three lines of the ``construct`` method, a :class:`.Square` and a :class:`.Circle` are initialized, then the square is added to the scene. The first frame of the rendered output should thus show an orange square. Then the actual animations happen: the square first transforms into a circle, then a :class:`.Dot` is created (Where do you guess the dot is located when it is first added to the scene? Answering this already requires detailed knowledge about the render process.). The dot has an updater attached to it, and as the circle moves right, the dot moves with it. In the end, all mobjects are faded out. Actually rendering the code yields the following video: .. manim:: ToyExample :hide_source: class ToyExample(Scene): def construct(self): orange_square = Square(color=ORANGE, fill_opacity=0.5) blue_circle = Circle(color=BLUE, fill_opacity=0.5) self.add(orange_square) self.play(ReplacementTransform(orange_square, blue_circle, run_time=3)) small_dot = Dot() small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN)) self.play(Create(small_dot)) self.play(blue_circle.animate.shift(RIGHT)) self.wait() self.play(FadeOut(blue_circle, small_dot)) For this example, the output (fortunately) coincides with our expectations. Overview -------- Because there is a lot of information in this article, here is a brief overview discussing the contents of the following chapters on a very high level. - `Preliminaries`_: In this chapter we unravel all the steps that take place to prepare a scene for rendering; right until the point where the user-overridden ``construct`` method is ran. This includes a brief discussion on using Manim's CLI versus other means of rendering (e.g., via Jupyter notebooks, or in your Python script by calling the :meth:`.Scene.render` method yourself). - `Mobject Initialization`_: For the second chapter we dive into creating and handling Mobjects, the basic elements that should be displayed in our scene. We discuss the :class:`.Mobject` base class, how there are essentially three different types of Mobjects, and then discuss the most important of them, vectorized Mobjects. In particular, we describe the internal point data structure that governs how the mechanism responsible for drawing the vectorized Mobject to the screen sets the corresponding Bézier curves. We conclude the chapter with a tour into :meth:`.Scene.add`, the bookkeeping mechanism controlling which mobjects should be rendered. - `Animations and the Render Loop`_: And finally, in the last chapter we walk through the instantiation of :class:`.Animation` objects (the blueprints that hold information on how Mobjects should be modified when the render loop runs), followed by a investigation of the infamous :meth:`.Scene.play` call. We will see that there are three relevant parts in a :meth:`.Scene.play` call; a part in which the passed animations and keyword arguments are processed and prepared, followed by the actual "render loop" in which the library steps through a time line and renders frame by frame. The final part does some post-processing to save a short video segment ("partial movie file") and cleanup for the next call to :meth:`.Scene.play`. In the end, after all of :meth:`.Scene.construct` has been run, the library combines the partial movie files to one video. And with that, let us get *in medias res*. Preliminaries ------------- Importing the library ^^^^^^^^^^^^^^^^^^^^^ Independent of how exactly you are telling your system to render the scene, i.e., whether you run ``manim -qm -p file_name.py ToyExample``, or whether you are rendering the scene directly from the Python script via a snippet like :: with tempconfig({"quality": "medium_quality", "preview": True}): scene = ToyExample() scene.render() or whether you are rendering the code in a Jupyter notebook, you are still telling your python interpreter to import the library. The usual pattern used to do this is :: from manim import * which (while being a debatable strategy in general) imports a lot of classes and functions shipped with the library and makes them available in your global name space. I explicitly avoided stating that it imports **all** classes and functions of the library, because it does not do that: Manim makes use of the practice described in `Section 6.4.1 of the Python tutorial `__, and all module members that should be exposed to the user upon running the ``*``-import are explicitly declared in the ``__all__`` variable of the module. Manim also uses this strategy internally: taking a peek at the file that is run when the import is called, ``__init__.py`` (see `here `__), you will notice that most of the code in that module is concerned with importing members from various different submodules, again using ``*``-imports. .. hint:: If you would ever contribute a new submodule to Manim, the main ``__init__.py`` is where it would have to be listed in order to make its members accessible to users after importing the library. In that file, there is one particular import at the beginning of the file however, namely:: from ._config import * This initializes Manim's global configuration system, which is used in various places throughout the library. After the library runs this line, the current configuration options are set. The code in there takes care of reading the options in your ``.cfg`` files (all users have at least the global one that is shipped with the library) as well as correctly handling command line arguments (if you used the CLI to render). You can read more about the config system in the :doc:`corresponding thematic guide `, and if you are interested in learning more about the internals of the configuration system and how it is initialized, follow the code flow starting in `the config module's init file `__. Now that the library is imported, we can turn our attention to the next step: reading your scene code (which is not particularly exciting, Python just creates a new class ``ToyExample`` based on our code; Manim is virtually not involved in that step, with the exception that ``ToyExample`` inherits from ``Scene``). However, with the ``ToyExample`` class created and ready to go, there is a new excellent question to answer: how is the code in our ``construct`` method actually executed? Scene instantiation and rendering ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The answer to this question depends on how exactly you are running the code. To make things a bit clearer, let us first consider the case that you have created a file ``toy_example.py`` which looks like this:: from manim import * class ToyExample(Scene): def construct(self): orange_square = Square(color=ORANGE, fill_opacity=0.5) blue_circle = Circle(color=BLUE, fill_opacity=0.5) self.add(orange_square) self.play(ReplacementTransform(orange_square, blue_circle, run_time=3)) small_dot = Dot() small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN)) self.play(Create(small_dot)) self.play(blue_circle.animate.shift(RIGHT)) self.wait() self.play(FadeOut(blue_circle, small_dot)) with tempconfig({"quality": "medium_quality", "preview": True}): scene = ToyExample() scene.render() With such a file, the desired scene is rendered by simply running this Python script via ``python toy_example.py``. Then, as described above, the library is imported and Python has read and defined the ``ToyExample`` class (but, read carefully: *no instance of this class has been created yet*). At this point, the interpreter is about to enter the ``tempconfig`` context manager. Even if you have not seen Manim's ``tempconfig`` before, its name already suggests what it does: it creates a copy of the current state of the configuration, applies the changes to the key-value pairs in the passed dictionary, and upon leaving the context the original version of the configuration is restored. TL;DR: it provides a fancy way of temporarily setting configuration options. Inside the context manager, two things happen: an actual ``ToyExample``-scene object is instantiated, and the ``render`` method is called. Every way of using Manim ultimately does something along of these lines, the library always instantiates the scene object and then calls its ``render`` method. To illustrate that this really is the case, let us briefly look at the two most common ways of rendering scenes: **Command Line Interface.** When using the CLI and running the command ``manim -qm -p toy_example.py ToyExample`` in your terminal, the actual entry point is Manim's ``__main__.py`` file (located `here `__. Manim uses `Click `__ to implement the command line interface, and the corresponding code is located in Manim's ``cli`` module (https://github.com/ManimCommunity/manim/tree/main/manim/cli). The corresponding code creating the scene class and calling its render method is located `here `__. **Jupyter notebooks.** In Jupyter notebooks, the communication with the library is handled by the ``%%manim`` magic command, which is implemented in the ``manim.utils.ipython_magic`` module. There is :meth:`some documentation <.ManimMagic.manim>` available for the magic command, and the code creating the scene class and calling its render method is located `here `__. Now that we know that either way, a :class:`.Scene` object is created, let us investigate what Manim does when that happens. When instantiating our scene object :: scene = ToyExample() the ``Scene.__init__`` method is called, given that we did not implement our own initialization method. Inspecting the corresponding code (see `here `__) reveals that ``Scene.__init__`` first sets several attributes of the scene objects that do not depend on any configuration options set in ``config``. Then the scene inspects the value of ``config.renderer``, and based on its value, either instantiates a ``CairoRenderer`` or an ``OpenGLRenderer`` object and assigns it to its ``renderer`` attribute. The scene then asks its renderer to initialize the scene by calling :: self.renderer.init_scene(self) Inspecting both the default Cairo renderer and the OpenGL renderer shows that the ``init_scene`` method effectively makes the renderer instantiate a :class:`.SceneFileWriter` object, which basically is Manim's interface to ``libav`` (FFMPEG) and actually writes the movie file. The Cairo renderer (see the implementation `here `__) does not require any further initialization. The OpenGL renderer does some additional setup to enable the realtime rendering preview window, which we do not go into detail further here. .. warning:: Currently, there is a lot of interplay between a scene and its renderer. This is a flaw in Manim's current architecture, and we are working on reducing this interdependency to achieve a less convoluted code flow. After the renderer has been instantiated and initialized its file writer, the scene populates further initial attributes (notable mention: the ``mobjects`` attribute which keeps track of the mobjects that have been added to the scene). It is then done with its instantiation and ready to be rendered. The rest of this article is concerned with the last line in our toy example script:: scene.render() This is where the actual magic happens. Inspecting the `implementation of the render method `__ reveals that there are several hooks that can be used for pre- or postprocessing a scene. Unsurprisingly, :meth:`.Scene.render` describes the full *render cycle* of a scene. During this life cycle, there are three custom methods whose base implementation is empty and that can be overwritten to suit your purposes. In the order they are called, these customizable methods are: - :meth:`.Scene.setup`, which is intended for preparing and, well, *setting up* the scene for your animation (e.g., adding initial mobjects, assigning custom attributes to your scene class, etc.), - :meth:`.Scene.construct`, which is the *script* for your screen play and contains programmatic descriptions of your animations, and - :meth:`.Scene.tear_down`, which is intended for any operations you might want to run on the scene after the last frame has already been rendered (for example, this could run some code that generates a custom thumbnail for the video based on the state of the objects in the scene -- this hook is more relevant for situations where Manim is used within other Python scripts). After these three methods are run, the animations have been fully rendered, and Manim calls :meth:`.CairoRenderer.scene_finished` to gracefully complete the rendering process. This checks whether any animations have been played -- and if so, it tells the :class:`.SceneFileWriter` to close the output file. If not, Manim assumes that a static image should be output which it then renders using the same strategy by calling the render loop (see below) once. **Back in our toy example,** the call to :meth:`.Scene.render` first triggers :meth:`.Scene.setup` (which only consists of ``pass``), followed by a call of :meth:`.Scene.construct`. At this point, our *animation script* is run, starting with the initialization of ``orange_square``. Mobject Initialization ---------------------- Mobjects are, in a nutshell, the Python objects that represent all the *things* we want to display in our scene. Before we follow our debugger into the depths of mobject initialization code, it makes sense to discuss Manim's different types of Mobjects and their basic data structure. What even is a Mobject? ^^^^^^^^^^^^^^^^^^^^^^^ :class:`.Mobject` stands for *mathematical object* or *Manim object* (depends on who you ask 😄). The Python class :class:`.Mobject` is the base class for all objects that should be displayed on screen. Looking at the `initialization method `__ of :class:`.Mobject`, you will find that not too much happens in there: - some initial attribute values are assigned, like ``name`` (which makes the render logs mention the name of the mobject instead of its type), ``submobjects`` (initially an empty list), ``color``, and some others. - Then, two methods related to *points* are called: ``reset_points`` followed by ``generate_points``, - and finally, ``init_colors`` is called. Digging deeper, you will find that :meth:`.Mobject.reset_points` simply sets the ``points`` attribute of the mobject to an empty NumPy vector, while the other two methods, :meth:`.Mobject.generate_points` and :meth:`.Mobject.init_colors` are just implemented as ``pass``. This makes sense: :class:`.Mobject` is not supposed to be used as an *actual* object that is displayed on screen; in fact the camera (which we will discuss later in more detail; it is the class that is, for the Cairo renderer, responsible for "taking a picture" of the current scene) does not process "pure" :class:`Mobjects <.Mobject>` in any way, they *cannot* even appear in the rendered output. This is where different types of mobjects come into play. Roughly speaking, the Cairo renderer setup knows three different types of mobjects that can be rendered: - :class:`.ImageMobject`, which represent images that you can display in your scene, - :class:`.PMobject`, which are very special mobjects used to represent point clouds; we will not discuss them further in this guide, - :class:`.VMobject`, which are *vectorized mobjects*, that is, mobjects that consist of points that are connected via curves. These are pretty much everywhere, and we will discuss them in detail in the next section. ... and what are VMobjects? ^^^^^^^^^^^^^^^^^^^^^^^^^^^ As just mentioned, :class:`VMobjects <.VMobject>` represent vectorized mobjects. To render a :class:`.VMobject`, the camera looks at the ``points`` attribute of a :class:`.VMobject` and divides it into sets of four points each. Each of these sets is then used to construct a cubic Bézier curve with the first and last entry describing the end points of the curve ("anchors"), and the second and third entry describing the control points in between ("handles"). .. hint:: To learn more about Bézier curves, take a look at the excellent online textbook `A Primer on Bézier curves `__ by `Pomax `__ -- there is a playground representing cubic Bézier curves `in §1 `__, the red and yellow points are "anchors", and the green and blue points are "handles". In contrast to :class:`.Mobject`, :class:`.VMobject` can be displayed on screen (even though, technically, it is still considered a base class). To illustrate how points are processed, consider the following short example of a :class:`.VMobject` with 8 points (and thus made out of 8/4 = 2 cubic Bézier curves). The resulting :class:`.VMobject` is drawn in green. The handles are drawn as red dots with a line to their closest anchor. .. manim:: VMobjectDemo :save_last_frame: class VMobjectDemo(Scene): def construct(self): plane = NumberPlane() my_vmobject = VMobject(color=GREEN) my_vmobject.points = [ np.array([-2, -1, 0]), # start of first curve np.array([-3, 1, 0]), np.array([0, 3, 0]), np.array([1, 3, 0]), # end of first curve np.array([1, 3, 0]), # start of second curve np.array([0, 1, 0]), np.array([4, 3, 0]), np.array([4, -2, 0]), # end of second curve ] handles = [ Dot(point, color=RED) for point in [[-3, 1, 0], [0, 3, 0], [0, 1, 0], [4, 3, 0]] ] handle_lines = [ Line( my_vmobject.points[ind], my_vmobject.points[ind+1], color=RED, stroke_width=2 ) for ind in range(0, len(my_vmobject.points), 2) ] self.add(plane, *handles, *handle_lines, my_vmobject) .. warning:: Manually setting the points of your :class:`.VMobject` is usually discouraged; there are specialized methods that can take care of that for you -- but it might be relevant when implementing your own, custom :class:`.VMobject`. Squares and Circles: back to our Toy Example ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ With a basic understanding of different types of mobjects, and an idea of how vectorized mobjects are built we can now come back to our toy example and the execution of the :meth:`.Scene.construct` method. In the first two lines of our animation script, the ``orange_square`` and the ``blue_circle`` are initialized. When creating the orange square by running :: Square(color=ORANGE, fill_opacity=0.5) the initialization method of :class:`.Square`, ``Square.__init__``, is called. `Looking at the implementation `__, we can see that the ``side_length`` attribute of the square is set, and then :: super().__init__(height=side_length, width=side_length, **kwargs) is called. This ``super`` call is the Python way of calling the initialization function of the parent class. As :class:`.Square` inherits from :class:`.Rectangle`, the next method called is ``Rectangle.__init__``. There, only the first three lines are really relevant for us:: super().__init__(UR, UL, DL, DR, color=color, **kwargs) self.stretch_to_fit_width(width) self.stretch_to_fit_height(height) First, the initialization function of the parent class of :class:`.Rectangle` -- :class:`.Polygon` -- is called. The four positional arguments passed are the four corners of the polygon: ``UR`` is up right (and equal to ``UP + RIGHT``), ``UL`` is up left (and equal to ``UP + LEFT``), and so forth. Before we follow our debugger deeper, let us observe what happens with the constructed polygon: the remaining two lines stretch the polygon to fit the specified width and height such that a rectangle with the desired measurements is created. The initialization function of :class:`.Polygon` is particularly simple, it only calls the initialization function of its parent class, :class:`.Polygram`. There, we have almost reached the end of the chain: :class:`.Polygram` inherits from :class:`.VMobject`, whose initialization function mainly sets the values of some attributes (quite similar to ``Mobject.__init__``, but more specific to the Bézier curves that make up the mobject). After calling the initialization function of :class:`.VMobject`, the constructor of :class:`.Polygram` also does something somewhat odd: it sets the points (which, you might remember above, should actually be set in a corresponding ``generate_points`` method of :class:`.Polygram`). .. warning:: In several instances, the implementation of mobjects does not really stick to all aspects of Manim's interface. This is unfortunate, and increasing consistency is something that we actively work on. Help is welcome! Without going too much into detail, :class:`.Polygram` sets its ``points`` attribute via :meth:`.VMobject.start_new_path`, :meth:`.VMobject.add_points_as_corners`, which take care of setting the quadruples of anchors and handles appropriately. After the points are set, Python continues to process the call stack until it reaches the method that was first called; the initialization method of :class:`.Square`. After this, the square is initialized and assigned to the ``orange_square`` variable. The initialization of ``blue_circle`` is similar to the one of ``orange_square``, with the main difference being that the inheritance chain of :class:`.Circle` is different. Let us briefly follow the trace of the debugger: The implementation of :meth:`.Circle.__init__` immediately calls the initialization method of :class:`.Arc`, as a circle in Manim is simply an arc with an angle of :math:`\tau = 2\pi`. When initializing the arc, some basic attributes are set (like ``Arc.radius``, ``Arc.arc_center``, ``Arc.start_angle``, and ``Arc.angle``), and then the initialization method of its parent class, :class:`.TipableVMobject`, is called (which is a rather abstract base class for mobjects which a arrow tip can be attached to). Note that in contrast to :class:`.Polygram`, this class does **not** preemptively generate the points of the circle. After that, things are less exciting: :class:`.TipableVMobject` again sets some attributes relevant for adding arrow tips, and afterwards passes to the initialization method of :class:`.VMobject`. From there, :class:`.Mobject` is initialized and :meth:`.Mobject.generate_points` is called, which actually runs the method implemented in :meth:`.Arc.generate_points`. After both our ``orange_square`` and the ``blue_circle`` are initialized, the square is actually added to the scene. The :meth:`.Scene.add` method is actually doing a few interesting things, so it is worth to dig a bit deeper in the next section. Adding Mobjects to the Scene ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The code in our ``construct`` method that is run next is :: self.add(orange_square) From a high-level point of view, :meth:`.Scene.add` adds the ``orange_square`` to the list of mobjects that should be rendered, which is stored in the ``mobjects`` attribute of the scene. However, it does so in a very careful way to avoid the situation that a mobject is being added to the scene more than once. At a first glance, this sounds like a simple task -- the problem is that ``Scene.mobjects`` is not a "flat" list of mobjects, but a list of mobjects which might contain mobjects themselves, and so on. Stepping through the code in :meth:`.Scene.add`, we see that first it is checked whether we are currently using the OpenGL renderer (which we are not) -- adding mobjects to the scene works slightly different (and actually easier!) for the OpenGL renderer. Then, the code branch for the Cairo renderer is entered and the list of so-called foreground mobjects (which are rendered on top of all other mobjects) is added to the list of passed mobjects. This is to ensure that the foreground mobjects will stay above of the other mobjects, even after adding the new ones. In our case, the list of foreground mobjects is actually empty, and nothing changes. Next, :meth:`.Scene.restructure_mobjects` is called with the list of mobjects to be added as the ``to_remove`` argument, which might sound odd at first. Practically, this ensures that mobjects are not added twice, as mentioned above: if they were present in the scene ``Scene.mobjects`` list before (even if they were contained as a child of some other mobject), they are first removed from the list. The way :meth:`.Scene.restructure_mobjects` works is rather aggressive: It always operates on a given list of mobjects; in the ``add`` method two different lists occur: the default one, ``Scene.mobjects`` (no extra keyword argument is passed), and ``Scene.moving_mobjects`` (which we will discuss later in more detail). It iterates through all of the members of the list, and checks whether any of the mobjects passed in ``to_remove`` are contained as children (in any nesting level). If so, **their parent mobject is deconstructed** and their siblings are inserted directly one level higher. Consider the following example:: >>> from manim import Scene, Square, Circle, Group >>> test_scene = Scene() >>> mob1 = Square() >>> mob2 = Circle() >>> mob_group = Group(mob1, mob2) >>> test_scene.add(mob_group) >>> test_scene.mobjects [Group] >>> test_scene.restructure_mobjects(to_remove=[mob1]) >>> test_scene.mobjects [Circle] Note that the group is disbanded and the circle moves into the root layer of mobjects in ``test_scene.mobjects``. After the mobject list is "restructured", the mobject to be added are simply appended to ``Scene.mobjects``. In our toy example, the ``Scene.mobjects`` list is actually empty, so the ``restructure_mobjects`` method does not actually do anything. The ``orange_square`` is simply added to ``Scene.mobjects``, and as the aforementioned ``Scene.moving_mobjects`` list is, at this point, also still empty, nothing happens and :meth:`.Scene.add` returns. We will hear more about the ``moving_mobject`` list when we discuss the render loop. Before we do that, let us look at the next line of code in our toy example, which includes the initialization of an animation class, :: ReplacementTransform(orange_square, blue_circle, run_time=3) Hence it is time to talk about :class:`.Animation`. Animations and the Render Loop ------------------------------ Initializing animations ^^^^^^^^^^^^^^^^^^^^^^^ Before we follow the trace of the debugger, let us briefly discuss the general structure of the (abstract) base class :class:`.Animation`. An animation object holds all the information necessary for the renderer to generate the corresponding frames. Animations (in the sense of animation objects) in Manim are *always* tied to a specific mobject; even in the case of :class:`.AnimationGroup` (which you should actually think of as an animation on a group of mobjects rather than a group of animations). Moreover, except for in a particular special case, the run time of animations is also fixed and known beforehand. The initialization of animations actually is not very exciting, :meth:`.Animation.__init__` merely sets some attributes derived from the passed keyword arguments and additionally ensures that the ``Animation.starting_mobject`` and ``Animation.mobject`` attributes are populated. Once the animation is played, the ``starting_mobject`` attribute holds an unmodified copy of the mobject the animation is attached to; during the initialization it is set to a placeholder mobject. The ``mobject`` attribute is set to the mobject the animation is attached to. Animations have a few special methods which are called during the render loop: - :meth:`.Animation.begin`, which is called (as hinted by its name) at the beginning of every animation, so before the first frame is rendered. In it, all the required setup for the animation happens. - :meth:`.Animation.finish` is the counterpart to the ``begin`` method which is called at the end of the life cycle of the animation (after the last frame has been rendered). - :meth:`.Animation.interpolate` is the method that updates the mobject attached to the animation to the corresponding animation completion percentage. For example, if in the render loop, ``some_animation.interpolate(0.5)`` is called, the attached mobject will be updated to the state where 50% of the animation are completed. We will discuss details about these and some further animation methods once we walk through the actual render loop. For now, we continue with our toy example and the code that is run when initializing the :class:`.ReplacementTransform` animation. The initialization method of :class:`.ReplacementTransform` only consists of a call to the constructor of its parent class, :class:`.Transform`, with the additional keyword argument ``replace_mobject_with_target_in_scene`` set to ``True``. :class:`.Transform` then sets attributes that control how the points of the starting mobject are deformed into the points of the target mobject, and then passes on to the initialization method of :class:`.Animation`. Other basic properties of the animation (like its ``run_time``, the ``rate_func``, etc.) are processed there -- and then the animation object is fully initialized and ready to be played. The ``play`` call: preparing to enter Manim's render loop ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We are finally there, the render loop is in our reach. Let us walk through the code that is run when :meth:`.Scene.play` is called. .. hint:: Recall that this article is specifically about the Cairo renderer. Up to here, things were more or less the same for the OpenGL renderer as well; while some base mobjects might be different, the control flow and lifecycle of mobjects is still more or less the same. There are more substantial differences when it comes to the rendering loop. As you will see when inspecting the method, :meth:`.Scene.play` almost immediately passes over to the ``play`` method of the renderer, in our case :class:`.CairoRenderer.play`. The one thing :meth:`.Scene.play` takes care of is the management of subcaptions that you might have passed to it (see the the documentation of :meth:`.Scene.play` and :meth:`.Scene.add_subcaption` for more information). .. warning:: As has been said before, the communication between scene and renderer is not in a very clean state at this point, so the following paragraphs might be confusing if you don't run a debugger and step through the code yourself a bit. Inside :meth:`.CairoRenderer.play`, the renderer first checks whether it may skip rendering of the current play call. This might happen, for example, when ``-s`` is passed to the CLI (i.e., only the last frame should be rendered), or when the ``-n`` flag is passed and the current play call is outside of the specified render bounds. The "skipping status" is updated in form of the call to :meth:`.CairoRenderer.update_skipping_status`. Next, the renderer asks the scene to process the animations in the play call so that renderer obtains all of the information it needs. To be more concrete, :meth:`.Scene.compile_animation_data` is called, which then takes care of several things: - The method processes all animations and the keyword arguments passed to the initial :meth:`.Scene.play` call. In particular, this means that it makes sure all arguments passed to the play call are actually animations (or ``.animate`` syntax calls, which are also assembled to be actual :class:`.Animation`-objects at that point). It also propagates any animation-related keyword arguments (like ``run_time``, or ``rate_func``) passed to :class:`.Scene.play` to each individual animation. The processed animations are then stored in the ``animations`` attribute of the scene (which the renderer later reads...). - It adds all mobjects to which the animations that are played are bound to to the scene (provided the animation is not an mobject-introducing animation -- for these, the addition to the scene happens later). - In case the played animation is a :class:`.Wait` animation (this is the case in a :meth:`.Scene.wait` call), the method checks whether a static image should be rendered, or whether the render loop should be processed as usual (see :meth:`.Scene.should_update_mobjects` for the exact conditions, basically it checks whether there are any time-dependent updater functions and so on). - Finally, the method determines the total run time of the play call (which at this point is computed as the maximum of the run times of the passed animations). This is stored in the ``duration`` attribute of the scene. After the animation data has been compiled by the scene, the renderer continues to prepare for entering the render loop. It now checks the skipping status which has been determined before. If the renderer can skip this play call, it does so: it sets the current play call hash (which we will get back to in a moment) to ``None`` and increases the time of the renderer by the determined animation run time. Otherwise, the renderer checks whether or not Manim's caching system should be used. The idea of the caching system is simple: for every play call, a hash value is computed, which is then stored and upon re-rendering the scene, the hash is generated again and checked against the stored value. If it is the same, the cached output is reused, otherwise it is fully rerendered again. We will not go into details of the caching system here; if you would like to learn more, the :func:`.get_hash_from_play_call` function in the :mod:`.utils.hashing` module is essentially the entry point to the caching mechanism. In the event that the animation has to be rendered, the renderer asks its :class:`.SceneFileWriter` to open an output container. The process is started by a call to ``libav`` and opens a container to which rendered raw frames can be written. As long as the output is open, the container can be accessed via the ``output_container`` attribute of the file writer. With the writing process in place, the renderer then asks the scene to "begin" the animations. First, it literally *begins* all of the animations by calling their setup methods (:meth:`.Animation._setup_scene`, :meth:`.Animation.begin`). In doing so, the mobjects that are newly introduced by an animation (like via :class:`.Create` etc.) are added to the scene. Furthermore, the animation suspends updater functions being called on its mobject, and it sets its mobject to the state that corresponds to the first frame of the animation. After this has happened for all animations in the current ``play`` call, the Cairo renderer determines which of the scene's mobjects can be painted statically to the background, and which ones have to be redrawn every frame. It does so by calling :meth:`.Scene.get_moving_and_static_mobjects`, and the resulting partition of mobjects is stored in the corresponding ``moving_mobjects`` and ``static_mobjects`` attributes. .. NOTE:: The mechanism that determines static and moving mobjects is specific for the Cairo renderer, the OpenGL renderer works differently. Basically, moving mobjects are determined by checking whether they, any of their children, or any of the mobjects "below" them (in the sense of the order in which mobjects are processed in the scene) either have an update function attached, or whether they appear in one of the current animations. See the implementation of :meth:`.Scene.get_moving_mobjects` for more details. Up to this very point, we did not actually render any (partial) image or movie files from the scene yet. This is, however, about to change. Before we enter the render loop, let us briefly revisit our toy example and discuss how the generic :meth:`.Scene.play` call setup looks like there. For the call that plays the :class:`.ReplacementTransform`, there is no subcaption to be taken care of. The renderer then asks the scene to compile the animation data: the passed argument already is an animation (no additional preparations needed), there is no need for processing any keyword arguments (as we did not specify any additional ones to ``play``). The mobject bound to the animation, ``orange_square``, is already part of the scene (so again, no action taken). Finally, the run time is extracted (3 seconds long) and stored in ``Scene.duration``. The renderer then checks whether it should skip (it should not), then whether the animation is already cached (it is not). The corresponding animation hash value is determined and passed to the file writer, which then also calls ``libav`` to start the writing process which waits for rendered frames from the library. The scene then ``begin``\ s the animation: for the :class:`.ReplacementTransform` this means that the animation populates all of its relevant animation attributes (i.e., compatible copies of the starting and the target mobject so that it can safely interpolate between the two). The mechanism determining static and moving mobjects considers all of the scenes mobjects (at this point only the ``orange_square``), and determines that the ``orange_square`` is bound to an animation that is currently played. As a result, the square is classified as a "moving mobject". Time to render some frames. The render loop (for real this time) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As mentioned above, due to the mechanism that determines static and moving mobjects in the scene, the renderer knows which mobjects it can paint statically to the background of the scene. Practically, this means that it partially renders a scene (to produce a background image), and then when iterating through the time progression of the animation only the "moving mobjects" are re-painted on top of the static background. The renderer calls :meth:`.CairoRenderer.save_static_frame_data`, which first checks whether there are currently any static mobjects, and if there are, it updates the frame (only with the static mobjects; more about how exactly this works in a moment) and then saves a NumPy array representing the rendered frame in the ``static_image`` attribute. In our toy example, there are no static mobjects, and so the ``static_image`` attribute is simply set to ``None``. Next, the renderer asks the scene whether the current animation is a "frozen frame" animation, which would mean that the renderer actually does not have to repaint the moving mobjects in every frame of the time progression. It can then just take the latest static frame, and display it throughout the animation. .. NOTE:: An animation is considered a "frozen frame" animation if only a static :class:`.Wait` animation is played. See the description of :meth:`.Scene.compile_animation_data` above, or the implementation of :meth:`.Scene.should_update_mobjects` for more details. If this is not the case (just as in our toy example), the renderer then calls the :meth:`.Scene.play_internal` method, which is the integral part of the render loop (in which the library steps through the time progression of the animation and renders the corresponding frames). Within :meth:`.Scene.play_internal`, the following steps are performed: - The scene determines the run time of the animations by calling :meth:`.Scene.get_run_time`. This method basically takes the maximum ``run_time`` attribute of all of the animations passed to the :meth:`.Scene.play` call. - Then the *time progression* is constructed via the (internal) :meth:`.Scene._get_animation_time_progression` method, which wraps the actual :meth:`.Scene.get_time_progression` method. The time progression is a ``tqdm`` `progress bar object `__ for an iterator over ``np.arange(0, run_time, 1 / config.frame_rate)``. In other words, the time progression holds the time stamps (relative to the current animations, so starting at 0 and ending at the total animation run time, with the step size determined by the render frame rate) of the timeline where a new animation frame should be rendered. - Then the scene iterates over the time progression: for each time stamp ``t``, :meth:`.Scene.update_to_time` is called, which ... - ... first computes the time passed since the last update (which might be 0, especially for the initial call) and references it as ``dt``, - then (in the order in which the animations are passed to :meth:`.Scene.play`) calls :meth:`.Animation.update_mobjects` to trigger all updater functions that are attached to the respective animation except for the "main mobject" of the animation (that is, for example, for :class:`.Transform` the unmodified copies of start and target mobject -- see :meth:`.Animation.get_all_mobjects_to_update` for more details), - then the relative time progression with respect to the current animation is computed (``alpha = t / animation.run_time``), which is then used to update the state of the animation with a call to :meth:`.Animation.interpolate`. - After all of the passed animations have been processed, the updater functions of all mobjects in the scene, all meshes, and finally those attached to the scene itself are run. At this point, the internal (Python) state of all mobjects has been updated to match the currently processed timestamp. If rendering should not be skipped, then it is now time to *take a picture*! .. NOTE:: The update of the internal state (iteration over the time progression) happens *always* once :meth:`.Scene.play_internal` is entered. This ensures that even if frames do not need to be rendered (because, e.g., the ``-n`` CLI flag has been passed, something has been cached, or because we might be in a *Section* with skipped rendering), updater functions still run correctly, and the state of the first frame that *is* rendered is kept consistent. To render an image, the scene calls the corresponding method of its renderer, :meth:`.CairoRenderer.render` and passes just the list of *moving mobjects* (remember, the *static mobjects* are assumed to have already been painted statically to the background of the scene). All of the hard work then happens when the renderer updates its current frame via a call to :meth:`.CairoRenderer.update_frame`: First, the renderer prepares its :class:`.Camera` by checking whether the renderer has a ``static_image`` different from ``None`` stored already. If so, it sets the image as the *background image* of the camera via :meth:`.Camera.set_frame_to_background`, and otherwise it just resets the camera via :meth:`.Camera.reset`. The camera is then asked to capture the scene with a call to :meth:`.Camera.capture_mobjects`. Things get a bit technical here, and at some point it is more efficient to delve into the implementation -- but here is a summary of what happens once the camera is asked to capture the scene: - First, a flat list of mobjects is created (so submobjects get extracted from their parents). This list is then processed in groups of the same type of mobjects (e.g., a batch of vectorized mobjects, followed by a batch of image mobjects, followed by more vectorized mobjects, etc. -- in many cases there will just be one batch of vectorized mobjects). - Depending on the type of the currently processed batch, the camera uses dedicated *display functions* to convert the :class:`.Mobject` Python object to a NumPy array stored in the camera's ``pixel_array`` attribute. The most important example in that context is the display function for vectorized mobjects, :meth:`.Camera.display_multiple_vectorized_mobjects`, or the more particular (in case you did not add a background image to your :class:`.VMobject`), :meth:`.Camera.display_multiple_non_background_colored_vmobjects`. This method first gets the current Cairo context, and then, for every (vectorized) mobject in the batch, calls :meth:`.Camera.display_vectorized`. There, the actual background stroke, fill, and then stroke of the mobject is drawn onto the context. See :meth:`.Camera.apply_stroke` and :meth:`.Camera.set_cairo_context_color` for more details -- but it does not get much deeper than that, in the latter method the actual Bézier curves determined by the points of the mobject are drawn; this is where the low-level interaction with Cairo happens. After all batches have been processed, the camera has an image representation of the Scene at the current time stamp in form of a NumPy array stored in its ``pixel_array`` attribute. The renderer then takes this array and passes it to its :class:`.SceneFileWriter`. This concludes one iteration of the render loop, and once the time progression has been processed completely, a final bit of cleanup is performed before the :meth:`.Scene.play_internal` call is completed. A TL;DR for the render loop, in the context of our toy example, reads as follows: - The scene finds that a 3 second long animation (the :class:`.ReplacementTransform` changing the orange square to the blue circle) should be played. Given the requested medium render quality, the frame rate is 30 frames per second, and so the time progression with steps ``[0, 1/30, 2/30, ..., 89/30]`` is created. - In the internal render loop, each of these time stamps is processed: there are no updater functions, so effectively the scene updates the state of the transformation animation to the desired time stamp (for example, at time stamp ``t = 45/30``, the animation is completed to a rate of ``alpha = 0.5``). - Then the scene asks the renderer to do its job. The renderer asks its camera to capture the scene, the only mobject that needs to be processed at this point is the main mobject attached to the transformation; the camera converts the current state of the mobject to entries in a NumPy array. The renderer passes this array to the file writer. - At the end of the loop, 90 frames have been passed to the file writer. Completing the render loop ^^^^^^^^^^^^^^^^^^^^^^^^^^ The last few steps in the :meth:`.Scene.play_internal` call are not too exciting: for every animation, the corresponding :meth:`.Animation.finish` and :meth:`.Animation.clean_up_from_scene` methods are called. .. NOTE:: Note that as part of :meth:`.Animation.finish`, the :meth:`.Animation.interpolate` method is called with an argument of 1.0 -- you might have noticed already that the last frame of an animation can sometimes be a bit off or incomplete. This is by current design! The last frame rendered in the render loop (and displayed for a duration of ``1 / frame_rate`` seconds in the rendered video) corresponds to the state of the animation ``1 / frame_rate`` seconds before it ends. To display the final frame as well in the video, we would need to append another ``1 / frame_rate`` seconds to the video -- which would then mean that a 1 second rendered Manim video would be slightly longer than 1 second. We decided against this at some point. In the end, the time progression is closed (which completes the displayed progress bar) in the terminal. With the closing of the time progression, the :meth:`.Scene.play_internal` call is completed, and we return to the renderer, which now orders the :class:`.SceneFileWriter` to close the output container that has been opened for this animation: a partial movie file is written. This pretty much concludes the walkthrough of a :class:`.Scene.play` call, and actually there is not too much more to say for our toy example either: at this point, a partial movie file that represents playing the :class:`.ReplacementTransform` has been written. The initialization of the :class:`.Dot` happens analogous to the initialization of ``blue_circle``, which has been discussed above. The :meth:`.Mobject.add_updater` call literally just attaches a function to the ``updaters`` attribute of the ``small_dot``. And the remaining :meth:`.Scene.play` and :meth:`.Scene.wait` calls follow the exact same procedure as discussed in the render loop section above; each such call produces a corresponding partial movie file. Once the :meth:`.Scene.construct` method has been fully processed (and thus all of the corresponding partial movie files have been written), the scene calls its cleanup method :meth:`.Scene.tear_down`, and then asks its renderer to finish the scene. The renderer, in turn, asks its scene file writer to wrap things up by calling :meth:`.SceneFileWriter.finish`, which triggers the combination of the partial movie files into the final product. And there you go! This is a more or less detailed description of how Manim works under the hood. While we did not discuss every single line of code in detail in this walkthrough, it should still give you a fairly good idea of how the general structural design of the library and at least the Cairo rendering flow in particular looks like. ================================================ FILE: docs/source/guides/index.rst ================================================ Thematic Guides =============== .. toctree:: :caption: Table of Contents :maxdepth: 2 :glob: configuration deep_dive using_text add_voiceovers ================================================ FILE: docs/source/guides/using_text.rst ================================================ ########################### Rendering Text and Formulas ########################### There are two different ways by which you can render **Text** in videos: 1. Using Pango (:mod:`~.text_mobject`) 2. Using LaTeX (:mod:`~.tex_mobject`) If you want to render simple text, you should use either :class:`~.Text` or :class:`~.MarkupText`, or one of its derivatives like :class:`~.Paragraph`. See :ref:`using-text-objects` for more information. LaTeX should be used when you need mathematical typesetting. See :ref:`rendering-with-latex` for more information. .. _using-text-objects: Text Without LaTeX ****************** The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the `Pango library`_ to render text. With Pango, you can also render non-English alphabets like 你好 or こんにちは or 안녕하세요 or مرحبا بالعالم. Here is a simple *Hello World* animation. .. manim:: HelloWorld :save_last_frame: :ref_classes: Text class HelloWorld(Scene): def construct(self): text = Text("Hello world", font_size=144) self.add(text) You can also use :class:`~.MarkupText` which allows the use of PangoMarkup (see the documentation of :class:`~.MarkupText` for details) to render text. For example: .. manim:: SingleLineColor :save_last_frame: :ref_classes: MarkupText class SingleLineColor(Scene): def construct(self): text = MarkupText( f'all in red except this', color=RED ) self.add(text) .. _Pango library: https://pango.org Working with :class:`~.Text` ============================ This section explains the properties of :class:`~.Text` and how can it be used in your animations. Using Fonts ----------- You can set a different font using :attr:`~.Text.font`. .. note:: The font used must be installed in your system, and Pango should know about it. You can get a list of fonts using :func:`manimpango.list_fonts`. >>> import manimpango >>> manimpango.list_fonts() [...] .. manim:: FontsExample :save_last_frame: class FontsExample(Scene): def construct(self): ft = Text("Noto Sans", font="Noto Sans") self.add(ft) Setting Slant and Weight ------------------------ Slant is the style of the Text, and it can be ``NORMAL`` (the default), ``ITALIC`` or ``OBLIQUE``. Usually, for many fonts both ``ITALIC`` and ``OBLIQUE`` look similar, but ``ITALIC`` uses **Roman Style**, whereas ``OBLIQUE`` uses **Italic Style**. Weight specifies the boldness of a font. You can see a list of weights in :class:`manimpango.Weight`. .. manim:: SlantsExample :save_last_frame: class SlantsExample(Scene): def construct(self): a = Text("Italic", slant=ITALIC) self.add(a) .. manim:: DifferentWeight :save_last_frame: class DifferentWeight(Scene): def construct(self): import manimpango g = VGroup() weight_list = dict( sorted( { weight: manimpango.Weight(weight).value for weight in manimpango.Weight }.items(), key=lambda x: x[1], ) ) for weight in weight_list: g += Text(weight.name, weight=weight.name, font="Open Sans") self.add(g.arrange(DOWN).scale(0.5)) .. _using-colors: Using Colors ------------ You can set the color of the text using :attr:`~.Text.color`: .. manim:: SimpleColor :save_last_frame: class SimpleColor(Scene): def construct(self): col = Text("RED COLOR", color=RED) self.add(col) You can use utilities like :attr:`~.Text.t2c` for coloring specific characters. This may be problematic if your text contains ligatures as explained in :ref:`iterating-text`. :attr:`~Text.t2c` accepts two types of dictionaries, * The keys can contain indices like ``[2:-1]`` or ``[4:8]``, this works similar to how `slicing `_ works in Python. The values should be the color of the Text from :class:`~.Color`. * The keys contain words or characters which should be colored separately and the values should be the color from :class:`~.Color`: .. manim:: Textt2cExample :save_last_frame: class Textt2cExample(Scene): def construct(self): t2cindices = Text('Hello', t2c={'[1:-1]': BLUE}).move_to(LEFT) t2cwords = Text('World',t2c={'rl':RED}).next_to(t2cindices, RIGHT) self.add(t2cindices, t2cwords) If you want to avoid problems when using colors (due to ligatures), consider using :class:`MarkupText`. Using Gradients --------------- You can add a gradient using :attr:`~.Text.gradient`. The value must be an iterable of any length: .. manim:: GradientExample :save_last_frame: class GradientExample(Scene): def construct(self): t = Text("Hello", gradient=(RED, BLUE, GREEN), font_size=96) self.add(t) You can also use :attr:`~.Text.t2g` for gradients with specific characters of the text. It shares a similar syntax to :ref:`the interface for colors `: .. manim:: t2gExample :save_last_frame: class t2gExample(Scene): def construct(self): t2gindices = Text( 'Hello', t2g={ '[1:-1]': (RED,GREEN), }, ).move_to(LEFT) t2gwords = Text( 'World', t2g={ 'World':(RED,BLUE), }, ).next_to(t2gindices, RIGHT) self.add(t2gindices, t2gwords) Setting Line Spacing -------------------- You can set the line spacing using :attr:`~.Text.line_spacing`: .. manim:: LineSpacing :save_last_frame: class LineSpacing(Scene): def construct(self): a = Text("Hello\nWorld", line_spacing=1) b = Text("Hello\nWorld", line_spacing=4) self.add(Group(a,b).arrange(LEFT, buff=5)) .. _disable-ligatures: Disabling Ligatures ------------------- By disabling ligatures you would get a one-to-one mapping between characters and submobjects. This fixes the issues with coloring text. .. warning:: Be aware that using this method with text that heavily depends on ligatures (Arabic text) may yield unexpected results. You can disable ligatures by passing ``disable_ligatures`` to :class:`Text`. For example: .. manim:: DisableLigature :save_last_frame: class DisableLigature(Scene): def construct(self): li = Text("fl ligature",font_size=96) nli = Text("fl ligature", disable_ligatures=True, font_size=96) self.add(Group(li, nli).arrange(DOWN, buff=.8)) .. _iterating-text: Iterating :class:`~.Text` ------------------------- Text objects behave like :class:`VGroups <.VGroup>`. Therefore, you can slice and index the text. For example, you can set each letter to different color by iterating it. .. manim:: IterateColor :save_last_frame: class IterateColor(Scene): def construct(self): text = Text("Colors", font_size=96) for letter in text: letter.set_color(random_bright_color()) self.add(text) .. warning:: Please note that `Ligature`_ can cause problems here. If you need a one-to-one mapping of characters to submobjects you should pass the ``disable_ligatures`` parameter to :class:`~.Text`. See :ref:`disable-ligatures`. .. _Ligature: https://en.wikipedia.org/wiki/Ligature_(writing) Working with :class:`~.MarkupText` ================================== MarkupText is similar to :class:`~.Text`, the only difference between them is that this accepts and processes PangoMarkup (which is similar to html), instead of just rendering plain text. Consult the documentation of :class:`~.MarkupText` for more details and further references about PangoMarkup. .. manim:: MarkupTest :save_last_frame: class MarkupTest(Scene): def construct(self): text = MarkupText( f'double green underline in red text except this', color=RED, font_size=34 ) self.add(text) .. _rendering-with-latex: Text With LaTeX *************** Just as you can use :class:`~.Text` to add text to your videos, you can use :class:`~.Tex` to insert LaTeX. For example, .. manim:: HelloLaTeX :save_last_frame: class HelloLaTeX(Scene): def construct(self): tex = Tex(r"\LaTeX", font_size=144) self.add(tex) .. note:: Note that we are using a raw string (``r'...'``) instead of a regular string (``'...'``). This is because TeX code uses a lot of special characters - like ``\`` for example - that have special meaning within a regular python string. An alternative would have been to write ``\\`` to escape the backslash: ``Tex('\\LaTeX')``. Working with :class:`~.MathTex` =============================== Everything passed to :class:`~.MathTex` is in math mode by default. To be more precise, :class:`~.MathTex` is processed within an ``align*`` environment. You can achieve a similar effect with :class:`~.Tex` by enclosing your formula with ``$`` symbols: ``$\xrightarrow{x^6y^8}$``: .. manim:: MathTeXDemo :save_last_frame: class MathTeXDemo(Scene): def construct(self): rtarrow0 = MathTex(r"\xrightarrow{x^6y^8}", font_size=96) rtarrow1 = Tex(r"$\xrightarrow{x^6y^8}$", font_size=96) self.add(VGroup(rtarrow0, rtarrow1).arrange(DOWN)) LaTeX commands and keyword arguments ==================================== We can use any standard LaTeX commands in the AMS maths packages. Such as the ``mathtt`` math-text type or the ``looparrowright`` arrow. .. manim:: AMSLaTeX :save_last_frame: class AMSLaTeX(Scene): def construct(self): tex = Tex(r'$\mathtt{H} \looparrowright$ \LaTeX', font_size=144) self.add(tex) On the Manim side, the :class:`~.Tex` class also accepts attributes to change the appearance of the output. This is very similar to the :class:`~.Text` class. For example, the ``color`` keyword changes the color of the TeX mobject. .. manim:: LaTeXAttributes :save_last_frame: class LaTeXAttributes(Scene): def construct(self): tex = Tex(r'Hello \LaTeX', color=BLUE, font_size=144) self.add(tex) Extra LaTeX Packages ==================== Some commands require special packages to be loaded into the TeX template. For example, to use the ``mathscr`` script, we need to add the ``mathrsfs`` package. Since this package isn't loaded into Manim's tex template by default, we have to add it manually. .. manim:: AddPackageLatex :save_last_frame: class AddPackageLatex(Scene): def construct(self): myTemplate = TexTemplate() myTemplate.add_to_preamble(r"\usepackage{mathrsfs}") tex = Tex( r"$\mathscr{H} \rightarrow \mathbb{H}$", tex_template=myTemplate, font_size=144, ) self.add(tex) Substrings and parts ==================== The TeX mobject can accept multiple strings as arguments. Afterwards you can refer to the individual parts either by their index (like ``tex[1]``), or by using :func:`~.set_color_by_tex`, which matches the argument exactly against the strings passed to the constructor. In this example, we color the ``\bigstar`` part: .. manim:: LaTeXSubstrings :save_last_frame: class LaTeXSubstrings(Scene): def construct(self): tex = Tex('Hello', r'$\bigstar$', r'\LaTeX', font_size=144) tex.set_color_by_tex(r'$\bigstar$', RED) self.add(tex) Because :func:`~.set_color_by_tex` requires an exact match, it cannot directly target a token inside a string that was passed as a single argument. To color every ``x`` in a formula, use ``substrings_to_isolate`` to split the string at each occurrence first: .. manim:: CorrectLaTeXSubstringColoring :save_last_frame: class CorrectLaTeXSubstringColoring(Scene): def construct(self): equation = MathTex( r"e^{x} = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots", substrings_to_isolate="x" ) equation.set_color_by_tex("x", YELLOW) self.add(equation) Each isolated occurrence of ``x`` becomes its own sub-mobject that :meth:`~.set_color_by_tex` can match exactly. If one of the ``substrings_to_isolate`` is in a sub or superscript, it needs to be enclosed by curly brackets. Note that Manim also supports a custom syntax that allows splitting a TeX string into substrings easily: simply enclose parts of your formula that you want to isolate with double braces. In the string ``MathTex(r"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}")``, the rendered mobject will consist of the substrings ``a^2``, ``+``, ``b^2``, ``=``, and ``c^2``. This makes transformations between similar text fragments easy to write using :class:`~.TransformMatchingTex`. For Manim to recognise a ``{{`` as a group opener, it must appear either at the very start of the string or be immediately preceded by a whitespace character. This means that ``{{`` embedded directly after non-whitespace LaTeX — such as ``\frac{{{n}}}{k}`` or ``a^{{2}}`` — is left untouched, which prevents accidental splitting of ordinary nested-brace expressions. To stop a leading ``{{`` from being treated as a group opener, insert a space between the two braces: ``{{ ... }}`` → ``{ { ... } }``. Using ``index_labels`` to work with complicated strings ======================================================= You might sometimes be working with a very complicated :class:`~.MathTex` mobject that makes it difficult to work with its individual components. This is where the debugging function :func:`.index_labels` is very useful. The method shows the index of a mobject's submobjects, allowing you to easily find the components of the mobject you would like to change. .. manim:: IndexLabelsMathTex :save_last_frame: class IndexLabelsMathTex(Scene): def construct(self): text = MathTex(r"\binom{2n}{n+2}", font_size=96) # index the first (and only) term of the MathTex mob self.add(index_labels(text[0])) text[0][1:3].set_color(YELLOW) text[0][3:6].set_color(RED) self.add(text) LaTeX Maths Fonts - The Template Library ======================================== Changing fonts in LaTeX when typesetting mathematical formulae is trickier than regular text. It requires changing the template that is used to compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates` ready for you to use. These templates will all work in math mode: .. manim:: LaTeXMathFonts :save_last_frame: class LaTeXMathFonts(Scene): def construct(self): tex = Tex( r"$x^2 + y^2 = z^2$", tex_template=TexFontTemplates.french_cursive, font_size=144, ) self.add(tex) Manim also has a :class:`~.TexTemplateLibrary` containing the TeX templates used by 3Blue1Brown. One example is the ctex template, used for typesetting Chinese script. For this to work, the ctex LaTeX package must be installed on your system. Furthermore, if you are only typesetting Text, you probably do not need :class:`~.Tex` at all, and should use :class:`~.Text` instead. .. manim:: LaTeXTemplateLibrary :save_last_frame: class LaTeXTemplateLibrary(Scene): def construct(self): tex = Tex('Hello 你好 \\LaTeX', tex_template=TexTemplateLibrary.ctex, font_size=144) self.add(tex) Aligning formulae ================= :class:`~.MathTex` mobject is typeset in the LaTeX ``align*`` environment. This means you can use the ``&`` alignment character when typesetting multiline formulae: .. manim:: LaTeXAlignEnvironment :save_last_frame: class LaTeXAlignEnvironment(Scene): def construct(self): tex = MathTex(r'f(x) &= 3 + 2 + 1\\ &= 5 + 1 \\ &= 6', font_size=96) self.add(tex) ================================================ FILE: docs/source/index.rst ================================================ .. manim documentation master file, created by sphinx-quickstart on Tue Aug 4 13:58:07 2020. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Manim Community Edition ======================= Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. Manim relies on Python's simplicity to generate animations programmatically, making it convenient to specify exactly how each one should run. Take a look at the :doc:`Example Gallery <../examples>` for some inspiration on how to create beautiful images and videos with Manim. First Steps ----------- Are you new to Manim and are looking for where to get started? Then you are in the right place! .. note:: Please be aware that there are different, incompatible versions of Manim available. This version, the Community Edition of Manim (`ManimCE `_), is a separate project maintained by the community, but it was forked from `3b1b/manim `_, the original Manim created and open-sourced by Grant Sanderson, creator of `3Blue1Brown `_ educational math videos. Check our :ref:`installation FAQ ` to learn more! - The :doc:`Installation ` section has the latest and up-to-date installation instructions for Windows, macOS, and Linux. You can also find information on Manim's docker images and (online) notebook environments there. - Want to try the library before installing it? Take a look at our interactive online playground at https://try.manim.community in the form of a Jupyter notebook. - In our :doc:`Tutorials ` section you will find a collection of resources that will teach you how to use Manim. In particular, the :doc:`tutorials/quickstart` tutorial teaches you Manim's basics, and in :doc:`tutorials/building_blocks` the classes used to compose your animations are described in more detail. Finding Help ------------ Are you struggling with installing or using Manim? Don't worry, we've all been there. Here are some good resources to help you out: - Perhaps your problem is one that occurs frequently, then chances are it is addressed in our :doc:`collection of FAQs `. - If you are looking for information on some specific class, look for it in the :doc:`reference manual ` and/or use the search feature of the documentation. - Still no luck? Then you are welcome to ask the community for help, together we usually manage to find a solution for your problem! Consult the :doc:`FAQ page on getting help ` for instructions. Navigating the Documentation ---------------------------- Here are some short summaries for all of the sections in this documentation: - The :doc:`Example Gallery ` is a collection of examples (rendered videos and images together with the code they were generated from) that show a few different, simple things that you can do with Manim. - The :doc:`Installation ` section has information on installing Manim. - In :doc:`Tutorials & Guides ` you can find learning resources: proper tutorials that guide you through the process of creating a video are in the :doc:`Tutorial ` section; guides on specific topics are in the :doc:`Guides ` section, and the answers to frequently asked questions can be found in the :doc:`FAQ ` section. - The :doc:`Reference Manual ` contains a comprehensive list of all of Manim's (documented) modules, classes, and functions. If you are somewhat familiar with Manim's module structure, feel free to browse the manual directly. If you are searching for something specific, feel free to use the documentation's search feature in the sidebar. Many classes and methods come with their own illustrated examples too! - The :doc:`Plugins ` page documents how to install, write, and distribute plugins (that is, separate Python packages that extend the feature set of the core library). - Changes between versions are documented in our :doc:`Changelog `. - If you are looking into contributing to the development of Manim, you can find information on how to get involved in our :doc:`Contributing ` section. - And finally, the :doc:`Code of Conduct
` page has a formal description of the rules you should abide by when interacting within our community. Sharing Your Work ----------------- We'd love to hear from you and see your manimations `on Twitter `_, `Reddit `_, or `Discord `_. If you're using Manim in a scientific context, instructions on how to cite a particular release can be found `in our README `_. License Information ------------------- Manim is an open-source library licensed under the **MIT License**, which applies to both the original and the community editions of the software. This means you are free to use, modify, and distribute the code in accordance with the MIT License terms. However, there are some additional points to be aware of: - **Copyrighted Assets:** Specific assets, such as the "Pi creatures" in Grant Sanderson's (3Blue1Brown) videos, are copyrighted and protected. Please avoid using these characters in any derivative works. - **Content Creation and Sharing:** Videos and animations created with Manim can be freely shared, and no attribution to Manim is required—although it is much appreciated! You are encouraged to showcase your work online and share it with the Manim community. Index ----- .. toctree:: :maxdepth: 2 examples installation tutorials_guides reference plugins changelog contributing conduct .. image:: _static/crowdin-badge.svg :align: center :alt: Localized with Crowdin :target: https://translate.manim.community ================================================ FILE: docs/source/installation/conda.rst ================================================ Conda ===== Required Dependencies --------------------- There are several package managers that work with conda packages, namely `conda `__, `mamba `__ and `pixi `__. After installing your package manager, you can create a new environment and install ``manim`` inside by running .. tab-set:: .. tab-item:: conda / mamba .. code-block:: bash # if you want to use mamba, just replace conda below with mamba conda create -n my-manim-environment conda activate my-manim-environment conda install -c conda-forge manim .. tab-item:: pixi .. code-block:: bash pixi init pixi add manim Since all dependencies (except LaTeX) are handled by conda, you don't need to worry about needing to install additional dependencies. Optional Dependencies --------------------- In order to make use of Manim's interface to LaTeX to, for example, render equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it. Recommendations on how to install LaTeX on different operating systems can be found :doc:`in our local installation guide
`. Working with Manim ------------------ At this point, you should have a working installation of Manim, head over to our :doc:`Quickstart Tutorial <../tutorials/quickstart>` to learn how to make your own *Manimations*! ================================================ FILE: docs/source/installation/docker.rst ================================================ Docker ====== The community maintains a docker image, which can be found `on DockerHub `__. For our image ``manimcommunity/manim``, there are the following tags: - ``latest``: the most recent version corresponding to `the main branch `__, - ``stable``: the latest released version (according to `the releases page `__), - ``vX.Y.Z``: any particular released version (according to `the releases page `__). .. note:: When using Manim's CLI within a Docker container, some flags like ``-p`` (preview file) and ``-f`` (show output file in the file browser) are not supported. .. note:: The Docker image ships with a minimal TeX Live installation. In particular, ``ctex`` is not installed by default. If your scenes rely on ``TexTemplateLibrary.ctex``, install it in the container via ``tlmgr install ctex``. Basic usage of the Docker container ----------------------------------- Assuming that you can access the docker installation on your system from a terminal (bash / PowerShell) via ``docker``, you can render a scene ``CircleToSquare`` in a file `test_scenes.py` with the following command. .. code-block:: bash docker run --rm -it -v "/full/path/to/your/directory:/manim" manimcommunity/manim manim -qm test_scenes.py CircleToSquare .. tip:: For Linux users there might be permission problems when letting the user in the container write to the mounted volume. Add ``--user="$(id -u):$(id -g)"`` to the ``docker`` CLI arguments to prevent the creation of output files not belonging to your user. Instead of using the "throwaway container" approach outlined above, you can also create a named container that you can modify to your liking. First, run .. code-block:: sh docker run -it --name my-manim-container -v "/full/path/to/your/directory:/manim" manimcommunity/manim bash to obtain an interactive shell inside your container allowing you to, e.g., install further dependencies (like texlive packages using ``tlmgr``). Exit the container as soon as you are satisfied. Then, before using it, start the container by running .. code-block:: sh docker start my-manim-container which starts the container in the background. Then, to render a scene ``CircleToSquare`` in a file ``test_scenes.py``, run .. code-block:: sh docker exec -it my-manim-container manim -qm test_scenes.py CircleToSquare Running JupyterLab via Docker ----------------------------- Another alternative to using the Docker image is to spin up a local JupyterLab instance. To do that, simply run .. code-block:: sh docker run -it -p 8888:8888 manimcommunity/manim jupyter lab --ip=0.0.0.0 and then follow the instructions in the terminal. ================================================ FILE: docs/source/installation/jupyter.rst ================================================ Jupyter Notebooks ================= Binder ------ `Binder `__ is an online platform that hosts shareable and customizable computing environments in the form of Jupyter notebooks. Manim ships with a built-in ``%%manim`` Jupyter magic command which makes it easy to use in these notebooks. To see an example for such an environment, visit our interactive tutorial over at https://try.manim.community/. It is relatively straightforward to prepare your own notebooks in a way that allows them to be shared interactively via Binder as well: #. First, prepare a directory containing one or multiple notebooks which you would like to share in an interactive environment. You can create these notebooks by using Jupyter notebooks with a local installation of Manim, or also by working in our pre-existing `interactive tutorial environment `__. #. In the same directory containing your notebooks, add a file named ``Dockerfile`` with the following content: .. code-block:: dockerfile FROM docker.io/manimcommunity/manim:v0.9.0 COPY --chown=manimuser:manimuser . /manim Don't forget to change the version tag ``v0.9.0`` to the version you were working with locally when creating your notebooks. #. Make the directory with your worksheets and the ``Dockerfile`` available to the public (and in particular: to Binder!). There are `several different options to do so `__, within the community we usually work with GitHub repositories or gists. #. Once your material is publicly available, visit https://mybinder.org and follow the instructions there to generate an interactive environment for your worksheets. .. hint:: The repository containing our `interactive tutorial `__ can be found at https://github.com/ManimCommunity/jupyter_examples. Google Colaboratory ------------------- It is also possible to install Manim in a `Google Colaboratory `__ environment. In contrast to Binder, where you can customize and prepare the environment beforehand (such that Manim is already installed and ready to be used), you will have to take care of that every time you start a new notebook in Google Colab. Fortunately, this is not particularly difficult. After creating a new notebook, paste the following code block in a cell, then execute it. .. code-block:: !sudo apt update !sudo apt install libcairo2-dev \ texlive texlive-latex-extra texlive-fonts-extra \ texlive-latex-recommended texlive-science \ tipa libpango1.0-dev !pip install manim !pip install IPython==8.21.0 You should start to see Colab installing all the dependencies specified in these commands. After the execution has completed, you will be prompted to restart the runtime. Click the "restart runtime" button at the bottom of the cell output. You are now ready to use Manim in Colab! To check that everything works as expected, first import Manim by running .. code-block:: from manim import * in a new code cell. Then create another cell containing the following code:: %%manim -qm -v WARNING SquareToCircle class SquareToCircle(Scene): def construct(self): square = Square() circle = Circle() circle.set_fill(PINK, opacity=0.5) self.play(Create(square)) self.play(Transform(square, circle)) self.wait() Upon running this cell, a short animation transforming a square into a circle should be rendered and displayed. ================================================ FILE: docs/source/installation/uv.md ================================================ # Installing Manim locally The standard way of installing Manim is by using Python's package manager `pip` to install the latest release from [PyPI](https://pypi.org/project/manim/). To make it easier for you to follow best practices when it comes to setting up a Python project for your Manim animations, we strongly recommend using a tool for managing Python environments and dependencies. In particular, [we strongly recommend using `uv`](https://docs.astral.sh/uv/#getting-started). For the two main ways of installing Manim described below, we assume that `uv` is available; we think it is particularly helpful if you are new to Python or programming in general. It is not a hard requirement whatsoever; if you know what you are doing you can just use `pip` to install Manim directly. :::::{admonition} Installing the Python management tool `uv` :class: seealso One way to install `uv` is via the dedicated console installer supporting all large operating systems. Simply paste the following snippet into your terminal / PowerShell -- or [consult `uv`'s documentation](https://docs.astral.sh/uv/#getting-started) for alternative ways to install the tool. ::::{tab-set} :::{tab-item} MacOS and Linux ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` ::: :::{tab-item} Windows ```powershell powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` ::: :::: ::::: Of course, if you know what you are doing and prefer to setup a virtual environment yourself, feel free to do so! :::{important} If you run into issues when following our instructions below, do not worry: check our [installation FAQs]() to see whether the problem is already addressed there -- and otherwise go and check [how to contact our community]() to get help. ::: ## Installation ### Step 1: Installing Python We first need to check that an appropriate version of Python is available on your machine. Open a terminal to run ```bash uv python install ``` to install the latest version of Python. If this is successful, continue to the next step. (installation-optional-latex)= ### Step 2 (optional): Installing LaTeX [LaTeX](https://en.wikibooks.org/wiki/LaTeX/Mathematics) is a very well-known and widely used typesetting system allowing you to write formulas like \begin{equation*} \frac{1}{2\pi i} \oint_{\gamma} \frac{f(z)}{(z - z_0)^{n+1}}~dz = \frac{f^{(n)}(z_0)}{n!}. \end{equation*} If rendering plain text is sufficient for your needs and you don't want to render any typeset formulas, you can technically skip this step. Otherwise select your operating system from the tab list below and follow the instructions. :::::{tab-set} ::::{tab-item} Windows For Windows we recommend installing LaTeX via the [MiKTeX distribution](https://miktex.org). Simply grab the Windows installer available from their download page, and run it. :::: ::::{tab-item} MacOS If you are running MacOS, we recommend installing the [MacTeX distribution](https://www.tug.org/mactex/). The latest available PKG file can be downloaded from . Get it and follow the standard installation procedure. :::: ::::{tab-item} Linux Given the large number of Linux distributions with different ways of installing packages, we cannot give detailed instructions for all package managers. In general we recommend to install a *TeX Live* distribution (). For most Linux distributions, TeX Live has already been packaged such that it can be installed easily with your system package manager. Search the internet and your usual OS resources for detailed instructions. For example, on Debian-based systems with the package manager `apt`, a full TeX Live distribution can be installed by running ```bash sudo apt install texlive-full ``` For Fedora (managed via `dnf`), the corresponding command is ```bash sudo dnf install texlive-scheme-full ``` As soon as LaTeX is installed, continue with actually installing Manim itself. :::: ::::: :::{dropdown} I know what I am doing and I would like to setup a minimal LaTeX installation You are welcome to use a smaller, more customizable LaTeX distribution like [TinyTeX](https://yihui.org/tinytex/). Manim overall requires the following LaTeX packages to be installed in your distribution: ```text amsmath babel-english cbfonts-fd cm-super count1to ctex doublestroke dvisvgm everysel fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin mathastext microtype multitoc physics preview prelim2e ragged2e relsize rsfs setspace standalone tipa wasy wasysym xcolor xetex xkeyval ``` ::: ### Step 3: Installing Manim These steps again differ slightly between different operating systems. Make sure you select the correct one from the tab list below, then follow the instructions below. ::::::{tab-set} :::::{tab-item} Windows The following commands will - create a new directory for a Python project, - and add Manim as a dependency, which installs it into the corresponding local Python environment. The name for the Python project is *manimations*, which you can change to anything you like. ```bash uv init manimations cd manimations uv add manim ``` Manim is now installed in your local project environment! ::::: :::::{tab-item} MacOS Before we can install Manim, we need to make sure that the system utilities `cairo` and `pkg-config` are present. They are needed for the [`pycairo` Python package](https://pycairo.readthedocs.io/en/latest/), a dependency of Manim. The easiest way of installing these utilities is by using [Homebrew](https://brew.sh/), a fairly popular 3rd party package manager for MacOS. Check whether Homebrew is already installed by running ```bash brew --version ``` which will report something along the lines of `Homebrew 4.4.15-54-...` if it is installed, and a message `command not found: brew` otherwise. In this case, use the shell installer [as instructed on Homebrew's website](https://brew.sh/), or get a `.pkg`-installer from [their GitHub release page](https://github.com/Homebrew/brew/releases). Make sure to follow the instructions of the installer carefully, especially when prompted to modify your `.zprofile` to add Homebrew to your system's PATH. With Homebrew available, the required utilities can be installed by running ```bash brew install cairo pkg-config ``` With all of this preparation out of the way, now it is time to actually install Manim itself! The following commands will - create a new directory for a Python project, - and add Manim as a dependency, which installs it into the corresponding local Python environment. The name for the Python project is *manimations*, which you can change to anything you like. ```bash uv init manimations cd manimations uv add manim ``` Manim is now installed in your local project environment! ::::: :::::{tab-item} Linux Practically, the instructions given in the *Windows* tab also apply for Linux -- however, some additional dependencies are required as Linux users need to build [ManimPango](https://github.com/ManimCommunity/ManimPango) (and potentially [pycairo](https://pycairo.readthedocs.io/en/latest/)) from source. More specifically, this includes: - A C compiler, - Python's development headers, - the `pkg-config` tool, - Pango and its development headers, - and Cairo and its development headers. Instructions for popular systems / package managers are given below. ::::{tab-set} :::{tab-item} Debian-based / apt ```bash sudo apt update sudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev ``` ::: :::{tab-item} Fedora / dnf ```bash sudo dnf install python3-devel pkg-config cairo-devel pango-devel ``` ::: :::{tab-item} Arch Linux / pacman ```bash sudo pacman -Syu base-devel cairo pango ``` ::: :::: As soon as the required dependencies are installed, you can create a Python project (feel free to change the name *manimations* used below to some other name) with a local environment containing Manim by running ```bash uv init manimations cd manimations uv add manim ``` ::::: :::::: To verify that your local Python project is setup correctly and that Manim is available, simply run ```bash uv run manim checkhealth ``` At this point, you can also open your project folder with the IDE of your choice. All modern Python IDEs (for example VS Code with the Python extension, or PyCharm) should automatically detect the local environment created by `uv` such that if you put ```py import manim ``` into a new file `my-first-animation.py`, the import is resolved correctly and autocompletion is available. *Happy Manimating!* :::{dropdown} Alternative: Installing Manim as a global `uv`-managed tool If you have Manim projects in many different directories and you do not want to setup a local project environment for each of them, you could also install Manim as a `uv`-managed tool. See [`uv`'s documentation for more information](https://docs.astral.sh/uv/concepts/tools/) on their tool mechanism. To install Manim as a global `uv` tool, simply run ```bash uv tool install manim ``` after which the `manim` executable will be available on your global system path, without the need to activate any virtual environment or prefixing your commands with `uv run`. Note that when using this approach, setting up your code editor to properly resolve `import manim` requires additional work, as the global tool environment is not automatically detected: the base path of all tool environments can be determined by running ``` uv tool dir ``` which should now contain a directory `manim` in which the appropriate virtual environment is located. Set the Python interpreter of your IDE to this environment to make imports properly resolve themselves. ::: :::{dropdown} Installing Manim for a different version of Python In case you would like to use a different version of Python (for example, due to compatibility issues with other packages), then `uv` allows you to do so in a fairly straightforward way. When initializing the local Python project, simply pass the Python version you want to use as an argument to the `init` command: ``` uv init --python 3.12 manimations cd manimations uv add manim ``` To change the version for an existing package, you will need to edit the `pyproject.toml` file. If you are downgrading the python version, the `requires-python` entry needs to be updated such that your chosen version satisfies the requirement. Change the line to, for example `requires-python = ">=3.12"`. After that, run `uv python pin 3.12` to pin the python version to `3.12`. Finally, run `uv sync`, and your environment is updated! ::: :::{dropdown} Installing the latest development version If you want to install the latest (potentially unstable!) development version of Manim from our source repository [on GitHub](https://github.com/ManimCommunity/manim), then simply run ```bash uv add git+https://github.com/ManimCommunity/manim.git@main ``` ::: ================================================ FILE: docs/source/installation.rst ================================================ Installation ============ Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try. Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (preferably to some isolated virtual Python environment, or a conda-like environment, or via Docker). .. warning:: Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :ref:`differences between Manim versions ` if you are unsure which version you should install. #. :ref:`(Recommended) Installing Manim via Python's package manager pip ` #. :ref:`Installing Manim to a conda environment ` #. :ref:`Using Manim via Docker ` #. :ref:`Interactive Jupyter notebooks via Binder / Google Colab ` .. _local-installation: Installing Manim locally via pip ******************************** The recommended way of installing Manim is by using Python's package manager pip. If you already have a Python environment set up, you can simply run ``pip install manim`` to install the library. Our :doc:`local installation guide ` provides more detailed instructions, including best practices for setting up a suitable local environment. .. toctree:: :hidden: installation/uv .. _conda-installation: Installing Manim via Conda and related environment managers *********************************************************** Conda is a package manager for Python that allows creating environments where all your dependencies are stored. Like this, you don't clutter up your PC with unwanted libraries and you can just delete the environment when you don't need it anymore. It is a good way to install manim since all dependencies like ``pycairo``, etc. come with it. Also, the installation steps are the same, no matter if you are on Windows, Linux, Intel Macs or on Apple Silicon. .. NOTE:: There are various popular alternatives to Conda like `mamba `__ / `micromamba `__, or `pixi `__. They all can be used to setup a suitable, isolated environment for your Manim projects. The following pages show how to install Manim in a conda environment: .. toctree:: :maxdepth: 2 installation/conda .. _docker-installation: Using Manim via Docker ********************** `Docker `__ is a virtualization tool that allows the distribution of encapsulated software environments (containers). The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``: .. toctree:: installation/docker .. _interactive-online: Interactive Jupyter notebooks for your browser ********************************************** Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks `__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook. The following pages explain how you can setup interactive environments like that yourself: .. toctree:: installation/jupyter .. _editor-addons: Editors ******** If you're using Visual Studio Code you can install an extension called *Manim Sideview* which provides automated rendering and an integrated preview of the animation inside the editor. The extension can be installed through the `marketplace of VS Code `__. .. caution:: This extension is not officially maintained by the Manim Community. If you run into issues, please report them to the extension's author. Installation for developers *************************** In order to change code in the library, it is recommended to install Manim in a different way. Please follow the instructions in our :doc:`contribution guide ` if you are interested in that. ================================================ FILE: docs/source/plugins.rst ================================================ .. _plugins: ======= Plugins ======= Plugins are features that extend Manim's core functionality. Since Manim is extensible and not everything belongs in its core, we'll go over how to install, use, and create your own plugins. .. note:: The standard naming convention for plugins is to prefix the plugin with ``manim-``. This makes them easy for users to find on package repositories such as PyPI. .. WARNING:: The plugin feature is new and under active development. Expect updates for the best practices on installing, using, and creating plugins; as well as new subcommands/flags for ``manim plugins`` .. tip:: See https://plugins.manim.community/ for the list of plugins available. Installing Plugins ****************** Plugins can be easily installed via the ``pip`` command: .. code-block:: bash pip install manim-* After installing a plugin, you may use the ``manim plugins`` command to list your available plugins, see the following help output: .. code-block:: bash manim plugins -h Usage: manim plugins [OPTIONS] Manages Manim plugins. Options: -l, --list List available plugins -h, --help Show this message and exit. Made with <3 by Manim Community developers. You can list plugins as such: .. code-block:: bash manim plugins -l Plugins: • manim_plugintemplate Using Plugins in Projects ************************* For enabling a plugin ``manim.cfg`` or command line parameters should be used. .. important:: The plugins should be module name of the plugin and not PyPi name. Enabling plugins through ``manim.cfg`` .. code-block:: ini [CLI] plugins = manim_rubikscube For specifying multiple plugins, comma-separated values must be used. .. code-block:: ini [CLI] plugins = manim_rubikscube, manim_plugintemplate Creating Plugins **************** Plugins are intended to extend Manim's core functionality. If you aren't sure whether a feature should be included in Manim's core, feel free to ask over on the `Discord server `_. Visit `manim-plugintemplate `_ on PyPI.org which serves as an in-depth tutorial for creating plugins. .. code-block:: bash pip install manim-plugintemplate The only requirement of manim plugins is that they specify an entry point with the group, ``"manim.plugins"``. This allows Manim to discover plugins available in the user's environment. Everything regarding the plugin's directory structure, build system, and naming are completely up to your discretion as an author. The standard way to specify an entry point (see `the Python packaging guide `__ for details) is to include the following in your ``pyproject.toml``: .. code-block:: toml [project.entry-points."manim.plugins"] "name" = "object_reference" .. versionremoved:: 0.18.1 Plugins should be imported explicitly to be usable in user code. The plugin system will probably be refactored in the future to provide a more structured interface. A note on Renderer Compatibility ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Depending on which renderer is currently active, custom mobjects created in your plugin might want to behave differently as the corresponding mobject base classes are (unfortunately) not fully compatible. The currently active renderer can be queried by checking the value of ``manim.config.renderer``. All possible renderer types are given by :class:`.constants.RendererType`. The module :mod:`.manim.mobject.utils` contains utility functions that return the base class for the currently active renderer. A simple form of renderer compatibility (by hot-swapping the class inheritance chain) for Mobjects directly inheriting from :class:`.Mobject` or :class:`.VMobject` can be achieved by using the :class:`.mobject.opengl.opengl_compatibility.ConvertToOpenGL` metaclass. ================================================ FILE: docs/source/reference.rst ================================================ Reference Manual ================ This reference manual details modules, functions, and variables included in Manim, describing what they are and what they do. For learning how to use Manim, see :doc:`tutorials/index`. For a list of changes since the last release, see the :doc:`changelog`. .. warning:: The pages linked to here are currently a work in progress. Inheritance Graphs ------------------ Animations ********** .. inheritance-diagram:: manim.animation.animation manim.animation.changing manim.animation.composition manim.animation.creation manim.animation.fading manim.animation.growing manim.animation.indication manim.animation.movement manim.animation.numbers manim.animation.rotation manim.animation.specialized manim.animation.speedmodifier manim.animation.transform manim.animation.transform_matching_parts manim.animation.updaters.mobject_update_utils manim.animation.updaters.update :parts: 1 :top-classes: manim.animation.animation.Animation Cameras ******* .. inheritance-diagram:: manim.camera.camera manim.camera.mapping_camera manim.camera.moving_camera manim.camera.multi_camera manim.camera.three_d_camera :parts: 1 :top-classes: manim.camera.camera.Camera, manim.mobject.mobject.Mobject Mobjects ******** .. inheritance-diagram:: manim.mobject.frame manim.mobject.geometry.arc manim.mobject.geometry.boolean_ops manim.mobject.geometry.line manim.mobject.geometry.polygram manim.mobject.geometry.shape_matchers manim.mobject.geometry.tips manim.mobject.graph manim.mobject.graphing.coordinate_systems manim.mobject.graphing.functions manim.mobject.graphing.number_line manim.mobject.graphing.probability manim.mobject.graphing.scale manim.mobject.logo manim.mobject.matrix manim.mobject.mobject manim.mobject.table manim.mobject.three_d.polyhedra manim.mobject.three_d.three_d_utils manim.mobject.three_d.three_dimensions manim.mobject.svg.brace manim.mobject.svg.svg_mobject manim.mobject.text.code_mobject manim.mobject.text.numbers manim.mobject.text.tex_mobject manim.mobject.text.text_mobject manim.mobject.types.image_mobject manim.mobject.types.point_cloud_mobject manim.mobject.types.vectorized_mobject manim.mobject.value_tracker manim.mobject.vector_field :parts: 1 :top-classes: manim.mobject.mobject.Mobject Scenes ****** .. inheritance-diagram:: manim.scene.moving_camera_scene manim.scene.scene manim.scene.scene_file_writer manim.scene.three_d_scene manim.scene.vector_space_scene manim.scene.zoomed_scene :parts: 1 :top-classes: manim.scene.scene.Scene, manim.scene.scene.RerunSceneHandler Module Index ------------ .. toctree:: :maxdepth: 3 reference_index/animations reference_index/cameras reference_index/configuration reference_index/mobjects reference_index/scenes reference_index/utilities_misc ================================================ FILE: docs/source/reference_index/animations.rst ================================================ Animations ========== .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~animation.animation ~animation.changing ~animation.composition ~animation.creation ~animation.fading ~animation.growing ~animation.indication ~animation.movement ~animation.numbers ~animation.rotation ~animation.specialized ~animation.speedmodifier ~animation.transform ~animation.transform_matching_parts ~animation.updaters ================================================ FILE: docs/source/reference_index/cameras.rst ================================================ Cameras ======= .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~camera.camera ~camera.mapping_camera ~camera.moving_camera ~camera.multi_camera ~camera.three_d_camera ================================================ FILE: docs/source/reference_index/configuration.rst ================================================ Configuration ============= Module Index ------------ .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~_config ~_config.utils ~_config.logger_utils ================================================ FILE: docs/source/reference_index/mobjects.rst ================================================ Mobjects ======== .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~mobject.frame ~mobject.geometry ~mobject.graph ~mobject.graphing ~mobject.logo ~mobject.matrix ~mobject.mobject ~mobject.svg ~mobject.table ~mobject.text ~mobject.three_d ~mobject.types ~mobject.utils ~mobject.value_tracker ~mobject.vector_field ================================================ FILE: docs/source/reference_index/scenes.rst ================================================ Scenes ====== .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~scene.moving_camera_scene ~scene.section ~scene.scene ~scene.scene_file_writer ~scene.three_d_scene ~scene.vector_space_scene ~scene.zoomed_scene ================================================ FILE: docs/source/reference_index/utilities_misc.rst ================================================ Utilities and other modules =========================== Module Index ------------ .. currentmodule:: manim .. autosummary:: :toctree: ../reference ~utils.bezier cli ~utils.color ~utils.commands ~utils.config_ops constants data_structures ~utils.debug ~utils.deprecation ~utils.docbuild ~utils.hashing ~utils.images ~utils.ipython_magic ~utils.iterables ~utils.paths ~utils.rate_functions ~utils.simple_functions ~utils.sounds ~utils.space_ops ~utils.testing ~utils.tex ~utils.tex_file_writing ~utils.tex_templates typing ================================================ FILE: docs/source/robots.txt ================================================ User-agent: * Disallow: / Allow: /en/stable/ Sitemap: https://docs.manim.community/sitemap.xml ================================================ FILE: docs/source/tutorials/building_blocks.rst ================================================ ####################### Manim's building blocks ####################### This document explains the building blocks of manim and will give you all the necessary tools to start producing your own videos. Essentially, manim puts at your disposal three different concepts that you can orchestrate together to produce mathematical animations: the **mathematical object** (or **mobject** for short), the **animation**, and the **scene**. As we will see in the following sections, each of these three concepts is implemented in manim as a separate class: the :class:`.Mobject`, :class:`.Animation`, and :class:`.Scene` classes. .. note:: It is recommended that you read the tutorials :doc:`quickstart` and :doc:`output_and_config` before reading this page. ******** Mobjects ******** Mobjects are the basic building blocks for all manim animations. Each class that derives from :class:`.Mobject` represents an object that can be displayed on the screen. For example, simple shapes such as :class:`.Circle`, :class:`.Arrow`, and :class:`.Rectangle` are all mobjects. More complicated constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or :class:`.BarChart` are mobjects as well. If you try to display an instance of :class:`.Mobject` on the screen, you will only see an empty frame. The reason is that the :class:`.Mobject` class is an abstract base class of all other mobjects, i.e. it does not have any pre-determined visual shape that can be displayed on the screen. It is only the skeleton of a thing that *could* be displayed. Therefore, you will rarely need to use plain instances of :class:`.Mobject`; instead, you will most likely create instances of its derived classes. One of these derived classes is :class:`.VMobject`. The ``V`` stands for Vectorized Mobject. In essence, a vmobject is a mobject that uses `vector graphics `_ to be displayed. Most of the time, you will be dealing with vmobjects, though we will continue to use the term "mobject" to refer to the class of shapes that can be displayed on the screen, as it is more general. .. note:: Any object that can be displayed on the screen is a ``mobject``, even if it is not necessarily *mathematical* in nature. .. tip:: To see examples of classes derived from :class:`.Mobject`, see the :mod:`.geometry` module. Most of these are in fact derived from :class:`.VMobject` as well. Creating and displaying mobjects ================================ As explained in :doc:`quickstart`, usually all of the code in a manim script is put inside the :meth:`.construct` method of a :class:`.Scene` class. To display a mobject on the screen, call the :meth:`~.Scene.add` method of the containing :class:`.Scene`. This is the principal way of displaying a mobject on the screen when it is not being animated. To remove a mobject from the screen, simply call the :meth:`~.Scene.remove` method from the containing :class:`.Scene`. .. manim:: CreatingMobjects class CreatingMobjects(Scene): def construct(self): circle = Circle() self.add(circle) self.wait(1) self.remove(circle) self.wait(1) Placing mobjects ================ Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add` some mobjects to it. This script generates a static picture that displays a circle, a square, and a triangle: .. manim:: Shapes class Shapes(Scene): def construct(self): circle = Circle() square = Square() triangle = Triangle() circle.shift(LEFT) square.shift(UP) triangle.shift(RIGHT) self.add(circle, square, triangle) self.wait(1) By default, mobjects are placed at the center of coordinates, or *origin*, when they are first created. They are also given some default colors. Further, the ``Shapes`` scene places the mobjects by using the :meth:`.shift` method. The square is shifted one unit in the ``UP`` direction from the origin, while the circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively. .. attention:: Unlike other graphics software, manim places the center of coordinates at the center of the screen. The positive vertical direction is up, and the positive horizontal direction is right. See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT``, and others, defined in the :mod:`.constants` module. There are many other possible ways to place mobjects on the screen, for example :meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`. The next scene ``MobjectPlacement`` uses all three. .. manim:: MobjectPlacement class MobjectPlacement(Scene): def construct(self): circle = Circle() square = Square() triangle = Triangle() # place the circle two units left from the origin circle.move_to(LEFT * 2) # place the square to the left of the circle square.next_to(circle, LEFT) # align the left border of the triangle to the left border of the circle triangle.align_to(circle, LEFT) self.add(circle, square, triangle) self.wait(1) The :meth:`.move_to` method uses absolute units (measured relative to the ``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the mobject passed as the first argument). :meth:`align_to` uses ``LEFT`` not as measuring units but as a way to determine the border to use for alignment. The coordinates of the borders of a mobject are determined using an imaginary bounding box around it. .. tip:: Many methods in manim can be chained together. For example the two lines .. code-block:: python square = Square() square.shift(LEFT) can be replaced by .. code-block:: python square = Square().shift(LEFT) Technically, this is possible because most methods calls return the modified mobject. Styling mobjects ================ The following scene changes the default aesthetics of the mobjects. .. manim:: MobjectStyling class MobjectStyling(Scene): def construct(self): circle = Circle().shift(LEFT) square = Square().shift(UP) triangle = Triangle().shift(RIGHT) circle.set_stroke(color=GREEN, width=20) square.set_fill(YELLOW, opacity=1.0) triangle.set_fill(PINK, opacity=0.5) self.add(circle, square, triangle) self.wait(1) This scene uses two of the main functions that change the visual style of a mobject: :meth:`.set_stroke` and :meth:`.set_fill`. The former changes the visual style of the mobject's border while the latter changes the style of the interior. By default, most mobjects have a fully transparent interior so you must specify the ``opacity`` parameter to display the color. An opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent. Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and :meth:`.set_fill`. Instances of :class:`.Mobject` implement :meth:`.~Mobject.set_color` instead. The vast majority of pre-defined classes are derived from :class:`.VMobject` so it is usually safe to assume that you have access to :meth:`.set_stroke` and :meth:`.set_fill`. Mobject on-screen order ======================= The next scene is exactly the same as the ``MobjectStyling`` scene from the previous section, except for exactly one line. .. manim:: MobjectZOrder class MobjectZOrder(Scene): def construct(self): circle = Circle().shift(LEFT) square = Square().shift(UP) triangle = Triangle().shift(RIGHT) circle.set_stroke(color=GREEN, width=20) square.set_fill(YELLOW, opacity=1.0) triangle.set_fill(PINK, opacity=0.5) self.add(triangle, square, circle) self.wait(1) The only difference here (besides the scene name) is the order in which the mobjects are added to the scene. In ``MobjectStyling``, we added them as ``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as ``add(triangle, square, circle)``. As you can see, the order of the arguments of :meth:`~.Scene.add` determines the order that the mobjects are displayed on the screen, with the left-most arguments being put in the back. ********** Animations ********** At the heart of manim is animation. Generally, you can add an animation to your scene by calling the :meth:`~.Scene.play` method. .. manim:: SomeAnimations class SomeAnimations(Scene): def construct(self): square = Square() # some animations display mobjects, ... self.play(FadeIn(square)) # ... some move or rotate mobjects around... self.play(Rotate(square, PI/4)) # some animations remove mobjects from the screen self.play(FadeOut(square)) self.wait(1) Put simply, animations are procedures that interpolate between two mobjects. For example, :code:`FadeIn(square)` starts with a fully transparent version of :code:`square` and ends with a fully opaque version, interpolating between them by gradually increasing the opacity. :class:`.FadeOut` works in the opposite way: it interpolates from fully opaque to fully transparent. As another example, :class:`.Rotate` starts with the mobject passed to it as argument, and ends with the same object but rotated by a certain amount, this time interpolating the mobject's angle instead of its opacity. Animating methods ================= Any property of a mobject that can be changed can be animated. In fact, any method that changes a mobject's property can be used as an animation, through the use of :meth:`.animate`. .. manim:: AnimateExample :ref_classes: Animation class AnimateExample(Scene): def construct(self): square = Square().set_fill(RED, opacity=1.0) self.add(square) # animate the change of color self.play(square.animate.set_fill(WHITE)) self.wait(1) # animate the change of position and the rotation at the same time self.play(square.animate.shift(UP).rotate(PI / 3)) self.wait(1) :meth:`.animate` is a property of all mobjects that animates the methods that come afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of the square, while :code:`square.animate.set_fill(WHITE)` animates this action. Animation run time ================== By default, any animation passed to :meth:`play` lasts for exactly one second. Use the :code:`run_time` argument to control the duration. .. manim:: RunTime class RunTime(Scene): def construct(self): square = Square() self.add(square) self.play(square.animate.shift(UP), run_time=3) self.wait(1) Creating a custom animation =========================== Even though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another. If you find yourself in that situation, then you can define your own custom animation. You start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`. The :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation. So, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method. Then you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions. Let's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number. You can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number. But when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly. Manim has a feature that allows you to customize this behavior by defining your own custom animation. You can start by creating your own ``Count`` class that extends :class:`~.Animation`. The class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end. The constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end. The only thing that you need to do is to define how you want it to look at every step of the animation. Manim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played. The alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation. For example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation. In the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation. Suppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation. * If alpha is 0, you want the value to be 50. * If alpha is 0.5, you want the value to be 75. * If alpha is 1, you want the value to be 100. Generally, you start with the starting number and add only some part of the value to be increment according to the alpha value. So, the logic of calculating the number to display at each step will be ``50 + alpha * (100 - 50)``. Once you set the calculated value for the :class:`~.DecimalNumber`, you are done. .. note:: If you're creating a custom animation and want to use a ``rate_func``, you must explicitly apply ``self.rate_func(alpha)`` to the parameter you're animating. For example, try switching the rate function to ``rate_functions.there_and_back`` to observe how it affects the counting behavior. Once you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function. .. manim:: CountingScene :ref_classes: Animation DecimalNumber :ref_methods: Animation.interpolate_mobject Scene.play class Count(Animation): def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs) -> None: # Pass number as the mobject of the animation super().__init__(number, **kwargs) # Set start and end self.start = start self.end = end def interpolate_mobject(self, alpha: float) -> None: # Set value of DecimalNumber according to alpha value = self.start + (self.rate_func(alpha) * (self.end - self.start)) self.mobject.set_value(value) class CountingScene(Scene): def construct(self): # Create Decimal Number and add it to scene number = DecimalNumber().set_color(WHITE).scale(5) # Add an updater to keep the DecimalNumber centered as its value changes number.add_updater(lambda number: number.move_to(ORIGIN)) self.add(number) self.wait() # Play the Count Animation to count from 0 to 100 in 4 seconds self.play(Count(number, 0, 100), run_time=4, rate_func=linear) self.wait() Using coordinates of a mobject ============================== Mobjects contain points that define their boundaries. These points can be used to add other mobjects respectively to each other, e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates: .. manim:: MobjectExample :save_last_frame: class MobjectExample(Scene): def construct(self): p1 = [-1,-1, 0] p2 = [ 1,-1, 0] p3 = [ 1, 1, 0] p4 = [-1, 1, 0] a = Line(p1,p2).append_points(Line(p2,p3).points).append_points(Line(p3,p4).points) point_start = a.get_start() point_end = a.get_end() point_center = a.get_center() self.add(Text(f"a.get_start() = {np.round(point_start,2).tolist()}", font_size=24).to_edge(UR).set_color(YELLOW)) self.add(Text(f"a.get_end() = {np.round(point_end,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(RED)) self.add(Text(f"a.get_center() = {np.round(point_center,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(BLUE)) self.add(Dot(a.get_start()).set_color(YELLOW).scale(2)) self.add(Dot(a.get_end()).set_color(RED).scale(2)) self.add(Dot(a.get_top()).set_color(GREEN_A).scale(2)) self.add(Dot(a.get_bottom()).set_color(GREEN_D).scale(2)) self.add(Dot(a.get_center()).set_color(BLUE).scale(2)) self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2)) self.add(*[Dot(x) for x in a.points]) self.add(a) Transforming mobjects into other mobjects ========================================= It is also possible to transform a mobject into another mobject like this: .. manim:: ExampleTransform class ExampleTransform(Scene): def construct(self): self.camera.background_color = WHITE m1 = Square().set_color(RED) m2 = Rectangle().set_color(RED).rotate(0.2) self.play(Transform(m1,m2)) The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the `flip` function and reposition the points via the `roll `_ function of numpy: .. manim:: ExampleRotation class ExampleRotation(Scene): def construct(self): self.camera.background_color = WHITE m1a = Square().set_color(RED).shift(LEFT) m1b = Circle().set_color(RED).shift(LEFT) m2a = Square().set_color(BLUE).shift(RIGHT) m2b = Circle().set_color(BLUE).shift(RIGHT) points = m2a.points points = np.roll(points, int(len(points)/4), axis=0) m2a.points = points self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1) ****** Scenes ****** The :class:`.Scene` class is the connective tissue of manim. Every mobject has to be :meth:`added <.Scene.add>` to a scene to be displayed, or :meth:`removed <.Scene.remove>` from it to cease being displayed. Every animation has to be :meth:`played <.Scene.play>` by a scene, and every time interval where no animation occurs is determined by a call to :meth:`~.Scene.wait`. All of the code of your video must be contained in the :meth:`~.Scene.construct` method of a class that derives from :class:`.Scene`. Finally, a single file may contain multiple :class:`.Scene` subclasses if multiple scenes are to be rendered at the same time. ================================================ FILE: docs/source/tutorials/index.rst ================================================ Tutorials ========= .. toctree:: :caption: Table of Contents :maxdepth: 2 quickstart output_and_config building_blocks ================================================ FILE: docs/source/tutorials/output_and_config.rst ================================================ Manim's Output Settings ======================= This document will focus on understanding manim's output files and some of the main command-line flags available. .. note:: This tutorial picks up where :doc:`quickstart` left off, so please read that document before starting this one. Manim output folders ******************** At this point, you have just executed the following command. .. code-block:: bash manim -pql scene.py SquareToCircle Let's dissect what just happened step by step. First, this command executes manim on the file ``scene.py``, which contains our animation code. Further, this command tells manim exactly which ``Scene`` is to be rendered, in this case, it is ``SquareToCircle``. This is necessary because a single scene file may contain more than one scene. Next, the flag `-p` tells manim to play the scene once it's rendered, and the `-ql` flag tells manim to render the scene in low quality. After the video is rendered, you will see that manim has generated some new files and the project folder will look as follows. .. code-block:: bash project/ ├─scene.py └─media ├─videos | └─scene | └─480p15 | ├─SquareToCircle.mp4 | └─partial_movie_files ├─text └─Tex There are quite a few new files. The main output is in ``media/videos/scene/480p15/SquareToCircle.mp4``. By default, the ``media`` folder will contain all of manim's output files. The ``media/videos`` subfolder contains the rendered videos. Inside of it, you will find one folder for each different video quality. In our case, since we used the ``-l`` flag, the video was generated at 480 resolution at 15 frames per second from the ``scene.py`` file. Therefore, the output can be found inside ``media/videos/scene/480p15``. The additional folders ``media/videos/scene/480p15/partial_movie_files`` as well as ``media/text`` and ``media/Tex`` contain files that are used by manim internally. You can see how manim makes use of the generated folder structure by executing the following command, .. code-block:: bash manim -pqh scene.py SquareToCircle The ``-ql`` flag (for low quality) has been replaced by the ``-qh`` flag, for high quality. Manim will take considerably longer to render this file, and it will play it once it's done since we are using the ``-p`` flag. The output should look like this: .. manim:: SquareToCircle3 :hide_source: :quality: high class SquareToCircle3(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set color and transparency square = Square() # create a square square.flip(RIGHT) # flip horizontally square.rotate(-3 * TAU / 8) # rotate a certain amount self.play(Create(square)) # animate the creation of the square self.play(Transform(square, circle)) # interpolate the square into the circle self.play(FadeOut(square)) # fade out animation And the folder structure should look as follows. .. code-block:: bash project/ ├─scene.py └─media ├─videos | └─scene | ├─480p15 | | ├─SquareToCircle.mp4 | | └─partial_movie_files | └─1080p60 | ├─SquareToCircle.mp4 | └─partial_movie_files ├─text └─Tex Manim has created a new folder ``media/videos/1080p60``, which corresponds to the high resolution and the 60 frames per second. Inside of it, you can find the new ``SquareToCircle.mp4``, as well as the corresponding ``partial_movie_files``. When working on a project with multiple scenes, and trying out multiple resolutions, the structure of the output directories will keep all your videos organized. Further, manim has the option to output the last frame of a scene, when adding the flag ``-s``. This is the fastest option to quickly get a preview of a scene. The corresponding folder structure looks like this: .. code-block:: bash project/ ├─scene.py └─media ├─images | └─scene | ├─SquareToCircle.png ├─videos | └─scene | ├─480p15 | | ├─SquareToCircle.mp4 | | └─partial_movie_files | └─1080p60 | ├─SquareToCircle.mp4 | └─partial_movie_files ├─text └─Tex Saving the last frame with ``-s`` can be combined with the flags for different resolutions, e.g. ``-s -ql``, ``-s -qh`` Sections ******** In addition to the movie output file one can use sections. Each section produces its own output video. The cuts between two sections can be set like this: .. code-block:: python def construct(self): # play the first animations... # you don't need a section in the very beginning as it gets created automatically self.next_section() # play more animations... self.next_section("this is an optional name that doesn't have to be unique") # play even more animations... self.next_section("this is a section without any animations, it will be removed") All the animations between two of these cuts get concatenated into a single output video file. Be aware that you need at least one animation in each section. For example this wouldn't create an output video: .. code-block:: python def construct(self): self.next_section() # this section doesn't have any animations and will be removed # but no error will be thrown # feel free to tend your flock of empty sections if you so desire self.add(Circle()) self.next_section() One way of fixing this is to wait a little: .. code-block:: python def construct(self): self.next_section() self.add(Circle()) # now we wait 1sec and have an animation to satisfy the section self.wait() self.next_section() For videos to be created for each section you have to add the ``--save_sections`` flag to the Manim call like this: .. code-block:: bash manim --save_sections scene.py If you do this, the ``media`` folder will look like this: .. code-block:: bash media ├── images │ └── simple_scenes └── videos └── simple_scenes └── 480p15 ├── ElaborateSceneWithSections.mp4 ├── partial_movie_files │ └── ElaborateSceneWithSections │ ├── 2201830969_104169243_1331664314.mp4 │ ├── 2201830969_398514950_125983425.mp4 │ ├── 2201830969_398514950_3447021159.mp4 │ ├── 2201830969_398514950_4144009089.mp4 │ ├── 2201830969_4218360830_1789939690.mp4 │ ├── 3163782288_524160878_1793580042.mp4 │ └── partial_movie_file_list.txt └── sections ├── ElaborateSceneWithSections_0000.mp4 ├── ElaborateSceneWithSections_0001.mp4 ├── ElaborateSceneWithSections_0002.mp4 └── ElaborateSceneWithSections.json As you can see each section receives their own output video in the ``sections`` directory. The JSON file in here contains some useful information for each section: .. code-block:: json [ { "name": "create square", "type": "default.normal", "video": "ElaborateSceneWithSections_0000.mp4", "codec_name": "h264", "width": 854, "height": 480, "avg_frame_rate": "15/1", "duration": "2.000000", "nb_frames": "30" }, { "name": "transform to circle", "type": "default.normal", "video": "ElaborateSceneWithSections_0001.mp4", "codec_name": "h264", "width": 854, "height": 480, "avg_frame_rate": "15/1", "duration": "2.000000", "nb_frames": "30" }, { "name": "fade out", "type": "default.normal", "video": "ElaborateSceneWithSections_0002.mp4", "codec_name": "h264", "width": 854, "height": 480, "avg_frame_rate": "15/1", "duration": "2.000000", "nb_frames": "30" } ] This data can be used by third party applications, like a presentation system or automated video editing tool. You can also skip rendering all animations belonging to a section like this: .. code-block:: python def construct(self): self.next_section(skip_animations=True) # play some animations that shall be skipped... self.next_section() # play some animations that won't get skipped... Some command line flags *********************** When executing the command .. code-block:: bash manim -pql scene.py SquareToCircle it specifies the scene to render. This is not necessary now. When a single file contains only one ``Scene`` class, it will just render the ``Scene`` class. When a single file contains more than one ``Scene`` class, manim will let you choose a ``Scene`` class. If your file contains multiple ``Scene`` classes, and you want to render them all, you can use the ``-a`` flag. As discussed previously, the ``-ql`` specifies low render quality (854x480 15FPS). This does not look very good, but is very useful for rapid prototyping and testing. The other options that specify render quality are ``-qm``, ``-qh``, ``-qp`` and ``-qk`` for medium (1280x720 30FPS), high (1920x1080 60FPS), 2k (2560x1440 60FPS) and 4k quality (3840x2160 60FPS), respectively. The ``-p`` flag plays the animation once it is rendered. If you want to open the file browser at the location of the animation instead of playing it, you can use the ``-f`` flag. You can also omit these two flags. Finally, by default manim will output .mp4 files. If you want your animations in .gif format instead, use the ``--format gif`` flag. The output files will be in the same folder as the .mp4 files, and with the same name, but a different file extension. This was a quick review of some of the most frequent command-line flags. For a thorough review of all flags available, see the :doc:`thematic guide on Manim's configuration system `. ================================================ FILE: docs/source/tutorials/quickstart.rst ================================================ ========== Quickstart ========== .. note:: Before proceeding, install Manim and make sure it is running properly by following the steps in :doc:`../installation`. For information on using Manim with Jupyterlab or Jupyter notebook, go to the documentation for the :meth:`IPython magic command `, ``%%manim``. .. important:: If you installed Manim in the recommended way, using the Python management tool ``uv``, then you either need to make sure the corresponding virtual environment is activated (follow the instructions printed on running ``uv venv``), or you need to remember to prefix the ``manim`` command in the console with ``uv run``; that is, ``uv run manim ...``. Overview ******** This quickstart guide will lead you through creating a sample project using Manim: an animation engine for precise programmatic animations. First, you will use a command line interface to create a ``Scene``, the class through which Manim generates videos. In the ``Scene`` you will animate a circle. Then you will add another ``Scene`` showing a square transforming into a circle. This will be your introduction to Manim's animation ability. Afterwards, you will position multiple mathematical objects (``Mobject``\s). Finally, you will learn the ``.animate`` syntax, a powerful feature that animates the methods you use to modify ``Mobject``\s. Starting a new project ********************** Start by creating a new folder:: manim init project my-project --default The ``my-project`` folder is the root folder for your project. It contains all the files that Manim needs to function, as well as any output that your project produces. Animating a circle ****************** 1. Open a text editor, such as Notepad. Open the file ``main.py`` in the ``my-project`` folder. It should look something like this: .. code-block:: python from manim import * class CreateCircle(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set the color and transparency self.play(Create(circle)) # show the circle on screen 2. Open the command line, navigate to your project folder, and execute the following command: .. code-block:: bash manim -pql main.py CreateCircle Manim will output rendering information, then create an MP4 file. Your default movie player will play the MP4 file, displaying the following animation. .. manim:: CreateCircle :hide_source: class CreateCircle(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set the color and transparency self.play(Create(circle)) # show the circle on screen If you see an animation of a pink circle being drawn, congratulations! You just wrote your first Manim scene from scratch. If you get an error message instead, you do not see a video, or if the video output does not look like the preceding animation, it is likely that Manim has not been installed correctly. Please refer to our :doc:`FAQ section ` for help with the most common issues. *********** Explanation *********** Let's go over the script you just executed line by line to see how Manim was able to draw the circle. The first line imports all of the contents of the library: .. code-block:: python from manim import * This is the recommended way of using Manim, as a single script often uses multiple names from the Manim namespace. In your script, you imported and used ``Scene``, ``Circle``, ``PINK`` and ``Create``. Now let's look at the next two lines: .. code-block:: python class CreateCircle(Scene): def construct(self): [...] Most of the time, the code for scripting an animation is entirely contained within the :meth:`~.Scene.construct` method of a :class:`.Scene` class. Inside :meth:`~.Scene.construct`, you can create objects, display them on screen, and animate them. The next two lines create a circle and set its color and opacity: .. code-block:: python circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set the color and transparency Finally, the last line uses the animation :class:`.Create` to display the circle on your screen: .. code-block:: python self.play(Create(circle)) # show the circle on screen .. tip:: All animations must reside within the :meth:`~.Scene.construct` method of a class derived from :class:`.Scene`. Other code, such as auxiliary or mathematical functions, may reside outside the class. Transforming a square into a circle *********************************** With our circle animation complete, let's move on to something a little more complicated. 1. Open ``scene.py``, and add the following code snippet below the ``CreateCircle`` class: .. code-block:: python class SquareToCircle(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set color and transparency square = Square() # create a square square.rotate(PI / 4) # rotate a certain amount self.play(Create(square)) # animate the creation of the square self.play(Transform(square, circle)) # interpolate the square into the circle self.play(FadeOut(square)) # fade out animation 2. Render ``SquareToCircle`` by running the following command in the command line: .. code-block:: bash manim -pql scene.py SquareToCircle The following animation will render: .. manim:: SquareToCircle2 :hide_source: class SquareToCircle2(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set color and transparency square = Square() # create a square square.rotate(PI / 4) # rotate a certain amount self.play(Create(square)) # animate the creation of the square self.play(Transform(square, circle)) # interpolate the square into the circle self.play(FadeOut(square)) # fade out animation This example shows one of the primary features of Manim: the ability to implement complicated and mathematically intensive animations (such as cleanly interpolating between two geometric shapes) with just a few lines of code. Positioning ``Mobject``\s ************************* Next, let's go over some basic techniques for positioning ``Mobject``\s. 1. Open ``scene.py``, and add the following code snippet below the ``SquareToCircle`` class: .. code-block:: python class SquareAndCircle(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set the color and transparency square = Square() # create a square square.set_fill(BLUE, opacity=0.5) # set the color and transparency square.next_to(circle, RIGHT, buff=0.5) # set the position self.play(Create(circle), Create(square)) # show the shapes on screen 2. Render ``SquareAndCircle`` by running the following command in the command line: .. code-block:: bash manim -pql scene.py SquareAndCircle The following animation will render: .. manim:: SquareAndCircle2 :hide_source: class SquareAndCircle2(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set the color and transparency square = Square() # create a square square.set_fill(BLUE, opacity=0.5) # set the color and transparency square.next_to(circle, RIGHT, buff=0.5) # set the position self.play(Create(circle), Create(square)) # show the shapes on screen ``next_to`` is a ``Mobject`` method for positioning ``Mobject``\s. We first specified the pink circle as the square's reference point by passing ``circle`` as the method's first argument. The second argument is used to specify the direction the ``Mobject`` is placed relative to the reference point. In this case, we set the direction to ``RIGHT``, telling Manim to position the square to the right of the circle. Finally, ``buff=0.5`` applied a small distance buffer between the two objects. Try changing ``RIGHT`` to ``LEFT``, ``UP``, or ``DOWN`` instead, and see how that changes the position of the square. Using positioning methods, you can render a scene with multiple ``Mobject``\s, setting their locations in the scene using coordinates or positioning them relative to each other. For more information on ``next_to`` and other positioning methods, check out the list of :class:`.Mobject` methods in our reference manual. Using ``.animate`` syntax to animate methods ******************************************** The final lesson in this tutorial is using ``.animate``, a ``Mobject`` method which animates changes you make to a ``Mobject``. When you prepend ``.animate`` to any method call that modifies a ``Mobject``, the method becomes an animation which can be played using ``self.play``. Let's return to ``SquareToCircle`` to see the differences between using methods when creating a ``Mobject``, and animating those method calls with ``.animate``. 1. Open ``scene.py``, and add the following code snippet below the ``SquareAndCircle`` class: .. code-block:: python class AnimatedSquareToCircle(Scene): def construct(self): circle = Circle() # create a circle square = Square() # create a square self.play(Create(square)) # show the square on screen self.play(square.animate.rotate(PI / 4)) # rotate the square self.play(Transform(square, circle)) # transform the square into a circle self.play( square.animate.set_fill(PINK, opacity=0.5) ) # color the circle on screen 2. Render ``AnimatedSquareToCircle`` by running the following command in the command line: .. code-block:: bash manim -pql scene.py AnimatedSquareToCircle The following animation will render: .. manim:: AnimatedSquareToCircle2 :hide_source: class AnimatedSquareToCircle2(Scene): def construct(self): circle = Circle() # create a circle square = Square() # create a square self.play(Create(square)) # show the square on screen self.play(square.animate.rotate(PI / 4)) # rotate the square self.play(Transform(square, circle)) # transform the square into a circle self.play(square.animate.set_fill(PINK, opacity=0.5)) # color the circle on screen The first ``self.play`` creates the square. The second animates rotating it 45 degrees. The third transforms the square into a circle, and the last colors the circle pink. Although the end result is the same as that of ``SquareToCircle``, ``.animate`` shows ``rotate`` and ``set_fill`` being applied to the ``Mobject`` dynamically, instead of creating them with the changes already applied. Try other methods, like ``flip`` or ``shift``, and see what happens. 3. Open ``scene.py``, and add the following code snippet below the ``AnimatedSquareToCircle`` class: .. code-block:: python class DifferentRotations(Scene): def construct(self): left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT) right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT) self.play( left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2 ) self.wait() 4. Render ``DifferentRotations`` by running the following command in the command line: .. code-block:: bash manim -pql scene.py DifferentRotations The following animation will render: .. manim:: DifferentRotations2 :hide_source: class DifferentRotations2(Scene): def construct(self): left_square = Square(color=BLUE, fill_opacity=0.7).shift(2*LEFT) right_square = Square(color=GREEN, fill_opacity=0.7).shift(2*RIGHT) self.play(left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2) self.wait() This ``Scene`` illustrates the quirks of ``.animate``. When using ``.animate``, Manim actually takes a ``Mobject``'s starting state and its ending state and interpolates the two. In the ``AnimatedSquareToCircle`` class, you can observe this when the square rotates: the corners of the square appear to contract slightly as they move into the positions required for the first square to transform into the second one. In ``DifferentRotations``, the difference between ``.animate``'s interpretation of rotation and the ``Rotate`` method is far more apparent. The starting and ending states of a ``Mobject`` rotated 180 degrees are the same, so ``.animate`` tries to interpolate two identical objects and the result is the left square. If you find that your own usage of ``.animate`` is causing similar unwanted behavior, consider using conventional animation methods like the right square, which uses ``Rotate``. ``Transform`` vs ``ReplacementTransform`` ***************************************** The difference between ``Transform`` and ``ReplacementTransform`` is that ``Transform(mob1, mob2)`` transforms the points (as well as other attributes like color) of ``mob1`` into the points/attributes of ``mob2``. ``ReplacementTransform(mob1, mob2)`` on the other hand literally replaces ``mob1`` on the scene with ``mob2``. The use of ``ReplacementTransform`` or ``Transform`` is mostly up to personal preference. They can be used to accomplish the same effect, as shown below. .. code-block:: python class TwoTransforms(Scene): def transform(self): a = Circle() b = Square() c = Triangle() self.play(Transform(a, b)) self.play(Transform(a, c)) self.play(FadeOut(a)) def replacement_transform(self): a = Circle() b = Square() c = Triangle() self.play(ReplacementTransform(a, b)) self.play(ReplacementTransform(b, c)) self.play(FadeOut(c)) def construct(self): self.transform() self.wait(0.5) # wait for 0.5 seconds self.replacement_transform() However, in some cases it is more beneficial to use ``Transform``, like when you are transforming several mobjects one after the other. The code below avoids having to keep a reference to the last mobject that was transformed. .. manim:: TransformCycle class TransformCycle(Scene): def construct(self): a = Circle() t1 = Square() t2 = Triangle() self.add(a) self.wait() for t in [t1,t2]: self.play(Transform(a,t)) ************ You're done! ************ With a working installation of Manim and this sample project under your belt, you're ready to start creating animations of your own. To learn more about what Manim is doing under the hood, move on to the next tutorial: :doc:`output_and_config`. For an overview of Manim's features, as well as its configuration and other settings, check out the other :doc:`Tutorials <../tutorials/index>`. For a list of all available features, refer to the :doc:`../reference` page. ================================================ FILE: docs/source/tutorials_guides.rst ================================================ Tutorials & Guides ================== .. toctree:: :caption: Table of Contents :maxdepth: 2 tutorials/index guides/index faq/index ================================================ FILE: example_scenes/advanced_tex_fonts.py ================================================ from manim import * # French Cursive LaTeX font example from http://jf.burnol.free.fr/showcase.html # Example 1 Manually creating a Template TemplateForFrenchCursive = TexTemplate( preamble=r""" \usepackage[english]{babel} \usepackage{amsmath} \usepackage{amssymb} \usepackage[T1]{fontenc} \usepackage[default]{frcursive} \usepackage[eulergreek,noplusnominus,noequal,nohbar,% nolessnomore,noasterisk]{mathastext} """, ) def FrenchCursive(*tex_strings, **kwargs): return Tex(*tex_strings, tex_template=TemplateForFrenchCursive, **kwargs) class TexFontTemplateManual(Scene): """An example scene that uses a manually defined TexTemplate() object to create LaTeX output in French Cursive font """ def construct(self): self.add(Tex("Tex Font Example").to_edge(UL)) self.play(Create(FrenchCursive("$f: A \\longrightarrow B$").shift(UP))) self.play(Create(FrenchCursive("Behold! We can write math in French Cursive"))) self.wait(1) self.play( Create( Tex( "See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html", ).shift(2 * DOWN), ), ) self.wait(2) # Example 2, using a Template from the collection class TexFontTemplateLibrary(Scene): """An example scene that uses TexTemplate objects from the TexFontTemplates collection to create sample LaTeX output in every font that will compile on the local system. Please Note: Many of the in the TexFontTemplates collection require that specific fonts are installed on your local machine. For example, choosing the template TexFontTemplates.comic_sans will not compile if the Comic Sans Microsoft font is not installed. This scene will only render those Templates that do not cause a TeX compilation error on your system. Furthermore, some of the ones that do render, may still render incorrectly. This is beyond the scope of manim. Feel free to experiment. """ def construct(self): def write_one_line(template): x = Tex(template.description, tex_template=template).shift(UP) self.play(Create(x)) self.wait(1) self.play(FadeOut(x)) examples = [ TexFontTemplates.american_typewriter, # "American Typewriter" TexFontTemplates.antykwa, # "Antykwa Półtawskiego (TX Fonts for Greek and math symbols)" TexFontTemplates.apple_chancery, # "Apple Chancery" TexFontTemplates.auriocus_kalligraphicus, # "Auriocus Kalligraphicus (Symbol Greek)" TexFontTemplates.baskervald_adf_fourier, # "Baskervald ADF with Fourier" TexFontTemplates.baskerville_it, # "Baskerville (Italic)" TexFontTemplates.biolinum, # "Biolinum" TexFontTemplates.brushscriptx, # "BrushScriptX-Italic (PX math and Greek)" TexFontTemplates.chalkboard_se, # "Chalkboard SE" TexFontTemplates.chalkduster, # "Chalkduster" TexFontTemplates.comfortaa, # "Comfortaa" TexFontTemplates.comic_sans, # "Comic Sans MS" TexFontTemplates.droid_sans, # "Droid Sans" TexFontTemplates.droid_sans_it, # "Droid Sans (Italic)" TexFontTemplates.droid_serif, # "Droid Serif" TexFontTemplates.droid_serif_px_it, # "Droid Serif (PX math symbols) (Italic)" TexFontTemplates.ecf_augie, # "ECF Augie (Euler Greek)" TexFontTemplates.ecf_jd, # "ECF JD (with TX fonts)" TexFontTemplates.ecf_skeetch, # "ECF Skeetch (CM Greek)" TexFontTemplates.ecf_tall_paul, # "ECF Tall Paul (with Symbol font)" TexFontTemplates.ecf_webster, # "ECF Webster (with TX fonts)" TexFontTemplates.electrum_adf, # "Electrum ADF (CM Greek)" TexFontTemplates.epigrafica, # Epigrafica TexFontTemplates.fourier_utopia, # "Fourier Utopia (Fourier upright Greek)" TexFontTemplates.french_cursive, # "French Cursive (Euler Greek)" TexFontTemplates.gfs_bodoni, # "GFS Bodoni" TexFontTemplates.gfs_didot, # "GFS Didot (Italic)" TexFontTemplates.gfs_neoHellenic, # "GFS NeoHellenic" TexFontTemplates.gnu_freesans_tx, # "GNU FreeSerif (and TX fonts symbols)" TexFontTemplates.gnu_freeserif_freesans, # "GNU FreeSerif and FreeSans" TexFontTemplates.helvetica_fourier_it, # "Helvetica with Fourier (Italic)" TexFontTemplates.latin_modern_tw_it, # "Latin Modern Typewriter Proportional (CM Greek) (Italic)" TexFontTemplates.latin_modern_tw, # "Latin Modern Typewriter Proportional" TexFontTemplates.libertine, # "Libertine" TexFontTemplates.libris_adf_fourier, # "Libris ADF with Fourier" TexFontTemplates.minion_pro_myriad_pro, # "Minion Pro and Myriad Pro (and TX fonts symbols)" TexFontTemplates.minion_pro_tx, # "Minion Pro (and TX fonts symbols)" TexFontTemplates.new_century_schoolbook, # "New Century Schoolbook (Symbol Greek)" TexFontTemplates.new_century_schoolbook_px, # "New Century Schoolbook (Symbol Greek, PX math symbols)" TexFontTemplates.noteworthy_light, # "Noteworthy Light" TexFontTemplates.palatino, # "Palatino (Symbol Greek)" TexFontTemplates.papyrus, # "Papyrus" TexFontTemplates.romande_adf_fourier_it, # "Romande ADF with Fourier (Italic)" TexFontTemplates.slitex, # "SliTeX (Euler Greek)" TexFontTemplates.times_fourier_it, # "Times with Fourier (Italic)" TexFontTemplates.urw_avant_garde, # "URW Avant Garde (Symbol Greek)" TexFontTemplates.urw_zapf_chancery, # "URW Zapf Chancery (CM Greek)" TexFontTemplates.venturis_adf_fourier_it, # "Venturis ADF with Fourier (Italic)" TexFontTemplates.verdana_it, # "Verdana (Italic)" TexFontTemplates.vollkorn_fourier_it, # "Vollkorn with Fourier (Italic)" TexFontTemplates.vollkorn, # "Vollkorn (TX fonts for Greek and math symbols)" TexFontTemplates.zapf_chancery, # "Zapf Chancery" ] self.add(Tex("Tex Font Template Example").to_edge(UL)) for font in examples: try: write_one_line(font) except Exception: print("FAILURE on ", font.description, " - skipping.") self.play( Create( Tex( "See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html", ).shift(2 * DOWN), ), ) self.wait(2) ================================================ FILE: example_scenes/basic.py ================================================ #!/usr/bin/env python from manim import * # To watch one of these scenes, run the following: # python --quality m manim -p example_scenes.py SquareToCircle # # Use the flag --quality l for a faster rendering at a lower quality. # Use -s to skip to the end and just save the final frame # Use the -p to have preview of the animation (or image, if -s was # used) pop up once done. # Use -n to skip ahead to the nth animation of a scene. # Use -r to specify a resolution (for example, -r 1920,1080 # for a 1920x1080 video) class OpeningManim(Scene): def construct(self): title = Tex(r"This is some \LaTeX") basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}") VGroup(title, basel).arrange(DOWN) self.play( Write(title), FadeIn(basel, shift=DOWN), ) self.wait() transform_title = Tex("That was a transform") transform_title.to_corner(UP + LEFT) self.play( Transform(title, transform_title), LaggedStart(*(FadeOut(obj, shift=DOWN) for obj in basel)), ) self.wait() grid = NumberPlane() grid_title = Tex("This is a grid", font_size=72) grid_title.move_to(transform_title) self.add(grid, grid_title) # Make sure title is on top of grid self.play( FadeOut(title), FadeIn(grid_title, shift=UP), Create(grid, run_time=3, lag_ratio=0.1), ) self.wait() grid_transform_title = Tex( r"That was a non-linear function \\ applied to the grid", ) grid_transform_title.move_to(grid_title, UL) grid.prepare_for_nonlinear_transform() self.play( grid.animate.apply_function( lambda p: p + np.array( [ np.sin(p[1]), np.sin(p[0]), 0, ], ), ), run_time=3, ) self.wait() self.play(Transform(grid_title, grid_transform_title)) self.wait() class SquareToCircle(Scene): def construct(self): circle = Circle() square = Square() square.flip(RIGHT) square.rotate(-3 * TAU / 8) circle.set_fill(PINK, opacity=0.5) self.play(Create(square)) self.play(Transform(square, circle)) self.play(FadeOut(square)) class WarpSquare(Scene): def construct(self): square = Square() self.play( ApplyPointwiseFunction( lambda point: complex_to_R3(np.exp(R3_to_complex(point))), square, ), ) self.wait() class WriteStuff(Scene): def construct(self): example_text = Tex("This is a some text", tex_to_color_map={"text": YELLOW}) example_tex = MathTex( "\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}", ) group = VGroup(example_text, example_tex) group.arrange(DOWN) group.width = config["frame_width"] - 2 * LARGE_BUFF self.play(Write(example_text)) self.play(Write(example_tex)) self.wait() class UpdatersExample(Scene): def construct(self): decimal = DecimalNumber( 0, show_ellipsis=True, num_decimal_places=3, include_sign=True, ) square = Square().to_edge(UP) decimal.add_updater(lambda d: d.next_to(square, RIGHT)) decimal.add_updater(lambda d: d.set_value(square.get_center()[1])) self.add(square, decimal) self.play( square.animate.to_edge(DOWN), rate_func=there_and_back, run_time=5, ) self.wait() class SpiralInExample(Scene): def construct(self): logo_green = "#81b29a" logo_blue = "#454866" logo_red = "#e07a5f" font_color = "#ece6e2" pi = MathTex(r"\pi").scale(7).set_color(font_color) pi.shift(2.25 * LEFT + 1.5 * UP) circle = Circle(color=logo_green, fill_opacity=0.7, stroke_width=0).shift(LEFT) square = Square(color=logo_blue, fill_opacity=0.8, stroke_width=0).shift(UP) triangle = Triangle(color=logo_red, fill_opacity=0.9, stroke_width=0).shift( RIGHT ) pentagon = Polygon( *[ [np.cos(2 * np.pi / 5 * i), np.sin(2 * np.pi / 5 * i), 0] for i in range(5) ], color=PURPLE_B, fill_opacity=1, stroke_width=0, ).shift(UP + 2 * RIGHT) shapes = VGroup(triangle, square, circle, pentagon, pi) self.play(SpiralIn(shapes, fade_in_fraction=0.9)) self.wait() self.play(FadeOut(shapes)) Triangle.set_default(stroke_width=20) class LineJoints(Scene): def construct(self): t1 = Triangle() t2 = Triangle(joint_type=LineJointType.ROUND) t3 = Triangle(joint_type=LineJointType.BEVEL) grp = VGroup(t1, t2, t3).arrange(RIGHT) grp.set(width=config.frame_width - 1) self.add(grp) # See many more examples at https://docs.manim.community/en/stable/examples.html ================================================ FILE: example_scenes/custom_template.tex ================================================ \documentclass[preview]{standalone} \usepackage[english]{babel} \usepackage{amsmath} \usepackage{amssymb} \usepackage[f]{esvect} \begin{document} YourTextHere \end{document} ================================================ FILE: example_scenes/customtex.py ================================================ from manim import * class TexTemplateFromCLI(Scene): """This scene uses a custom TexTemplate file. The path of the TexTemplate _must_ be passed with the command line argument `--tex_template `. For this scene, you can use the custom_template.tex file next to it. This scene will fail to render if a tex_template.tex that doesn't import esvect is passed, and will throw a LaTeX error in that case. """ def construct(self): text = MathTex(r"\vv{vb}") self.play(Write(text)) self.wait(1) class InCodeTexTemplate(Scene): """This example scene demonstrates how to modify the tex template for a particular scene from the code for the scene itself. """ def construct(self): # Create a new template myTemplate = TexTemplate() # Add packages to the template myTemplate.add_to_preamble(r"\usepackage{esvect}") # Set the compiler and output format (default: latex and .dvi) # possible tex compilers: "latex", "pdflatex", "xelatex", "lualatex", "luatex" # possible output formats: ".dvi", ".pdf", and ".xdv" myTemplate.tex_compiler = "latex" myTemplate.output_format = ".dvi" # To use this template in a Tex() or MathTex() object # use the keyword argument tex_template text = MathTex(r"\vv{vb}", tex_template=myTemplate) self.play(Write(text)) self.wait(1) ================================================ FILE: example_scenes/manim.cfg ================================================ #This is some custom configuration just as an example [logger] logging_keyword = magenta logging_level_notset = dim logging_level_debug = yellow logging_level_info = dim green logging_level_warning = dim red logging_level_error = red logging_level_critical = red log_level = log_time = dim yellow log_message = green log_path = dim ================================================ FILE: example_scenes/manim_jupyter_example.ipynb ================================================ { "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from manim import *" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING --disable_caching -ql -s Example1\n", "\n", "class Example1(Scene):\n", " def construct(self):\n", " self.add(Circle())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING --disable_caching -qm HelloManim\n", "\n", "# set the maximum width for video outputs to a predefined value\n", "config.media_width = \"20vw\"\n", "# embed video\n", "config.media_embed = True\n", "\n", "class HelloManim(Scene):\n", " def construct(self):\n", " self.camera.background_color = \"#ece6e2\"\n", " banner_large = ManimBanner(dark_theme=False).scale(0.7)\n", " self.play(banner_large.create())\n", " self.play(banner_large.expand())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.1" } }, "nbformat": 4, "nbformat_minor": 4 } ================================================ FILE: example_scenes/opengl.py ================================================ from pathlib import Path import manim.utils.opengl as opengl from manim import * 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. def get_plane_mesh(context): shader = Shader(context, name="vertex_colors") attributes = np.zeros( 18, dtype=[ ("in_vert", np.float32, (4,)), ("in_color", np.float32, (4,)), ], ) attributes["in_vert"] = np.array( [ # xy plane [-1, -1, 0, 1], [-1, 1, 0, 1], [1, 1, 0, 1], [-1, -1, 0, 1], [1, -1, 0, 1], [1, 1, 0, 1], # yz plane [0, -1, -1, 1], [0, -1, 1, 1], [0, 1, 1, 1], [0, -1, -1, 1], [0, 1, -1, 1], [0, 1, 1, 1], # xz plane [-1, 0, -1, 1], [-1, 0, 1, 1], [1, 0, 1, 1], [-1, 0, -1, 1], [1, 0, -1, 1], [1, 0, 1, 1], ], ) attributes["in_color"] = np.array( [ # xy plane [1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1], # yz plane [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], # xz plane [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], ], ) return Mesh(shader, attributes) class TextTest(Scene): def construct(self): import string text = Text(string.ascii_lowercase, stroke_width=4, stroke_color=BLUE).scale(2) text2 = ( Text(string.ascii_uppercase, stroke_width=4, stroke_color=BLUE) .scale(2) .next_to(text, DOWN) ) # self.add(text, text2) self.play(Write(text)) self.play(Write(text2)) self.interactive_embed() class GuiTest(Scene): def construct(self): mesh = get_plane_mesh(self.renderer.context) # mesh.attributes["in_vert"][:, 0] self.add(mesh) def update_mesh(mesh, dt): mesh.model_matrix = np.matmul( opengl.rotation_matrix(z=dt), mesh.model_matrix, ) mesh.add_updater(update_mesh) self.interactive_embed() class GuiTest2(Scene): def construct(self): mesh = get_plane_mesh(self.renderer.context) mesh.attributes["in_vert"][:, 0] -= 2 self.add(mesh) mesh2 = get_plane_mesh(self.renderer.context) mesh2.attributes["in_vert"][:, 0] += 2 self.add(mesh2) def callback(sender, data): mesh2.attributes["in_color"][:, 3] = dpg.get_value(sender) self.widgets.append( { "name": "mesh2 opacity", "widget": "slider_float", "callback": callback, "min_value": 0, "max_value": 1, "default_value": 1, }, ) self.interactive_embed() class ThreeDMobjectTest(Scene): def construct(self): # config["background_color"] = "#333333" s = Square(fill_opacity=0.5).shift(2 * RIGHT) self.add(s) sp = Sphere().shift(2 * LEFT) self.add(sp) mesh = get_plane_mesh(self.renderer.context) self.add(mesh) def update_mesh(mesh, dt): mesh.model_matrix = np.matmul( opengl.rotation_matrix(z=dt), mesh.model_matrix, ) mesh.add_updater(update_mesh) self.interactive_embed() class NamedFullScreenQuad(Scene): def construct(self): surface = FullScreenQuad(self.renderer.context, fragment_shader_name="design_3") surface.shader.set_uniform( "u_resolution", (config["pixel_width"], config["pixel_height"], 0.0), ) surface.shader.set_uniform("u_time", 0) self.add(surface) t = 0 def update_surface(surface, dt): nonlocal t t += dt surface.shader.set_uniform("u_time", t / 4) surface.add_updater(update_surface) # self.wait() self.interactive_embed() class InlineFullScreenQuad(Scene): def construct(self): surface = FullScreenQuad( self.renderer.context, """ #version 330 #define TWO_PI 6.28318530718 uniform vec2 u_resolution; uniform float u_time; out vec4 frag_color; // Function from Iñigo Quiles // https://www.shadertoy.com/view/MsS3Wc vec3 hsb2rgb( in vec3 c ){ vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0 ); rgb = rgb*rgb*(3.0-2.0*rgb); return c.z * mix( vec3(1.0), rgb, c.y); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution; vec3 color = vec3(0.0); // Use polar coordinates instead of cartesian vec2 toCenter = vec2(0.5)-st; float angle = atan(toCenter.y,toCenter.x); angle += u_time; float radius = length(toCenter)*2.0; // Map the angle (-PI to PI) to the Hue (from 0 to 1) // and the Saturation to the radius color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0)); frag_color = vec4(color,1.0); } """, ) surface.shader.set_uniform( "u_resolution", (config["pixel_width"], config["pixel_height"]), ) shader_time = 0 def update_surface(surface): nonlocal shader_time surface.shader.set_uniform("u_time", shader_time) shader_time += 1 / 60.0 surface.add_updater(update_surface) self.add(surface) # self.wait(5) self.interactive_embed() class SimpleInlineFullScreenQuad(Scene): def construct(self): surface = FullScreenQuad( self.renderer.context, """ #version 330 uniform float v_red; uniform float v_green; uniform float v_blue; out vec4 frag_color; void main() { frag_color = vec4(v_red, v_green, v_blue, 1); } """, ) surface.shader.set_uniform("v_red", 0) surface.shader.set_uniform("v_green", 0) surface.shader.set_uniform("v_blue", 0) increase = True val = 0.5 surface.shader.set_uniform("v_red", val) surface.shader.set_uniform("v_green", val) surface.shader.set_uniform("v_blue", val) def update_surface(mesh, dt): nonlocal increase nonlocal val if increase: val += dt else: val -= dt if val >= 1: increase = False elif val <= 0: increase = True surface.shader.set_uniform("v_red", val) surface.shader.set_uniform("v_green", val) surface.shader.set_uniform("v_blue", val) surface.add_updater(update_surface) self.add(surface) self.wait(5) class InlineShaderExample(Scene): def construct(self): config["background_color"] = "#333333" c = Circle(fill_opacity=0.7).shift(UL) self.add(c) shader = Shader( self.renderer.context, source={ "vertex_shader": """ #version 330 in vec4 in_vert; in vec4 in_color; out vec4 v_color; uniform mat4 u_model_view_matrix; uniform mat4 u_projection_matrix; void main() { v_color = in_color; vec4 camera_space_vertex = u_model_view_matrix * in_vert; vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex; gl_Position = clip_space_vertex; } """, "fragment_shader": """ #version 330 in vec4 v_color; out vec4 frag_color; void main() { frag_color = v_color; } """, }, ) shader.set_uniform("u_model_view_matrix", opengl.view_matrix()) shader.set_uniform( "u_projection_matrix", opengl.orthographic_projection_matrix(), ) attributes = np.zeros( 6, dtype=[ ("in_vert", np.float32, (4,)), ("in_color", np.float32, (4,)), ], ) attributes["in_vert"] = np.array( [ [-1, -1, 0, 1], [-1, 1, 0, 1], [1, 1, 0, 1], [-1, -1, 0, 1], [1, -1, 0, 1], [1, 1, 0, 1], ], ) attributes["in_color"] = np.array( [ [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], ], ) mesh = Mesh(shader, attributes) self.add(mesh) self.wait(5) # self.embed_2() class NamedShaderExample(Scene): def construct(self): shader = Shader(self.renderer.context, "manim_coords") shader.set_uniform("u_color", (0.0, 1.0, 0.0, 1.0)) view_matrix = self.camera.formatted_view_matrix shader.set_uniform("u_model_view_matrix", view_matrix) shader.set_uniform( "u_projection_matrix", opengl.perspective_projection_matrix(), ) attributes = np.zeros( 6, dtype=[ ("in_vert", np.float32, (4,)), ], ) attributes["in_vert"] = np.array( [ [-1, -1, 0, 1], [-1, 1, 0, 1], [1, 1, 0, 1], [-1, -1, 0, 1], [1, -1, 0, 1], [1, 1, 0, 1], ], ) mesh = Mesh(shader, attributes) self.add(mesh) self.wait(5) class InteractiveDevelopment(Scene): def construct(self): circle = Circle() circle.set_fill(BLUE, opacity=0.5) circle.set_stroke(BLUE_E, width=4) square = Square() self.play(Create(square)) self.wait() # This opens an iPython terminal where you can keep writing # lines as if they were part of this construct method. # In particular, 'square', 'circle' and 'self' will all be # part of the local namespace in that terminal. # self.embed() # Try copying and pasting some of the lines below into # the interactive shell self.play(ReplacementTransform(square, circle)) self.wait() self.play(circle.animate.stretch(4, 0)) self.play(Rotate(circle, 90 * DEGREES)) self.play(circle.animate.shift(2 * RIGHT).scale(0.25)) # text = Text( # """ # In general, using the interactive shell # is very helpful when developing new scenes # """ # ) # self.play(Write(text)) # # In the interactive shell, you can just type # # play, add, remove, clear, wait, save_state and restore, # # instead of self.play, self.add, self.remove, etc. # # To interact with the window, type touch(). You can then # # scroll in the window, or zoom by holding down 'z' while scrolling, # # and change camera perspective by holding down 'd' while moving # # the mouse. Press 'r' to reset to the standard camera position. # # Press 'q' to stop interacting with the window and go back to # # typing new commands into the shell. # # In principle you can customize a scene to be responsive to # # mouse and keyboard interactions # always(circle.move_to, self.mouse_point) class SurfaceExample(Scene): def construct(self): # surface_text = Text("For 3d scenes, try using surfaces") # surface_text.fix_in_frame() # surface_text.to_edge(UP) # self.add(surface_text) # self.wait(0.1) torus1 = Torus(major_radius=1, minor_radius=1) torus2 = Torus(major_radius=3, minor_radius=1) sphere = Sphere(radius=3, resolution=torus1.resolution) # You can texture a surface with up to two images, which will # be interpreted as the side towards the light, and away from # the light. These can be either urls, or paths to a local file # in whatever you've set as the image directory in # the custom_config.yml file script_location = Path(__file__).resolve().parent day_texture = ( script_location / "assets" / "1280px-Whole_world_-_land_and_oceans.jpg" ) night_texture = script_location / "assets" / "1280px-The_earth_at_night.jpg" surfaces = [ OpenGLTexturedSurface(surface, day_texture, night_texture) for surface in [sphere, torus1, torus2] ] for mob in surfaces: mob.shift(IN) mob.mesh = OpenGLSurfaceMesh(mob) mob.mesh.set_stroke(BLUE, 1, opacity=0.5) # Set perspective frame = self.renderer.camera frame.set_euler_angles( theta=-30 * DEGREES, phi=70 * DEGREES, ) surface = surfaces[0] self.play( FadeIn(surface), Create(surface.mesh, lag_ratio=0.01, run_time=3), ) for mob in surfaces: mob.add(mob.mesh) surface.save_state() self.play(Rotate(surface, PI / 2), run_time=2) for mob in surfaces[1:]: mob.rotate(PI / 2) self.play(Transform(surface, surfaces[1]), run_time=3) self.play( Transform(surface, surfaces[2]), # Move camera frame during the transition frame.animate.increment_phi(-10 * DEGREES), frame.animate.increment_theta(-20 * DEGREES), run_time=3, ) # Add ambient rotation frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt)) # Play around with where the light is # light_text = Text("You can move around the light source") # light_text.move_to(surface_text) # light_text.fix_in_frame() # self.play(FadeTransform(surface_text, light_text)) light = self.camera.light_source self.add(light) light.save_state() self.play(light.animate.move_to(3 * IN), run_time=5) self.play(light.animate.shift(10 * OUT), run_time=5) # drag_text = Text("Try moving the mouse while pressing d or s") # drag_text.move_to(light_text) # drag_text.fix_in_frame() ================================================ FILE: lgtm.yml ================================================ queries: - exclude: py/init-calls-subclass - exclude: py/unexpected-raise-in-special-method - exclude: py/modification-of-locals - exclude: py/multiple-calls-to-init - exclude: py/missing-call-to-init ================================================ FILE: manim/__init__.py ================================================ #!/usr/bin/env python from __future__ import annotations from importlib.metadata import PackageNotFoundError, version # Use installed distribution version if available; otherwise fall back to a # sensible default so that importing from a source checkout works without an # editable install (pip install -e .). try: __version__ = version(__name__) except PackageNotFoundError: # Package is not installed; provide a fallback version string. __version__ = "0.0.0+unknown" # isort: off # Importing the config module should be the first thing we do, since other # modules depend on the global config dict for initialization. from ._config import * # many scripts depend on this -> has to be loaded first from .utils.commands import * # isort: on import numpy as np from .animation.animation import * from .animation.changing import * from .animation.composition import * from .animation.creation import * from .animation.fading import * from .animation.growing import * from .animation.indication import * from .animation.movement import * from .animation.numbers import * from .animation.rotation import * from .animation.specialized import * from .animation.speedmodifier import * from .animation.transform import * from .animation.transform_matching_parts import * from .animation.updaters.mobject_update_utils import * from .animation.updaters.update import * from .camera.camera import * from .camera.mapping_camera import * from .camera.moving_camera import * from .camera.multi_camera import * from .camera.three_d_camera import * from .constants import * from .mobject.frame import * from .mobject.geometry.arc import * from .mobject.geometry.boolean_ops import * from .mobject.geometry.labeled import * from .mobject.geometry.line import * from .mobject.geometry.polygram import * from .mobject.geometry.shape_matchers import * from .mobject.geometry.tips import * from .mobject.graph import * from .mobject.graphing.coordinate_systems import * from .mobject.graphing.functions import * from .mobject.graphing.number_line import * from .mobject.graphing.probability import * from .mobject.graphing.scale import * from .mobject.logo import * from .mobject.matrix import * from .mobject.mobject import * from .mobject.opengl.dot_cloud import * from .mobject.opengl.opengl_point_cloud_mobject import * from .mobject.svg.brace import * from .mobject.svg.svg_mobject import * from .mobject.table import * from .mobject.text.code_mobject import * from .mobject.text.numbers import * from .mobject.text.tex_mobject import * from .mobject.text.text_mobject import * from .mobject.three_d.polyhedra import * from .mobject.three_d.three_d_utils import * from .mobject.three_d.three_dimensions import * from .mobject.types.image_mobject import * from .mobject.types.point_cloud_mobject import * from .mobject.types.vectorized_mobject import * from .mobject.value_tracker import * from .mobject.vector_field import * from .renderer.cairo_renderer import * from .scene.moving_camera_scene import * from .scene.scene import * from .scene.scene_file_writer import * from .scene.section import * from .scene.three_d_scene import * from .scene.vector_space_scene import * from .scene.zoomed_scene import * from .utils import color, rate_functions, unit from .utils.bezier import * from .utils.color import * from .utils.config_ops import * from .utils.debug import * from .utils.file_ops import * from .utils.images import * from .utils.iterables import * from .utils.paths import * from .utils.rate_functions import * from .utils.simple_functions import * from .utils.sounds import * from .utils.space_ops import * from .utils.tex import * from .utils.tex_templates import * try: from IPython import get_ipython from .utils.ipython_magic import ManimMagic except ImportError: pass else: ipy = get_ipython() if ipy is not None: ipy.register_magics(ManimMagic) from .plugins import * ================================================ FILE: manim/__main__.py ================================================ from __future__ import annotations import click import cloup from manim import __version__ from manim._config import cli_ctx_settings, console from manim.cli.cfg.group import cfg from manim.cli.checkhealth.commands import checkhealth from manim.cli.default_group import DefaultGroup from manim.cli.init.commands import init from manim.cli.plugins.commands import plugins from manim.cli.render.commands import render from manim.constants import EPILOG def show_splash(ctx: click.Context, param: click.Option, value: str | None) -> None: """When giving a value by console, show an initial message with the Manim version before executing any other command: ``Manim Community vA.B.C``. Parameters ---------- ctx The Click context. param A Click option. value A string value given by console, or None. """ if value: console.print(f"Manim Community [green]v{__version__}[/green]\n") def print_version_and_exit( ctx: click.Context, param: click.Option, value: str | None ) -> None: """Same as :func:`show_splash`, but also exit when giving a value by console. Parameters ---------- ctx The Click context. param A Click option. value A string value given by console, or None. """ show_splash(ctx, param, value) if value: ctx.exit() @cloup.group( context_settings=cli_ctx_settings, cls=DefaultGroup, default="render", no_args_is_help=True, help="Animation engine for explanatory math videos.", epilog="See 'manim ' to read about a specific subcommand.\n\n" "Note: the subcommand 'manim render' is called if no other subcommand " "is specified. Run 'manim render --help' if you would like to know what the " f"'-ql' or '-p' flags do, for example.\n\n{EPILOG}", ) @cloup.option( "--version", is_flag=True, help="Show version and exit.", callback=print_version_and_exit, is_eager=True, expose_value=False, ) @click.option( "--show-splash/--hide-splash", is_flag=True, default=True, help="Print splash message with version information.", callback=show_splash, is_eager=True, expose_value=False, ) @cloup.pass_context def main(ctx: click.Context) -> None: """The entry point for Manim. Parameters ---------- ctx The Click context. """ pass main.add_command(checkhealth) main.add_command(cfg) main.add_command(plugins) main.add_command(init) main.add_command(render) if __name__ == "__main__": main() ================================================ FILE: manim/_config/__init__.py ================================================ """Set the global config and logger.""" from __future__ import annotations import logging from collections.abc import Generator from contextlib import contextmanager from typing import Any from .cli_colors import parse_cli_ctx from .logger_utils import make_logger from .utils import ManimConfig, ManimFrame, make_config_parser __all__ = [ "logger", "console", "error_console", "config", "frame", "tempconfig", "cli_ctx_settings", ] parser = make_config_parser() # Logger usage: accessible globally as `manim.logger` or via `logging.getLogger("manim")`. # For printing, use `manim.console.print()` instead of the built-in `print()`. # For error output, use `error_console`, which prints to stderr. logger, console, error_console = make_logger( parser["logger"], parser["CLI"]["verbosity"], ) cli_ctx_settings = parse_cli_ctx(parser["CLI_CTX"]) # TODO: temporary to have a clean terminal output when working with PIL or matplotlib logging.getLogger("PIL").setLevel(logging.INFO) logging.getLogger("matplotlib").setLevel(logging.INFO) config = ManimConfig().digest_parser(parser) # TODO: to be used in the future - see PR #620 # https://github.com/ManimCommunity/manim/pull/620 frame = ManimFrame(config) # This has to go here because it needs access to this module's config @contextmanager def tempconfig(temp: ManimConfig | dict[str, Any]) -> Generator[None, None, None]: """Temporarily modifies the global ``config`` object using a context manager. Inside the ``with`` statement, the modified config will be used. After context manager exits, the config will be restored to its original state. Parameters ---------- temp Object whose keys will be used to temporarily update the global ``config``. Examples -------- Use ``with tempconfig({...})`` to temporarily change the default values of certain config options. .. code-block:: pycon >>> config["frame_height"] 8.0 >>> with tempconfig({"frame_height": 100.0}): ... print(config["frame_height"]) 100.0 >>> config["frame_height"] 8.0 """ global config original = config.copy() temp = {k: v for k, v in temp.items() if k in original} # In order to change the config that every module has access to, use # update(), DO NOT use assignment. Assigning config = some_dict will just # make the local variable named config point to a new dictionary, it will # NOT change the dictionary that every module has a reference to. config.update(temp) try: yield finally: config.update(original) # update, not assignment! ================================================ FILE: manim/_config/cli_colors.py ================================================ """Parses CLI context settings from the configuration file and returns a Cloup Context settings dictionary. This module reads configuration values for help formatting, theme styles, and alignment options used when rendering command-line interfaces in Manim. """ from __future__ import annotations import configparser from typing import Any from cloup import Context, HelpFormatter, HelpTheme, Style __all__ = ["parse_cli_ctx"] def parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]: formatter_settings: dict[str, str | int | None] = { "indent_increment": int(parser["indent_increment"]), "width": int(parser["width"]), "col1_max_width": int(parser["col1_max_width"]), "col2_min_width": int(parser["col2_min_width"]), "col_spacing": int(parser["col_spacing"]), "row_sep": parser["row_sep"] if parser["row_sep"] else None, } theme_settings = {} theme_keys = { "command_help", "invoked_command", "heading", "constraint", "section_help", "col1", "col2", "epilog", } # Extract and apply any style-related keys defined in the config section. for k, v in parser.items(): if k in theme_keys and v: theme_settings.update({k: Style(v)}) formatter = {} theme = parser["theme"] if parser["theme"] else None if theme is None: formatter = HelpFormatter.settings( theme=HelpTheme(**theme_settings), **formatter_settings, ) elif theme.lower() == "dark": formatter = HelpFormatter.settings( theme=HelpTheme.dark().with_(**theme_settings), **formatter_settings, ) elif theme.lower() == "light": formatter = HelpFormatter.settings( theme=HelpTheme.light().with_(**theme_settings), **formatter_settings, ) return_val: dict[str, Any] = Context.settings( align_option_groups=parser["align_option_groups"].lower() == "true", align_sections=parser["align_sections"].lower() == "true", show_constraints=True, formatter_settings=formatter, ) return return_val ================================================ FILE: manim/_config/default.cfg ================================================ # manim.cfg # Default configuration for manim # Configure how manim behaves when called from the command line without # specifying any flags [CLI] # Each of the following will be set to True if the corresponding CLI flag # is present when executing manim. If the flag is not present, they will # be set to the value found here. For example, running manim with the -w # flag will set WRITE_TO_MOVIE to True. However, since the default value # of WRITE_TO_MOVIE defined in this file is also True, running manim # without the -w value will also output a movie file. To change that, set # WRITE_TO_MOVIE = False so that running manim without the -w flag will not # generate a movie file. Note all of the following accept boolean values. # --notify_outdated_version notify_outdated_version = True # -w, --write_to_movie write_to_movie = True format = mp4 # -s, --save_last_frame # setting save_last_frame to True forces write_to_movie to False save_last_frame = False # -a, --write_all write_all = False # -g, --save_pngs save_pngs = False # -0, --zero_pad zero_pad = 4 # -i, --save_as_gif save_as_gif = False # --save_sections save_sections = False # -p, --preview preview = False # -f, --show_in_file_browser show_in_file_browser = False # -v, --verbosity verbosity = INFO # --progress_bar progress_bar = display # -o, --output_file output_file = # --log_to_file log_to_file = False # -c, --background_color background_color = BLACK # --background_opacity background_opacity = 1 # The following two are both set by the -n (or --from_animation_number) # flag. See manim -h for more information. from_animation_number = 0 # Use -1 to render all animations upto_animation_number = -1 # The following are meant to be paths relative to the point of execution. # Set them at the CLI with the corresponding flag, or set their default # values here. # --media_dir media_dir = ./media # --log_dir log_dir = {media_dir}/logs # --assets_dir assets_dir = ./ # the following do not have CLI arguments but depend on media_dir video_dir = {media_dir}/videos/{module_name}/{quality} sections_dir = {video_dir}/sections images_dir = {media_dir}/images/{module_name} tex_dir = {media_dir}/Tex text_dir = {media_dir}/texts partial_movie_dir = {video_dir}/partial_movie_files/{scene_name} # --renderer [cairo|opengl] renderer = cairo # --enable_gui enable_gui = False # --gui_location gui_location = 0,0 # --fullscreen fullscreen = False # "Set the position of preview window. You can use directions, e.g. UL/DR/LEFT/ORIGIN # or the position (pixel) of the upper left corner of the window, e.g. '960,540'", # --window_position window_position = UR # Manually adjust the size of the window, or use default to automatically scale the window based on # the dimensions of the monitor. # --window_size window_size = default # --window_monitor window_monitor = 0 # --force_window force_window = False # --use_projection_fill_shaders use_projection_fill_shaders = False # --use_projection_stroke_shaders use_projection_stroke_shaders = False movie_file_extension = .mp4 # These now override the --quality option. frame_rate = 60 pixel_height = 1080 pixel_width = 1920 # Use -1 to set max_files_cached to infinity. max_files_cached = 100 #Flush cache will delete all the cached partial-movie-files. flush_cache = False disable_caching = False # Disable the warning when there are too much submobjects to hash. disable_caching_warning = False # --enable_wireframe enable_wireframe = False # --dry_run dry_run = False # Default tex_template # --tex_template tex_template = # specify the plugins as comma separated values # manim will load that plugin if it specified here. plugins = # CLI Context/Formatter # Visit the cloup documentation to understand the formatting options available: # https://cloup.readthedocs.io/en/latest/index.html#a-simple-example [CLI_CTX] # CTX settings align_option_groups = True align_sections = True show_constraints = True # Formatter settings indent_increment = 2 width = 80 col1_max_width = 30 col2_min_width = 35 col_spacing = 2 row_sep = # Dark/Light, or leave empty theme = # Theme Settings - The following options override the theme colors. command_help = invoked_command = heading = constraint = section_help = col1 = col2 = epilog = # Overrides the default output folders, NOT the output file names. Note that # if the custom_folders flag is present, the Tex and text files will not be put # under media_dir, as is the default. [custom_folders] media_dir = videos video_dir = {media_dir} sections_dir = {media_dir} images_dir = {media_dir} text_dir = {media_dir}/temp_files tex_dir = {media_dir}/temp_files log_dir = {media_dir}/temp_files partial_movie_dir = {media_dir}/partial_movie_files/{scene_name} # Rich settings [logger] logging_keyword = bold yellow logging_level_notset = dim logging_level_debug = green logging_level_info = green logging_level_warning = red logging_level_error = red bold logging_level_critical = red bold reverse log_level = log_time = cyan dim log_message = log_path = dim log_width = -1 log_height = -1 log_timestamps = True repr_number = green [ffmpeg] # Uncomment the following line to manually set the loglevel for ffmpeg. See # ffmpeg manpage for accepted values loglevel = ERROR [jupyter] media_embed = False media_width = 60%% ================================================ FILE: manim/_config/logger_utils.py ================================================ """Utilities to create and set the logger. Manim's logger can be accessed as ``manim.logger``, or as ``logging.getLogger("manim")``, once the library has been imported. Manim also exports a second object, ``console``, which should be used to print on screen messages that need not be logged. Both ``logger`` and ``console`` use the ``rich`` library to produce rich text format. """ from __future__ import annotations import configparser import copy import json import logging from typing import TYPE_CHECKING, Any from rich import color, errors from rich import print as printf from rich.console import Console from rich.logging import RichHandler from rich.theme import Theme if TYPE_CHECKING: from pathlib import Path __all__ = ["make_logger", "parse_theme", "set_file_logger", "JSONFormatter"] HIGHLIGHTED_KEYWORDS = [ # these keywords are highlighted specially "Played", "animations", "scene", "Reading", "Writing", "script", "arguments", "Invalid", "Aborting", "module", "File", "Rendering", "Rendered", ] WRONG_COLOR_CONFIG_MSG = """ [logging.level.error]Your colour configuration couldn't be parsed. Loading the default color configuration.[/logging.level.error] """ def make_logger( parser: configparser.SectionProxy, verbosity: str, ) -> tuple[logging.Logger, Console, Console]: """Make the manim logger and console. Parameters ---------- parser A parser containing any .cfg files in use. verbosity The verbosity level of the logger. Returns ------- :class:`logging.Logger`, :class:`rich.Console`, :class:`rich.Console` The manim logger and consoles. The first console outputs to stdout, the second to stderr. All use the theme returned by :func:`parse_theme`. See Also -------- :func:`~._config.utils.make_config_parser`, :func:`parse_theme` Notes ----- The ``parser`` is assumed to contain only the options related to configuring the logger at the top level. """ # Throughout the codebase, use console.print() instead of print() theme = parse_theme(parser) console = Console(theme=theme) error_console = Console(theme=theme, stderr=True) # set the rich handler rich_handler = RichHandler( console=console, show_time=parser.getboolean("log_timestamps", fallback=False), keywords=HIGHLIGHTED_KEYWORDS, ) # finally, the logger logger = logging.getLogger("manim") logger.addHandler(rich_handler) logger.setLevel(verbosity) logger.propagate = False if not (libav_logger := logging.getLogger()).hasHandlers(): libav_logger.addHandler(rich_handler) libav_logger.setLevel(verbosity) return logger, console, error_console def parse_theme(parser: configparser.SectionProxy) -> Theme | None: """Configure the rich style of logger and console output. Parameters ---------- parser A parser containing any .cfg files in use. Returns ------- :class:`rich.Theme` The rich theme to be used by the manim logger. See Also -------- :func:`make_logger`. """ theme: dict[str, Any] = {key.replace("_", "."): parser[key] for key in parser} theme["log.width"] = None if theme["log.width"] == "-1" else int(theme["log.width"]) theme["log.height"] = ( None if theme["log.height"] == "-1" else int(theme["log.height"]) ) theme["log.timestamps"] = False try: custom_theme = Theme( { k: v for k, v in theme.items() if k not in ["log.width", "log.height", "log.timestamps"] }, ) except (color.ColorParseError, errors.StyleSyntaxError): printf(WRONG_COLOR_CONFIG_MSG) custom_theme = None return custom_theme def set_file_logger(scene_name: str, module_name: str, log_dir: Path) -> None: """Add a file handler to manim logger. The path to the file is built using ``config.log_dir``. Parameters ---------- scene_name The name of the scene, used in the name of the log file. module_name The name of the module, used in the name of the log file. log_dir Path to the folder where log files are stored. """ # Note: The log file name will be # _.log, gotten from config. So it # can differ from the real name of the scene. would only # appear if scene name was provided when manim was called. log_file_name = f"{module_name}_{scene_name}.log" log_file_path = log_dir / log_file_name file_handler = logging.FileHandler(log_file_path, mode="w") file_handler.setFormatter(JSONFormatter()) logger = logging.getLogger("manim") logger.addHandler(file_handler) logger.info("Log file will be saved in %(logpath)s", {"logpath": log_file_path}) class JSONFormatter(logging.Formatter): """A formatter that outputs logs in a custom JSON format. This class is used internally for testing purposes. """ def format(self, record: logging.LogRecord) -> str: """Format the record in a custom JSON format.""" record_c = copy.deepcopy(record) if record_c.args: if isinstance(record_c.args, dict): for arg in record_c.args: record_c.args[arg] = "<>" else: record_c.args = ("<>",) * len(record_c.args) return json.dumps( { "levelname": record_c.levelname, "module": record_c.module, "message": super().format(record_c), }, ) ================================================ FILE: manim/_config/utils.py ================================================ """Utilities to create and set the config. The main class exported by this module is :class:`ManimConfig`. This class contains all configuration options, including frame geometry (e.g. frame height/width, frame rate), output (e.g. directories, logging), styling (e.g. background color, transparency), and general behavior (e.g. writing a movie vs writing a single frame). See :doc:`/guides/configuration` for an introduction to Manim's configuration system. """ from __future__ import annotations import argparse import configparser import copy import errno import logging import os import re import sys from collections.abc import Iterator, Mapping, MutableMapping from pathlib import Path from typing import TYPE_CHECKING, Any, ClassVar, NoReturn import numpy as np from manim import constants from manim.constants import RendererType from manim.utils.color import ManimColor from manim.utils.tex import TexTemplate if TYPE_CHECKING: from enum import EnumMeta from typing import Self from manim.typing import StrPath, Vector3D __all__ = ["config_file_paths", "make_config_parser", "ManimConfig", "ManimFrame"] logger = logging.getLogger("manim") def config_file_paths() -> list[Path]: """The paths where ``.cfg`` files will be searched for. When manim is first imported, it processes any ``.cfg`` files it finds. This function returns the locations in which these files are searched for. In ascending order of precedence, these are: the library-wide config file, the user-wide config file, and the folder-wide config file. The library-wide config file determines manim's default behavior. The user-wide config file is stored in the user's home folder, and determines the behavior of manim whenever the user invokes it from anywhere in the system. The folder-wide config file only affects scenes that are in the same folder. The latter two files are optional. These files, if they exist, are meant to loaded into a single :class:`configparser.ConfigParser` object, and then processed by :class:`ManimConfig`. Returns ------- List[:class:`Path`] List of paths which may contain ``.cfg`` files, in ascending order of precedence. See Also -------- :func:`make_config_parser`, :meth:`ManimConfig.digest_file`, :meth:`ManimConfig.digest_parser` Notes ----- The location of the user-wide config file is OS-specific. """ library_wide = Path.resolve(Path(__file__).parent / "default.cfg") if sys.platform.startswith("win32"): user_wide = Path.home() / "AppData" / "Roaming" / "Manim" / "manim.cfg" else: user_wide = Path.home() / ".config" / "manim" / "manim.cfg" folder_wide = Path("manim.cfg") return [library_wide, user_wide, folder_wide] def make_config_parser( custom_file: StrPath | None = None, ) -> configparser.ConfigParser: """Make a :class:`ConfigParser` object and load any ``.cfg`` files. The user-wide file, if it exists, overrides the library-wide file. The folder-wide file, if it exists, overrides the other two. The folder-wide file can be ignored by passing ``custom_file``. However, the user-wide and library-wide config files cannot be ignored. Parameters ---------- custom_file Path to a custom config file. If used, the folder-wide file in the relevant directory will be ignored, if it exists. If None, the folder-wide file will be used, if it exists. Returns ------- :class:`ConfigParser` A parser containing the config options found in the .cfg files that were found. It is guaranteed to contain at least the config options found in the library-wide file. See Also -------- :func:`config_file_paths` """ library_wide, user_wide, folder_wide = config_file_paths() # From the documentation: "An application which requires initial values to # be loaded from a file should load the required file or files using # read_file() before calling read() for any optional files." # https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.read parser = configparser.ConfigParser() logger.info(f"Reading config file: {library_wide}") with library_wide.open() as file: parser.read_file(file) # necessary file other_files = [user_wide, Path(custom_file) if custom_file else folder_wide] for path in other_files: if path.exists(): logger.info(f"Reading config file: {path}") parser.read(other_files) # optional files return parser def _determine_quality(qual: str | None) -> str: for quality, values in constants.QUALITIES.items(): if values["flag"] is not None and values["flag"] == qual: return quality return qual class ManimConfig(MutableMapping): """Dict-like class storing all config options. The global ``config`` object is an instance of this class, and acts as a single source of truth for all of the library's customizable behavior. The global ``config`` object is capable of digesting different types of sources and converting them into a uniform interface. These sources are (in ascending order of precedence): configuration files, command line arguments, and programmatic changes. Regardless of how the user chooses to set a config option, she can access its current value using :class:`ManimConfig`'s attributes and properties. Notes ----- Each config option is implemented as a property of this class. Each config option can be set via a config file, using the full name of the property. If a config option has an associated CLI flag, then the flag is equal to the full name of the property. Those that admit an alternative flag or no flag at all are documented in the individual property's docstring. Examples -------- We use a copy of the global configuration object in the following examples for the sake of demonstration; you can skip these lines and just import ``config`` directly if you actually want to modify the configuration: .. code-block:: pycon >>> from manim import config as global_config >>> config = global_config.copy() Each config option allows for dict syntax and attribute syntax. For example, the following two lines are equivalent, .. code-block:: pycon >>> from manim import WHITE >>> config.background_color = WHITE >>> config["background_color"] = WHITE The former is preferred; the latter is provided mostly for backwards compatibility. The config options are designed to keep internal consistency. For example, setting ``frame_y_radius`` will affect ``frame_height``: .. code-block:: pycon >>> config.frame_height 8.0 >>> config.frame_y_radius = 5.0 >>> config.frame_height 10.0 There are many ways of interacting with config options. Take for example the config option ``background_color``. There are three ways to change it: via a config file, via CLI flags, or programmatically. To set the background color via a config file, save the following ``manim.cfg`` file with the following contents. .. code-block:: [CLI] background_color = WHITE In order to have this ``.cfg`` file apply to a manim scene, it needs to be placed in the same directory as the script, .. code-block:: bash project/ ├─scene.py └─manim.cfg Now, when the user executes .. code-block:: bash manim scene.py the background of the scene will be set to ``WHITE``. This applies regardless of where the manim command is invoked from. Command line arguments override ``.cfg`` files. In the previous example, executing .. code-block:: bash manim scene.py -c BLUE will set the background color to BLUE, regardless of the contents of ``manim.cfg``. Finally, any programmatic changes made within the scene script itself will override the command line arguments. For example, if ``scene.py`` contains the following .. code-block:: python from manim import * config.background_color = RED class MyScene(Scene): ... the background color will be set to RED, regardless of the contents of ``manim.cfg`` or the CLI arguments used when invoking manim. """ _OPTS = { "assets_dir", "background_color", "background_opacity", "custom_folders", "disable_caching", "disable_caching_warning", "dry_run", "enable_wireframe", "ffmpeg_loglevel", "format", "flush_cache", "frame_height", "frame_rate", "frame_width", "frame_x_radius", "frame_y_radius", "from_animation_number", "images_dir", "input_file", "media_embed", "media_width", "log_dir", "log_to_file", "max_files_cached", "media_dir", "movie_file_extension", "notify_outdated_version", "output_file", "partial_movie_dir", "pixel_height", "pixel_width", "plugins", "preview", "progress_bar", "quality", "save_as_gif", "save_sections", "save_last_frame", "save_pngs", "scene_names", "seed", "show_in_file_browser", "tex_dir", "tex_template", "tex_template_file", "text_dir", "upto_animation_number", "renderer", "enable_gui", "gui_location", "use_projection_fill_shaders", "use_projection_stroke_shaders", "verbosity", "video_dir", "sections_dir", "fullscreen", "window_position", "window_size", "window_monitor", "write_all", "write_to_movie", "zero_pad", "force_window", "no_latex_cleanup", "preview_command", } def __init__(self) -> None: self._d: dict[str, Any | None] = dict.fromkeys(self._OPTS) # behave like a dict def __iter__(self) -> Iterator[str]: return iter(self._d) def __len__(self) -> int: return len(self._d) def __contains__(self, key: object) -> bool: try: assert isinstance(key, str) self.__getitem__(key) return True except AttributeError: return False def __getitem__(self, key: str) -> Any: return getattr(self, key) def __setitem__(self, key: str, val: Any) -> None: getattr(ManimConfig, key).fset(self, val) # fset is the property's setter def update(self, obj: ManimConfig | dict[str, Any]) -> None: # type: ignore[override] """Digest the options found in another :class:`ManimConfig` or in a dict. Similar to :meth:`dict.update`, replaces the values of this object with those of ``obj``. Parameters ---------- obj The object to copy values from. Returns ------- None Raises ----- :class:`AttributeError` If ``obj`` is a dict but contains keys that do not belong to any config options. See Also -------- :meth:`~ManimConfig.digest_file`, :meth:`~ManimConfig.digest_args`, :meth:`~ManimConfig.digest_parser` """ if isinstance(obj, ManimConfig): self._d.update(obj._d) if obj.tex_template: self.tex_template = obj.tex_template elif isinstance(obj, dict): # First update the underlying _d, then update other properties _dict = {k: v for k, v in obj.items() if k in self._d} for k, v in _dict.items(): self[k] = v _dict = {k: v for k, v in obj.items() if k not in self._d} for k, v in _dict.items(): self[k] = v # don't allow to delete anything def __delitem__(self, key: str) -> NoReturn: raise AttributeError("'ManimConfig' object does not support item deletion") def __delattr__(self, key: str) -> NoReturn: raise AttributeError("'ManimConfig' object does not support item deletion") # copy functions def copy(self) -> Self: """Deepcopy the contents of this ManimConfig. Returns ------- :class:`ManimConfig` A copy of this object containing no shared references. See Also -------- :func:`tempconfig` Notes ----- This is the main mechanism behind :func:`tempconfig`. """ return copy.deepcopy(self) def __copy__(self) -> Self: """See ManimConfig.copy().""" return copy.deepcopy(self) def __deepcopy__(self, memo: dict[str, Any]) -> Self: """See ManimConfig.copy().""" c = type(self)() # Deepcopying the underlying dict is enough because all properties # either read directly from it or compute their value on the fly from # values read directly from it. c._d = copy.deepcopy(self._d, memo) # type: ignore[arg-type] return c # helper type-checking methods def _set_from_list(self, key: str, val: Any, values: list[Any]) -> None: """Set ``key`` to ``val`` if ``val`` is contained in ``values``.""" if val in values: self._d[key] = val else: raise ValueError(f"attempted to set {key} to {val}; must be in {values}") def _set_from_enum(self, key: str, enum_value: Any, enum_class: EnumMeta) -> None: """Set ``key`` to the enum object with value ``enum_value`` in the given ``enum_class``. Tests:: >>> from enum import Enum >>> class Fruit(Enum): ... APPLE = 1 ... BANANA = 2 ... CANTALOUPE = 3 >>> test_config = ManimConfig() >>> test_config._set_from_enum("fruit", 1, Fruit) >>> test_config._d['fruit'] >>> test_config._set_from_enum("fruit", Fruit.BANANA, Fruit) >>> test_config._d['fruit'] >>> test_config._set_from_enum("fruit", 42, Fruit) Traceback (most recent call last): ... ValueError: 42 is not a valid Fruit """ self._d[key] = enum_class(enum_value) def _set_boolean(self, key: str, val: Any) -> None: """Set ``key`` to ``val`` if ``val`` is Boolean.""" if val in [True, False]: self._d[key] = val else: raise ValueError(f"{key} must be boolean") def _set_tuple(self, key: str, val: tuple[Any]) -> None: if isinstance(val, tuple): self._d[key] = val else: raise ValueError(f"{key} must be tuple") def _set_str(self, key: str, val: Any) -> None: """Set ``key`` to ``val`` if ``val`` is a string.""" if isinstance(val, str): self._d[key] = val elif not val: self._d[key] = "" else: raise ValueError(f"{key} must be str or falsy value") def _set_between(self, key: str, val: float, lo: float, hi: float) -> None: """Set ``key`` to ``val`` if lo <= val <= hi.""" if lo <= val <= hi: self._d[key] = val else: raise ValueError(f"{key} must be {lo} <= {key} <= {hi}") def _set_int_between(self, key: str, val: int, lo: int, hi: int) -> None: """Set ``key`` to ``val`` if lo <= val <= hi.""" if lo <= val <= hi: self._d[key] = val else: raise ValueError( f"{key} must be an integer such that {lo} <= {key} <= {hi}", ) def _set_pos_number(self, key: str, val: int, allow_inf: bool) -> None: """Set ``key`` to ``val`` if ``val`` is a positive integer.""" if isinstance(val, int) and val > -1: self._d[key] = val elif allow_inf and val in [-1, float("inf")]: self._d[key] = float("inf") else: raise ValueError( f"{key} must be a non-negative integer (use -1 for infinity)", ) def __repr__(self) -> str: rep = "" for k, v in sorted(self._d.items(), key=lambda x: x[0]): rep += f"{k}: {v}, " return rep # builders def digest_parser(self, parser: configparser.ConfigParser) -> Self: """Process the config options present in a :class:`ConfigParser` object. This method processes arbitrary parsers, not only those read from a single file, whereas :meth:`~ManimConfig.digest_file` can only process one file at a time. Parameters ---------- parser An object reflecting the contents of one or many ``.cfg`` files. In particular, it may reflect the contents of multiple files that have been parsed in a cascading fashion. Returns ------- self : :class:`ManimConfig` This object, after processing the contents of ``parser``. See Also -------- :func:`make_config_parser`, :meth:`~.ManimConfig.digest_file`, :meth:`~.ManimConfig.digest_args`, Notes ----- If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first, and then call this function once (instead of calling :meth:`~.ManimConfig.digest_file` multiple times). Examples -------- To digest the config options set in two files, first create a ConfigParser and parse both files and then digest the parser: .. code-block:: python parser = configparser.ConfigParser() parser.read([file1, file2]) config = ManimConfig().digest_parser(parser) In fact, the global ``config`` object is initialized like so: .. code-block:: python parser = make_config_parser() config = ManimConfig().digest_parser(parser) """ self._parser = parser # boolean keys for key in [ "notify_outdated_version", "write_to_movie", "save_last_frame", "write_all", "save_pngs", "save_as_gif", "save_sections", "preview", "show_in_file_browser", "log_to_file", "disable_caching", "disable_caching_warning", "flush_cache", "custom_folders", "enable_gui", "fullscreen", "use_projection_fill_shaders", "use_projection_stroke_shaders", "enable_wireframe", "force_window", "no_latex_cleanup", "dry_run", ]: setattr(self, key, parser["CLI"].getboolean(key, fallback=False)) # int keys for key in [ "from_animation_number", "upto_animation_number", "max_files_cached", # the next two must be set BEFORE digesting frame_width and frame_height "pixel_height", "pixel_width", "seed", "window_monitor", "zero_pad", ]: setattr(self, key, parser["CLI"].getint(key)) # str keys for key in [ "assets_dir", "verbosity", "media_dir", "log_dir", "video_dir", "sections_dir", "images_dir", "text_dir", "tex_dir", "partial_movie_dir", "input_file", "output_file", "movie_file_extension", "background_color", "renderer", "window_position", "preview_command", ]: setattr(self, key, parser["CLI"].get(key, fallback="", raw=True)) # float keys for key in [ "background_opacity", "frame_rate", # the next two are floats but have their own logic, applied later # "frame_width", # "frame_height", ]: setattr(self, key, parser["CLI"].getfloat(key)) # tuple keys gui_location = tuple( map(int, re.split(r"[;,\-]", parser["CLI"]["gui_location"])), ) self.gui_location = gui_location window_size = parser["CLI"][ "window_size" ] # if not "default", get a tuple of the position if window_size != "default": window_size_numbers = tuple(map(int, re.split(r"[;,\-]", window_size))) self.window_size = window_size_numbers else: self.window_size = window_size # plugins plugins = parser["CLI"].get("plugins", fallback="", raw=True) plugin_list = [] if plugins is None or plugins == "" else plugins.split(",") self.plugins = plugin_list # the next two must be set AFTER digesting pixel_width and pixel_height self["frame_height"] = parser["CLI"].getfloat("frame_height", 8.0) width = parser["CLI"].getfloat("frame_width", None) if width is None: self["frame_width"] = self["frame_height"] * self["aspect_ratio"] else: self["frame_width"] = width # other logic tex_template_file = parser["CLI"].get("tex_template_file") if tex_template_file: self.tex_template_file = Path(tex_template_file) progress_bar = parser["CLI"].get("progress_bar") if progress_bar: self.progress_bar = progress_bar ffmpeg_loglevel = parser["ffmpeg"].get("loglevel") if ffmpeg_loglevel: self.ffmpeg_loglevel = ffmpeg_loglevel try: media_embed = parser["jupyter"].getboolean("media_embed") except ValueError: media_embed = None self.media_embed = media_embed media_width = parser["jupyter"].get("media_width") if media_width: self.media_width = media_width quality = parser["CLI"].get("quality", fallback="", raw=True) if quality: self.quality = _determine_quality(quality) return self def digest_args(self, args: argparse.Namespace) -> Self: """Process the config options present in CLI arguments. Parameters ---------- args An object returned by :func:`.main_utils.parse_args()`. Returns ------- self : :class:`ManimConfig` This object, after processing the contents of ``parser``. See Also -------- :func:`.main_utils.parse_args()`, :meth:`~.ManimConfig.digest_parser`, :meth:`~.ManimConfig.digest_file` Notes ----- If ``args.config_file`` is a non-empty string, ``ManimConfig`` tries to digest the contents of said file with :meth:`~ManimConfig.digest_file` before digesting any other CLI arguments. """ # if the input file is a config file, parse it properly if args.file.suffix == ".cfg": args.config_file = args.file # if args.file is `-`, the animation code has to be taken from STDIN, so the # input file path shouldn't be absolute, since that file won't be read. if str(args.file) == "-": self.input_file = args.file # if a config file has been passed, digest it first so that other CLI # flags supersede it if args.config_file: self.digest_file(args.config_file) # read input_file from the args if it wasn't set by the config file if not self.input_file: self.input_file = Path(args.file).absolute() self.scene_names = args.scene_names if args.scene_names is not None else [] self.output_file = args.output_file for key in [ "notify_outdated_version", "preview", "show_in_file_browser", "write_to_movie", "save_last_frame", "save_pngs", "save_as_gif", "save_sections", "write_all", "disable_caching", "format", "flush_cache", "progress_bar", "transparent", "scene_names", "verbosity", "renderer", "background_color", "enable_gui", "fullscreen", "use_projection_fill_shaders", "use_projection_stroke_shaders", "zero_pad", "enable_wireframe", "force_window", "dry_run", "no_latex_cleanup", "preview_command", "seed", ]: if hasattr(args, key): attr = getattr(args, key) # if attr is None, then no argument was passed and we should # not change the current config if attr is not None: self[key] = attr for key in [ "media_dir", # always set this one first "log_dir", "log_to_file", # always set this one last ]: if hasattr(args, key): attr = getattr(args, key) # if attr is None, then no argument was passed and we should # not change the current config if attr is not None: self[key] = attr if self["save_last_frame"]: self["write_to_movie"] = False # Handle the -n flag. nflag = args.from_animation_number if nflag: self.from_animation_number = nflag[0] try: self.upto_animation_number = nflag[1] except Exception: logger.info( f"No end scene number specified in -n option. Rendering from {nflag[0]} onwards...", ) # Handle the quality flags self.quality = _determine_quality(getattr(args, "quality", None)) # Handle the -r flag. rflag = args.resolution if rflag: self.pixel_width = int(rflag[0]) self.pixel_height = int(rflag[1]) fps = args.frame_rate if fps: self.frame_rate = float(fps) # Handle --custom_folders if args.custom_folders: for opt in [ "media_dir", "video_dir", "sections_dir", "images_dir", "text_dir", "tex_dir", "log_dir", "partial_movie_dir", ]: self[opt] = self._parser["custom_folders"].get(opt, raw=True) # --media_dir overrides the default.cfg file if hasattr(args, "media_dir") and args.media_dir: self.media_dir = args.media_dir # Handle --tex_template if args.tex_template: self.tex_template = TexTemplate.from_file(args.tex_template) if self.renderer == RendererType.OPENGL and args.write_to_movie is None: # --write_to_movie was not passed on the command line, so don't generate video. self["write_to_movie"] = False # Handle --gui_location flag. if args.gui_location is not None: self.gui_location = args.gui_location return self def digest_file(self, filename: StrPath) -> Self: """Process the config options present in a ``.cfg`` file. This method processes a single ``.cfg`` file, whereas :meth:`~ManimConfig.digest_parser` can process arbitrary parsers, built perhaps from multiple ``.cfg`` files. Parameters ---------- filename Path to the ``.cfg`` file. Returns ------- self : :class:`ManimConfig` This object, after processing the contents of ``filename``. See Also -------- :meth:`~ManimConfig.digest_file`, :meth:`~ManimConfig.digest_args`, :func:`make_config_parser` Notes ----- If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first and digesting them with one call to :meth:`~ManimConfig.digest_parser`, instead of calling this method multiple times. """ if not Path(filename).is_file(): raise FileNotFoundError( errno.ENOENT, "Error: --config_file could not find a valid config file.", str(filename), ) return self.digest_parser(make_config_parser(filename)) # config options are properties @property def preview(self) -> bool: """Whether to play the rendered movie (-p).""" return self._d["preview"] or self._d["enable_gui"] @preview.setter def preview(self, value: bool) -> None: self._set_boolean("preview", value) @property def show_in_file_browser(self) -> bool: """Whether to show the output file in the file browser (-f).""" return self._d["show_in_file_browser"] @show_in_file_browser.setter def show_in_file_browser(self, value: bool) -> None: self._set_boolean("show_in_file_browser", value) @property def progress_bar(self) -> str: """Whether to show progress bars while rendering animations.""" return self._d["progress_bar"] @progress_bar.setter def progress_bar(self, value: str) -> None: self._set_from_list("progress_bar", value, ["none", "display", "leave"]) @property def log_to_file(self) -> bool: """Whether to save logs to a file.""" return self._d["log_to_file"] @log_to_file.setter def log_to_file(self, value: bool) -> None: self._set_boolean("log_to_file", value) @property def notify_outdated_version(self) -> bool: """Whether to notify if there is a version update available.""" return self._d["notify_outdated_version"] @notify_outdated_version.setter def notify_outdated_version(self, value: bool) -> None: self._set_boolean("notify_outdated_version", value) @property def write_to_movie(self) -> bool: """Whether to render the scene to a movie file (-w).""" return self._d["write_to_movie"] @write_to_movie.setter def write_to_movie(self, value: bool) -> None: self._set_boolean("write_to_movie", value) @property def save_last_frame(self) -> bool: """Whether to save the last frame of the scene as an image file (-s).""" return self._d["save_last_frame"] @save_last_frame.setter def save_last_frame(self, value: bool) -> None: self._set_boolean("save_last_frame", value) @property def write_all(self) -> bool: """Whether to render all scenes in the input file (-a).""" return self._d["write_all"] @write_all.setter def write_all(self, value: bool) -> None: self._set_boolean("write_all", value) @property def save_pngs(self) -> bool: """Whether to save all frames in the scene as images files (-g).""" return self._d["save_pngs"] @save_pngs.setter def save_pngs(self, value: bool) -> None: self._set_boolean("save_pngs", value) @property def save_as_gif(self) -> bool: """Whether to save the rendered scene in .gif format (-i).""" return self._d["save_as_gif"] @save_as_gif.setter def save_as_gif(self, value: bool) -> None: self._set_boolean("save_as_gif", value) @property def save_sections(self) -> bool: """Whether to save single videos for each section in addition to the movie file.""" return self._d["save_sections"] @save_sections.setter def save_sections(self, value: bool) -> None: self._set_boolean("save_sections", value) @property def enable_wireframe(self) -> bool: """Whether to enable wireframe debugging mode in opengl.""" return self._d["enable_wireframe"] @enable_wireframe.setter def enable_wireframe(self, value: bool) -> None: self._set_boolean("enable_wireframe", value) @property def force_window(self) -> bool: """Whether to force window when using the opengl renderer.""" return self._d["force_window"] @force_window.setter def force_window(self, value: bool) -> None: self._set_boolean("force_window", value) @property def no_latex_cleanup(self) -> bool: """Prevents deletion of .aux, .dvi, and .log files produced by Tex and MathTex.""" return self._d["no_latex_cleanup"] @no_latex_cleanup.setter def no_latex_cleanup(self, value: bool) -> None: self._set_boolean("no_latex_cleanup", value) @property def preview_command(self) -> str: return self._d["preview_command"] @preview_command.setter def preview_command(self, value: str) -> None: self._set_str("preview_command", value) @property def verbosity(self) -> str: """Logger verbosity; "DEBUG", "INFO", "WARNING", "ERROR", or "CRITICAL" (-v).""" return self._d["verbosity"] @verbosity.setter def verbosity(self, val: str) -> None: self._set_from_list( "verbosity", val, ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], ) logger.setLevel(val) @property def format(self) -> str | None: """File format; "png", "gif", "mp4", "webm" or "mov".""" return self._d["format"] @format.setter def format(self, val: str) -> None: self._set_from_list( "format", val, [None, "png", "gif", "mp4", "mov", "webm"], ) self.resolve_movie_file_extension(self.transparent) if self.format == "webm": logger.warning( "Output format set as webm, this can be slower than other formats", ) @property def ffmpeg_loglevel(self) -> str: """Verbosity level of ffmpeg (no flag).""" return self._d["ffmpeg_loglevel"] @ffmpeg_loglevel.setter def ffmpeg_loglevel(self, val: str) -> None: self._set_from_list( "ffmpeg_loglevel", val, ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], ) logging.getLogger("libav").setLevel(self.ffmpeg_loglevel) @property def media_embed(self) -> bool | None: """Whether to embed videos in Jupyter notebook.""" return self._d["media_embed"] @media_embed.setter def media_embed(self, value: bool) -> None: self._set_boolean("media_embed", value) @property def media_width(self) -> str: """Media width in Jupyter notebook.""" return self._d["media_width"] @media_width.setter def media_width(self, value: str) -> None: self._set_str("media_width", value) @property def pixel_width(self) -> int: """Frame width in pixels (--resolution, -r).""" return self._d["pixel_width"] @pixel_width.setter def pixel_width(self, value: int) -> None: self._set_pos_number("pixel_width", value, False) @property def pixel_height(self) -> int: """Frame height in pixels (--resolution, -r).""" return self._d["pixel_height"] @pixel_height.setter def pixel_height(self, value: int) -> None: self._set_pos_number("pixel_height", value, False) @property def aspect_ratio(self) -> float: """Aspect ratio (width / height) in pixels (--resolution, -r).""" assert isinstance(self._d["pixel_width"], int) assert isinstance(self._d["pixel_height"], int) return self._d["pixel_width"] / self._d["pixel_height"] @property def frame_height(self) -> float: """Frame height in logical units (no flag).""" return self._d["frame_height"] @frame_height.setter def frame_height(self, value: float) -> None: self._d.__setitem__("frame_height", value) @property def frame_width(self) -> float: """Frame width in logical units (no flag).""" return self._d["frame_width"] @frame_width.setter def frame_width(self, value: float) -> None: self._d.__setitem__("frame_width", value) @property def frame_y_radius(self) -> float: """Half the frame height (no flag).""" return self._d["frame_height"] / 2 # type: ignore[operator] @frame_y_radius.setter def frame_y_radius(self, value: float) -> None: self._d.__setitem__("frame_y_radius", value) or self._d.__setitem__( # type: ignore[func-returns-value] "frame_height", 2 * value ) @property def frame_x_radius(self) -> float: """Half the frame width (no flag).""" return self._d["frame_width"] / 2 # type: ignore[operator] @frame_x_radius.setter def frame_x_radius(self, value: float) -> None: self._d.__setitem__("frame_x_radius", value) or self._d.__setitem__( # type: ignore[func-returns-value] "frame_width", 2 * value ) @property def top(self) -> Vector3D: """Coordinate at the center top of the frame.""" return self.frame_y_radius * constants.UP @property def bottom(self) -> Vector3D: """Coordinate at the center bottom of the frame.""" return self.frame_y_radius * constants.DOWN @property def left_side(self) -> Vector3D: """Coordinate at the middle left of the frame.""" return self.frame_x_radius * constants.LEFT @property def right_side(self) -> Vector3D: """Coordinate at the middle right of the frame.""" return self.frame_x_radius * constants.RIGHT @property def frame_rate(self) -> float: """Frame rate in frames per second.""" return self._d["frame_rate"] @frame_rate.setter def frame_rate(self, value: float) -> None: self._d.__setitem__("frame_rate", value) # TODO: This was parsed before maybe add ManimColor(val), but results in circular import @property def background_color(self) -> ManimColor: """Background color of the scene (-c).""" return self._d["background_color"] @background_color.setter def background_color(self, value: Any) -> None: self._d.__setitem__("background_color", ManimColor(value)) @property def from_animation_number(self) -> int: """Start rendering animations at this number (-n).""" return self._d["from_animation_number"] @from_animation_number.setter def from_animation_number(self, value: int) -> None: self._d.__setitem__("from_animation_number", value) @property def upto_animation_number(self) -> int: """Stop rendering animations at this number. Use -1 to avoid skipping (-n).""" return self._d["upto_animation_number"] @upto_animation_number.setter def upto_animation_number(self, value: int) -> None: self._set_pos_number("upto_animation_number", value, True) @property def max_files_cached(self) -> int: """Maximum number of files cached. Use -1 for infinity (no flag).""" return self._d["max_files_cached"] @max_files_cached.setter def max_files_cached(self, value: int) -> None: self._set_pos_number("max_files_cached", value, True) @property def window_monitor(self) -> int: """The monitor on which the scene will be rendered.""" return self._d["window_monitor"] @window_monitor.setter def window_monitor(self, value: int) -> None: self._set_pos_number("window_monitor", value, True) @property def flush_cache(self) -> bool: """Whether to delete all the cached partial movie files.""" return self._d["flush_cache"] @flush_cache.setter def flush_cache(self, value: bool) -> None: self._set_boolean("flush_cache", value) @property def disable_caching(self) -> bool: """Whether to use scene caching.""" return self._d["disable_caching"] @disable_caching.setter def disable_caching(self, value: bool) -> None: self._set_boolean("disable_caching", value) @property def disable_caching_warning(self) -> bool: """Whether a warning is raised if there are too much submobjects to hash.""" return self._d["disable_caching_warning"] @disable_caching_warning.setter def disable_caching_warning(self, value: bool) -> None: self._set_boolean("disable_caching_warning", value) @property def movie_file_extension(self) -> str: """Either .mp4, .webm or .mov.""" return self._d["movie_file_extension"] @movie_file_extension.setter def movie_file_extension(self, value: str) -> None: self._set_from_list("movie_file_extension", value, [".mp4", ".mov", ".webm"]) @property def background_opacity(self) -> float: """A number between 0.0 (fully transparent) and 1.0 (fully opaque).""" return self._d["background_opacity"] @background_opacity.setter def background_opacity(self, value: float) -> None: self._set_between("background_opacity", value, 0, 1) if self.background_opacity < 1: self.resolve_movie_file_extension(is_transparent=True) @property def frame_size(self) -> tuple[int, int]: """Tuple with (pixel width, pixel height) (no flag).""" return (self._d["pixel_width"], self._d["pixel_height"]) @frame_size.setter def frame_size(self, value: tuple[int, int]) -> None: self._d.__setitem__("pixel_width", value[0]) or self._d.__setitem__( # type: ignore[func-returns-value] "pixel_height", value[1] ) @property def quality(self) -> str | None: """Video quality (-q).""" keys = ["pixel_width", "pixel_height", "frame_rate"] q = {k: self[k] for k in keys} for qual in constants.QUALITIES: if all(q[k] == constants.QUALITIES[qual][k] for k in keys): # type: ignore[literal-required] return qual return None @quality.setter def quality(self, value: str | None) -> None: if value is None: return if value not in constants.QUALITIES: raise KeyError(f"quality must be one of {list(constants.QUALITIES.keys())}") q = constants.QUALITIES[value] self.frame_size = q["pixel_width"], q["pixel_height"] self.frame_rate = q["frame_rate"] @property def transparent(self) -> bool: """Whether the background opacity is less than 1.0 (-t).""" assert isinstance(self._d["background_opacity"], float) return self._d["background_opacity"] < 1.0 @transparent.setter def transparent(self, value: bool) -> None: self._d["background_opacity"] = float(not value) self.resolve_movie_file_extension(value) @property def dry_run(self) -> bool: """Whether dry run is enabled.""" return self._d["dry_run"] @dry_run.setter def dry_run(self, val: bool) -> None: self._d["dry_run"] = val if val: self.write_to_movie = False self.write_all = False self.save_last_frame = False self.format = None @property def renderer(self) -> RendererType: """The currently active renderer. Populated with one of the available renderers in :class:`.RendererType`. Tests:: >>> test_config = ManimConfig() >>> test_config.renderer is None # a new ManimConfig is unpopulated True >>> test_config.renderer = 'opengl' >>> test_config.renderer >>> test_config.renderer = 42 Traceback (most recent call last): ... ValueError: 42 is not a valid RendererType Check that capitalization of renderer types is irrelevant:: >>> test_config.renderer = 'OpenGL' >>> test_config.renderer = 'cAirO' """ return self._d["renderer"] @renderer.setter def renderer(self, value: str | RendererType) -> None: """The setter of the renderer property. Takes care of switching inheritance bases using the :class:`.ConvertToOpenGL` metaclass. """ if isinstance(value, str): value = value.lower() renderer = RendererType(value) try: from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VMobject for cls in ConvertToOpenGL._converted_classes: if renderer == RendererType.OPENGL: conversion_dict = { Mobject: OpenGLMobject, VMobject: OpenGLVMobject, } else: conversion_dict = { OpenGLMobject: Mobject, OpenGLVMobject: VMobject, } cls.__bases__ = tuple( conversion_dict.get(base, base) for base in cls.__bases__ ) except ImportError: # The renderer is set during the initial import of the # library for the first time. The imports above cause an # ImportError due to circular imports. However, the # metaclass sets stuff up correctly in this case, so we # can just do nothing. pass self._set_from_enum("renderer", renderer, RendererType) @property def media_dir(self) -> str: """Main output directory. See :meth:`ManimConfig.get_dir`.""" return self._d["media_dir"] @media_dir.setter def media_dir(self, value: str | Path) -> None: self._set_dir("media_dir", value) @property def window_position(self) -> str: """Set the position of preview window. You can use directions, e.g. UL/DR/ORIGIN/LEFT...or the position(pixel) of the upper left corner of the window, e.g. '960,540'.""" return self._d["window_position"] @window_position.setter def window_position(self, value: str) -> None: self._d.__setitem__("window_position", value) @property def window_size(self) -> str | tuple[int, ...]: """The size of the opengl window. 'default' to automatically scale the window based on the display monitor.""" return self._d["window_size"] @window_size.setter def window_size(self, value: str | tuple[int, ...]) -> None: self._d.__setitem__("window_size", value) def resolve_movie_file_extension(self, is_transparent: bool) -> None: prev_file_extension = self.movie_file_extension if is_transparent: self.movie_file_extension = ".webm" if self.format == "webm" else ".mov" elif self.format == "webm": self.movie_file_extension = ".webm" elif self.format == "mov": self.movie_file_extension = ".mov" else: self.movie_file_extension = ".mp4" if self.movie_file_extension != prev_file_extension: logger.warning( f"Output format changed to '{self.movie_file_extension}' " "to support transparency", ) @property def enable_gui(self) -> bool: """Enable GUI interaction.""" return self._d["enable_gui"] @enable_gui.setter def enable_gui(self, value: bool) -> None: self._set_boolean("enable_gui", value) @property def gui_location(self) -> tuple[int, ...]: """Location parameters for the GUI window (e.g., screen coordinates or layout settings).""" return self._d["gui_location"] @gui_location.setter def gui_location(self, value: tuple[Any]) -> None: self._set_tuple("gui_location", value) @property def fullscreen(self) -> bool: """Expand the window to its maximum possible size.""" return self._d["fullscreen"] @fullscreen.setter def fullscreen(self, value: bool) -> None: self._set_boolean("fullscreen", value) @property def use_projection_fill_shaders(self) -> bool: """Use shaders for OpenGLVMobject fill which are compatible with transformation matrices.""" return self._d["use_projection_fill_shaders"] @use_projection_fill_shaders.setter def use_projection_fill_shaders(self, value: bool) -> None: self._set_boolean("use_projection_fill_shaders", value) @property def use_projection_stroke_shaders(self) -> bool: """Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.""" return self._d["use_projection_stroke_shaders"] @use_projection_stroke_shaders.setter def use_projection_stroke_shaders(self, value: bool) -> None: self._set_boolean("use_projection_stroke_shaders", value) @property def zero_pad(self) -> int: """PNG zero padding. A number between 0 (no zero padding) and 9 (9 columns minimum).""" return self._d["zero_pad"] @zero_pad.setter def zero_pad(self, value: int) -> None: self._set_int_between("zero_pad", value, 0, 9) def get_dir(self, key: str, **kwargs: Any) -> Path: """Resolve a config option that stores a directory. Config options that store directories may depend on one another. This method is used to provide the actual directory to the end user. Parameters ---------- key The config option to be resolved. Must be an option ending in ``'_dir'``, for example ``'media_dir'`` or ``'video_dir'``. kwargs Any strings to be used when resolving the directory. Returns ------- :class:`pathlib.Path` Path to the requested directory. If the path resolves to the empty string, return ``None`` instead. Raises ------ :class:`KeyError` When ``key`` is not a config option that stores a directory and thus :meth:`~ManimConfig.get_dir` is not appropriate; or when ``key`` is appropriate but there is not enough information to resolve the directory. Notes ----- Standard :meth:`str.format` syntax is used to resolve the paths so the paths may contain arbitrary placeholders using f-string notation. However, these will require ``kwargs`` to contain the required values. Examples -------- The value of ``config.tex_dir`` is ``'{media_dir}/Tex'`` by default, i.e. it is a subfolder of wherever ``config.media_dir`` is located. In order to get the *actual* directory, use :meth:`~ManimConfig.get_dir`. .. code-block:: pycon >>> from manim import config as globalconfig >>> config = globalconfig.copy() >>> config.tex_dir '{media_dir}/Tex' >>> config.media_dir './media' >>> config.get_dir("tex_dir").as_posix() 'media/Tex' Resolving directories is done in a lazy way, at the last possible moment, to reflect any changes in other config options: .. code-block:: pycon >>> config.media_dir = "my_media_dir" >>> config.get_dir("tex_dir").as_posix() 'my_media_dir/Tex' Some directories depend on information that is not available to :class:`ManimConfig`. For example, the default value of `video_dir` includes the name of the input file and the video quality (e.g. 480p15). This informamtion has to be supplied via ``kwargs``: .. code-block:: pycon >>> config.video_dir '{media_dir}/videos/{module_name}/{quality}' >>> config.get_dir("video_dir") Traceback (most recent call last): KeyError: 'video_dir {media_dir}/videos/{module_name}/{quality} requires the following keyword arguments: module_name' >>> config.get_dir("video_dir", module_name="myfile").as_posix() 'my_media_dir/videos/myfile/1080p60' Note the quality does not need to be passed as keyword argument since :class:`ManimConfig` does store information about quality. Directories may be recursively defined. For example, the config option ``partial_movie_dir`` depends on ``video_dir``, which in turn depends on ``media_dir``: .. code-block:: pycon >>> config.partial_movie_dir '{video_dir}/partial_movie_files/{scene_name}' >>> config.get_dir("partial_movie_dir") Traceback (most recent call last): KeyError: 'partial_movie_dir {video_dir}/partial_movie_files/{scene_name} requires the following keyword arguments: scene_name' >>> config.get_dir( ... "partial_movie_dir", module_name="myfile", scene_name="myscene" ... ).as_posix() 'my_media_dir/videos/myfile/1080p60/partial_movie_files/myscene' Standard f-string syntax is used. Arbitrary names can be used when defining directories, as long as the corresponding values are passed to :meth:`ManimConfig.get_dir` via ``kwargs``. .. code-block:: pycon >>> config.media_dir = "{dir1}/{dir2}" >>> config.get_dir("media_dir") Traceback (most recent call last): KeyError: 'media_dir {dir1}/{dir2} requires the following keyword arguments: dir1' >>> config.get_dir("media_dir", dir1="foo", dir2="bar").as_posix() 'foo/bar' >>> config.media_dir = "./media" >>> config.get_dir("media_dir").as_posix() 'media' """ dirs = [ "assets_dir", "media_dir", "video_dir", "sections_dir", "images_dir", "text_dir", "tex_dir", "log_dir", "input_file", "output_file", "partial_movie_dir", ] if key not in dirs: raise KeyError( "must pass one of " "{media,video,images,text,tex,log}_dir " "or {input,output}_file", ) dirs.remove(key) # a path cannot contain itself all_args = {k: self._d[k] for k in dirs} all_args.update(kwargs) all_args["quality"] = f"{self.pixel_height}p{self.frame_rate:g}" path = self._d[key] assert isinstance(path, str) while "{" in path: try: path = path.format(**all_args) except KeyError as exc: raise KeyError( f"{key} {self._d[key]} requires the following " + "keyword arguments: " + " ".join(exc.args), ) from exc return Path(path) if path else None def _set_dir(self, key: str, val: str | Path) -> None: if isinstance(val, Path): self._d.__setitem__(key, str(val)) else: self._d.__setitem__(key, val) @property def assets_dir(self) -> str: """Directory to locate video assets (no flag).""" return self._d["assets_dir"] @assets_dir.setter def assets_dir(self, value: str | Path) -> None: self._set_dir("assets_dir", value) @property def log_dir(self) -> str: """Directory to place logs. See :meth:`ManimConfig.get_dir`.""" return self._d["log_dir"] @log_dir.setter def log_dir(self, value: str | Path) -> None: self._set_dir("log_dir", value) @property def video_dir(self) -> str: """Directory to place videos (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["video_dir"] @video_dir.setter def video_dir(self, value: str | Path) -> None: self._set_dir("video_dir", value) @property def sections_dir(self) -> str: """Directory to place section videos (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["sections_dir"] @sections_dir.setter def sections_dir(self, value: str | Path) -> None: self._set_dir("sections_dir", value) @property def images_dir(self) -> str: """Directory to place images (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["images_dir"] @images_dir.setter def images_dir(self, value: str | Path) -> None: self._set_dir("images_dir", value) @property def text_dir(self) -> str: """Directory to place text (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["text_dir"] @text_dir.setter def text_dir(self, value: str | Path) -> None: self._set_dir("text_dir", value) @property def tex_dir(self) -> str: """Directory to place tex (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["tex_dir"] @tex_dir.setter def tex_dir(self, value: str | Path) -> None: self._set_dir("tex_dir", value) @property def partial_movie_dir(self) -> str: """Directory to place partial movie files (no flag). See :meth:`ManimConfig.get_dir`.""" return self._d["partial_movie_dir"] @partial_movie_dir.setter def partial_movie_dir(self, value: str | Path) -> None: self._set_dir("partial_movie_dir", value) @property def custom_folders(self) -> str: """Whether to use custom folder output.""" return self._d["custom_folders"] @custom_folders.setter def custom_folders(self, value: str | Path) -> None: self._set_dir("custom_folders", value) @property def input_file(self) -> str | Path: """Input file name.""" return self._d["input_file"] @input_file.setter def input_file(self, value: str | Path) -> None: self._set_dir("input_file", value) @property def output_file(self) -> str: """Output file name (-o).""" return self._d["output_file"] @output_file.setter def output_file(self, value: str | Path) -> None: self._set_dir("output_file", value) @property def scene_names(self) -> list[str]: """Scenes to play from file.""" return self._d["scene_names"] @scene_names.setter def scene_names(self, value: list[str]) -> None: self._d.__setitem__("scene_names", value) @property def tex_template(self) -> TexTemplate: """Template used when rendering Tex. See :class:`.TexTemplate`.""" if not hasattr(self, "_tex_template") or not self._tex_template: # type: ignore[has-type] fn = self._d["tex_template_file"] if fn: self._tex_template = TexTemplate.from_file(fn) else: self._tex_template = TexTemplate() return self._tex_template @tex_template.setter def tex_template(self, val: TexTemplate) -> None: if isinstance(val, TexTemplate): self._tex_template = val @property def tex_template_file(self) -> Path: """File to read Tex template from (no flag). See :class:`.TexTemplate`.""" return self._d["tex_template_file"] @tex_template_file.setter def tex_template_file(self, val: str) -> None: if val: if not os.access(val, os.R_OK): logger.warning( f"Custom TeX template {val} not found or not readable.", ) else: self._d["tex_template_file"] = Path(val) else: self._d["tex_template_file"] = val # actually set the falsy value @property def plugins(self) -> list[str]: """List of plugins to enable.""" return self._d["plugins"] @plugins.setter def plugins(self, value: list[str]) -> None: self._d["plugins"] = value @property def seed(self) -> int | None: """Random seed for reproducibility. None means no seed is set.""" return self._d["seed"] @seed.setter def seed(self, value: int | None) -> None: if value is None: return self._set_pos_number("seed", value, False) # TODO: to be used in the future - see PR #620 # https://github.com/ManimCommunity/manim/pull/620 class ManimFrame(Mapping): _OPTS: ClassVar[set[str]] = { "pixel_width", "pixel_height", "aspect_ratio", "frame_height", "frame_width", "frame_y_radius", "frame_x_radius", "top", "bottom", "left_side", "right_side", } _CONSTANTS: ClassVar[dict[str, Vector3D]] = { "UP": np.array((0.0, 1.0, 0.0)), "DOWN": np.array((0.0, -1.0, 0.0)), "RIGHT": np.array((1.0, 0.0, 0.0)), "LEFT": np.array((-1.0, 0.0, 0.0)), "IN": np.array((0.0, 0.0, -1.0)), "OUT": np.array((0.0, 0.0, 1.0)), "ORIGIN": np.array((0.0, 0.0, 0.0)), "X_AXIS": np.array((1.0, 0.0, 0.0)), "Y_AXIS": np.array((0.0, 1.0, 0.0)), "Z_AXIS": np.array((0.0, 0.0, 1.0)), "UL": np.array((-1.0, 1.0, 0.0)), "UR": np.array((1.0, 1.0, 0.0)), "DL": np.array((-1.0, -1.0, 0.0)), "DR": np.array((1.0, -1.0, 0.0)), } _c: ManimConfig def __init__(self, c: ManimConfig) -> None: if not isinstance(c, ManimConfig): raise TypeError("argument must be instance of 'ManimConfig'") # need to use __dict__ directly because setting attributes is not # allowed (see __setattr__) self.__dict__["_c"] = c # there are required by parent class Mapping to behave like a dict def __getitem__(self, key: str) -> Any: if key in self._OPTS: return self._c[key] elif key in self._CONSTANTS: return self._CONSTANTS[key] else: raise KeyError(key) def __iter__(self) -> Iterator[Any]: return iter(list(self._OPTS) + list(self._CONSTANTS)) def __len__(self) -> int: return len(self._OPTS) # make this truly immutable def __setattr__(self, attr: Any, val: Any) -> NoReturn: raise TypeError("'ManimFrame' object does not support item assignment") def __setitem__(self, key: Any, val: Any) -> NoReturn: raise TypeError("'ManimFrame' object does not support item assignment") def __delitem__(self, key: Any) -> NoReturn: raise TypeError("'ManimFrame' object does not support item deletion") for opt in list(ManimFrame._OPTS) + list(ManimFrame._CONSTANTS): setattr(ManimFrame, opt, property(lambda self, o=opt: self[o])) # type: ignore[misc] ================================================ FILE: manim/animation/__init__.py ================================================ ================================================ FILE: manim/animation/animation.py ================================================ """Animate mobjects.""" from __future__ import annotations from manim.mobject.opengl.opengl_mobject import OpenGLMobject from .. import config, logger from ..constants import RendererType from ..mobject import mobject from ..mobject.mobject import Group, Mobject from ..mobject.opengl import opengl_mobject from ..utils.rate_functions import linear, smooth __all__ = ["Animation", "Wait", "Add", "override_animation"] from collections.abc import Callable, Iterable, Sequence from copy import deepcopy from functools import partialmethod from typing import TYPE_CHECKING, Any, Self if TYPE_CHECKING: from manim.scene.scene import Scene DEFAULT_ANIMATION_RUN_TIME: float = 1.0 DEFAULT_ANIMATION_LAG_RATIO: float = 0.0 class Animation: """An animation. Animations have a fixed time span. Parameters ---------- mobject The mobject to be animated. This is not required for all types of animations. lag_ratio Defines the delay after which the animation is applied to submobjects. This lag is relative to the duration of the animation. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time. run_time The duration of the animation in seconds. rate_func The function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`) . For example ``rate_func(0.5)`` is the proportion of the animation that is done after half of the animations run time. reverse_rate_function Reverses the rate function of the animation. Setting ``reverse_rate_function`` does not have any effect on ``remover`` or ``introducer``. These need to be set explicitly if an introducer-animation should be turned into a remover one and vice versa. name The name of the animation. This gets displayed while rendering the animation. Defaults to (). remover Whether the given mobject should be removed from the scene after this animation. suspend_mobject_updating Whether updaters of the mobject should be suspended during the animation. .. NOTE:: In the current implementation of this class, the specified rate function is applied within :meth:`.Animation.interpolate_mobject` call as part of the call to :meth:`.Animation.interpolate_submobject`. For subclasses of :class:`.Animation` that are implemented by overriding :meth:`interpolate_mobject`, the rate function has to be applied manually (e.g., by passing ``self.rate_func(alpha)`` instead of just ``alpha``). Examples -------- .. manim:: LagRatios class LagRatios(Scene): def construct(self): ratios = [0, 0.1, 0.5, 1, 2] # demonstrated lag_ratios # Create dot groups group = VGroup(*[Dot() for _ in range(4)]).arrange_submobjects() groups = VGroup(*[group.copy() for _ in ratios]).arrange_submobjects(buff=1) self.add(groups) # Label groups self.add(Text("lag_ratio = ", font_size=36).next_to(groups, UP, buff=1.5)) for group, ratio in zip(groups, ratios): self.add(Text(str(ratio), font_size=36).next_to(group, UP)) #Animate groups with different lag_ratios self.play(AnimationGroup(*[ group.animate(lag_ratio=ratio, run_time=1.5).shift(DOWN * 2) for group, ratio in zip(groups, ratios) ])) # lag_ratio also works recursively on nested submobjects: self.play(groups.animate(run_time=1, lag_ratio=0.1).shift(UP * 2)) """ def __new__( cls, mobject=None, *args, use_override=True, **kwargs, ) -> Self: if isinstance(mobject, Mobject) and use_override: func = mobject.animation_override_for(cls) if func is not None: anim = func(mobject, *args, **kwargs) logger.debug( f"The {cls.__name__} animation has been overridden for " f"{type(mobject).__name__} mobjects. use_override = False can " f" be used as keyword argument to prevent animation overriding.", ) return anim return super().__new__(cls) def __init__( self, mobject: Mobject | OpenGLMobject | None, lag_ratio: float = DEFAULT_ANIMATION_LAG_RATIO, run_time: float = DEFAULT_ANIMATION_RUN_TIME, rate_func: Callable[[float], float] = smooth, reverse_rate_function: bool = False, name: str = None, remover: bool = False, # remove a mobject from the screen? suspend_mobject_updating: bool = True, introducer: bool = False, *, _on_finish: Callable[[], None] = lambda _: None, use_override: bool = True, # included here to avoid TypeError if passed from a subclass' constructor ) -> None: self._typecheck_input(mobject) self.run_time: float = run_time self.rate_func: Callable[[float], float] = rate_func self.reverse_rate_function: bool = reverse_rate_function self.name: str | None = name self.remover: bool = remover self.introducer: bool = introducer self.suspend_mobject_updating: bool = suspend_mobject_updating self.lag_ratio: float = lag_ratio self._on_finish: Callable[[Scene], None] = _on_finish if config["renderer"] == RendererType.OPENGL: self.starting_mobject: OpenGLMobject = OpenGLMobject() self.mobject: OpenGLMobject = ( mobject if mobject is not None else OpenGLMobject() ) else: self.starting_mobject: Mobject = Mobject() self.mobject: Mobject = mobject if mobject is not None else Mobject() if hasattr(self, "CONFIG"): logger.error( ( "CONFIG has been removed from ManimCommunity.", "Please use keyword arguments instead.", ), ) @property def run_time(self) -> float: return self._run_time @run_time.setter def run_time(self, value: float) -> None: if value < 0: raise ValueError( f"The run_time of {self.__class__.__name__} cannot be " f"negative. The given value was {value}." ) self._run_time = value def _typecheck_input(self, mobject: Mobject | None) -> None: if mobject is None: logger.debug("Animation with empty mobject") elif not isinstance(mobject, (Mobject, OpenGLMobject)): raise TypeError("Animation only works on Mobjects") def __str__(self) -> str: if self.name: return self.name return f"{self.__class__.__name__}({str(self.mobject)})" def __repr__(self) -> str: return str(self) def begin(self) -> None: """Begin the animation. This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method. """ self.starting_mobject = self.create_starting_mobject() if self.suspend_mobject_updating: # All calls to self.mobject's internal updaters # during the animation, either from this Animation # or from the surrounding scene, should do nothing. # It is, however, okay and desirable to call # the internal updaters of self.starting_mobject, # or any others among self.get_all_mobjects() self.mobject.suspend_updating() self.interpolate(0) def finish(self) -> None: # TODO: begin and finish should require a scene as parameter. # That way Animation.clean_up_from_screen and Scene.add_mobjects_from_animations # could be removed as they fulfill basically the same purpose. """Finish the animation. This method gets called when the animation is over. """ self.interpolate(1) if self.suspend_mobject_updating and self.mobject is not None: self.mobject.resume_updating() def clean_up_from_scene(self, scene: Scene) -> None: """Clean up the :class:`~.Scene` after finishing the animation. This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover. Parameters ---------- scene The scene the animation should be cleaned up from. """ self._on_finish(scene) if self.is_remover(): scene.remove(self.mobject) def _setup_scene(self, scene: Scene) -> None: """Setup up the :class:`~.Scene` before starting the animation. This includes to :meth:`~.Scene.add` the Animation's :class:`~.Mobject` if the animation is an introducer. Parameters ---------- scene The scene the animation should be cleaned up from. """ if scene is None: return if ( self.is_introducer() and self.mobject not in scene.get_mobject_family_members() ): scene.add(self.mobject) def create_starting_mobject(self) -> Mobject | OpenGLMobject: # Keep track of where the mobject starts return self.mobject.copy() def get_all_mobjects(self) -> Sequence[Mobject | OpenGLMobject]: """Get all mobjects involved in the animation. Ordering must match the ordering of arguments to interpolate_submobject Returns ------- Sequence[Mobject] The sequence of mobjects. """ return self.mobject, self.starting_mobject def get_all_families_zipped(self) -> Iterable[tuple]: if config["renderer"] == RendererType.OPENGL: return zip( *(mob.get_family() for mob in self.get_all_mobjects()), strict=False ) return zip( *(mob.family_members_with_points() for mob in self.get_all_mobjects()), strict=False, ) def update_mobjects(self, dt: float) -> None: """ Updates things like starting_mobject, and (for Transforms) target_mobject. Note, since typically (always?) self.mobject will have its updating suspended during the animation, this will do nothing to self.mobject. """ for mob in self.get_all_mobjects_to_update(): mob.update(dt) def get_all_mobjects_to_update(self) -> list[Mobject]: """Get all mobjects to be updated during the animation. Returns ------- List[Mobject] The list of mobjects to be updated during the animation. """ # The surrounding scene typically handles # updating of self.mobject. Besides, in # most cases its updating is suspended anyway return list(filter(lambda m: m is not self.mobject, self.get_all_mobjects())) def copy(self) -> Animation: """Create a copy of the animation. Returns ------- Animation A copy of ``self`` """ return deepcopy(self) # Methods for interpolation, the mean of an Animation # TODO: stop using alpha as parameter name in different meanings. def interpolate(self, alpha: float) -> None: """Set the animation progress. This method gets called for every frame during an animation. Parameters ---------- alpha The relative time to set the animation to, 0 meaning the start, 1 meaning the end. """ self.interpolate_mobject(alpha) def interpolate_mobject(self, alpha: float) -> None: """Interpolates the mobject of the :class:`Animation` based on alpha value. Parameters ---------- alpha A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively. """ families = list(self.get_all_families_zipped()) for i, mobs in enumerate(families): sub_alpha = self.get_sub_alpha(alpha, i, len(families)) self.interpolate_submobject(*mobs, sub_alpha) def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, # target_copy: Mobject, #Todo: fix - signature of interpolate_submobject differs in Transform(). alpha: float, ) -> Animation: # Typically implemented by subclass pass def get_sub_alpha(self, alpha: float, index: int, num_submobjects: int) -> float: """Get the animation progress of any submobjects subanimation. Parameters ---------- alpha The overall animation progress index The index of the subanimation. num_submobjects The total count of subanimations. Returns ------- float The progress of the subanimation. """ # TODO, make this more understandable, and/or combine # its functionality with AnimationGroup's method # build_animations_with_timings lag_ratio = self.lag_ratio full_length = (num_submobjects - 1) * lag_ratio + 1 value = alpha * full_length lower = index * lag_ratio if self.reverse_rate_function: return self.rate_func(1 - (value - lower)) else: return self.rate_func(value - lower) # Getters and setters def set_run_time(self, run_time: float) -> Animation: """Set the run time of the animation. Parameters ---------- run_time The new time the animation should take in seconds. .. note:: The run_time of an animation should not be changed while it is already running. Returns ------- Animation ``self`` """ self.run_time = run_time return self # TODO: is this getter even necessary? def get_run_time(self) -> float: """Get the run time of the animation. Returns ------- float The time the animation takes in seconds. """ return self.run_time def set_rate_func( self, rate_func: Callable[[float], float], ) -> Animation: """Set the rate function of the animation. Parameters ---------- rate_func The new function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`). Returns ------- Animation ``self`` """ self.rate_func = rate_func return self def get_rate_func( self, ) -> Callable[[float], float]: """Get the rate function of the animation. Returns ------- Callable[[float], float] The rate function of the animation. """ return self.rate_func def set_name(self, name: str) -> Animation: """Set the name of the animation. Parameters ---------- name The new name of the animation. Returns ------- Animation ``self`` """ self.name = name return self def is_remover(self) -> bool: """Test if the animation is a remover. Returns ------- bool ``True`` if the animation is a remover, ``False`` otherwise. """ return self.remover def is_introducer(self) -> bool: """Test if the animation is an introducer. Returns ------- bool ``True`` if the animation is an introducer, ``False`` otherwise. """ return self.introducer @classmethod def __init_subclass__(cls, **kwargs) -> None: super().__init_subclass__(**kwargs) cls._original__init__ = cls.__init__ _original__init__ = __init__ # needed if set_default() is called with no kwargs directly from Animation @classmethod def set_default(cls, **kwargs) -> None: """Sets the default values of keyword arguments. If this method is called without any additional keyword arguments, the original default values of the initialization method of this class are restored. Parameters ---------- kwargs Passing any keyword argument will update the default values of the keyword arguments of the initialization function of this class. Examples -------- .. manim:: ChangeDefaultAnimation class ChangeDefaultAnimation(Scene): def construct(self): Rotate.set_default(run_time=2, rate_func=rate_functions.linear) Indicate.set_default(color=None) S = Square(color=BLUE, fill_color=BLUE, fill_opacity=0.25) self.add(S) self.play(Rotate(S, PI)) self.play(Indicate(S)) Rotate.set_default() Indicate.set_default() """ if kwargs: cls.__init__ = partialmethod(cls.__init__, **kwargs) else: cls.__init__ = cls._original__init__ def prepare_animation( anim: Animation | mobject._AnimationBuilder | opengl_mobject._AnimationBuilder, ) -> Animation: r"""Returns either an unchanged animation, or the animation built from a passed animation factory. Examples -------- :: >>> from manim import Square, FadeIn >>> s = Square() >>> prepare_animation(FadeIn(s)) FadeIn(Square) :: >>> prepare_animation(s.animate.scale(2).rotate(42)) _MethodAnimation(Square) :: >>> prepare_animation(42) Traceback (most recent call last): ... TypeError: Object 42 cannot be converted to an animation """ if isinstance(anim, mobject._AnimationBuilder): return anim.build() if isinstance(anim, opengl_mobject._AnimationBuilder): return anim.build() if isinstance(anim, Animation): return anim raise TypeError(f"Object {anim} cannot be converted to an animation") class Wait(Animation): """A "no operation" animation. Parameters ---------- run_time The amount of time that should pass. stop_condition A function without positional arguments that evaluates to a boolean. The function is evaluated after every new frame has been rendered. Playing the animation stops after the return value is truthy, or after the specified ``run_time`` has passed. frozen_frame Controls whether or not the wait animation is static, i.e., corresponds to a frozen frame. If ``False`` is passed, the render loop still progresses through the animation as usual and (among other things) continues to call updater functions. If ``None`` (the default value), the :meth:`.Scene.play` call tries to determine whether the Wait call can be static or not itself via :meth:`.Scene.should_mobjects_update`. kwargs Keyword arguments to be passed to the parent class, :class:`.Animation`. """ def __init__( self, run_time: float = 1, stop_condition: Callable[[], bool] | None = None, frozen_frame: bool | None = None, rate_func: Callable[[float], float] = linear, **kwargs, ): if stop_condition and frozen_frame: raise ValueError("A static Wait animation cannot have a stop condition.") self.duration: float = run_time self.stop_condition = stop_condition self.is_static_wait: bool = frozen_frame super().__init__(None, run_time=run_time, rate_func=rate_func, **kwargs) # quick fix to work in opengl setting: self.mobject.shader_wrapper_list = [] def begin(self) -> None: pass def finish(self) -> None: pass def clean_up_from_scene(self, scene: Scene) -> None: pass def update_mobjects(self, dt: float) -> None: pass def interpolate(self, alpha: float) -> None: pass class Add(Animation): """Add Mobjects to a scene, without animating them in any other way. This is similar to the :meth:`.Scene.add` method, but :class:`Add` is an animation which can be grouped into other animations. Parameters ---------- mobjects One :class:`~.Mobject` or more to add to a scene. run_time The duration of the animation after adding the ``mobjects``. Defaults to 0, which means this is an instant animation without extra wait time after adding them. **kwargs Additional arguments to pass to the parent :class:`Animation` class. Examples -------- .. manim:: DefaultAddScene class DefaultAddScene(Scene): def construct(self): text_1 = Text("I was added with Add!") text_2 = Text("Me too!") text_3 = Text("And me!") texts = VGroup(text_1, text_2, text_3).arrange(DOWN) rect = SurroundingRectangle(texts, buff=0.5) self.play( Create(rect, run_time=3.0), Succession( Wait(1.0), # You can Add a Mobject in the middle of an animation... Add(text_1), Wait(1.0), # ...or multiple Mobjects at once! Add(text_2, text_3), ), ) self.wait() .. manim:: AddWithRunTimeScene class AddWithRunTimeScene(Scene): def construct(self): # A 5x5 grid of circles circles = VGroup( *[Circle(radius=0.5) for _ in range(25)] ).arrange_in_grid(5, 5) self.play( Succession( # Add a run_time of 0.2 to wait for 0.2 seconds after # adding the circle, instead of using Wait(0.2) after Add! *[Add(circle, run_time=0.2) for circle in circles], rate_func=smooth, ) ) self.wait() """ def __init__( self, *mobjects: Mobject, run_time: float = 0.0, **kwargs: Any ) -> None: mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects) super().__init__(mobject, run_time=run_time, introducer=True, **kwargs) def begin(self) -> None: pass def finish(self) -> None: pass def clean_up_from_scene(self, scene: Scene) -> None: pass def update_mobjects(self, dt: float) -> None: pass def interpolate(self, alpha: float) -> None: pass def override_animation( animation_class: type[Animation], ) -> Callable[[Callable], Callable]: """Decorator used to mark methods as overrides for specific :class:`~.Animation` types. Should only be used to decorate methods of classes derived from :class:`~.Mobject`. ``Animation`` overrides get inherited to subclasses of the ``Mobject`` who defined them. They don't override subclasses of the ``Animation`` they override. See Also -------- :meth:`~.Mobject.add_animation_override` Parameters ---------- animation_class The animation to be overridden. Returns ------- Callable[[Callable], Callable] The actual decorator. This marks the method as overriding an animation. Examples -------- .. manim:: OverrideAnimationExample class MySquare(Square): @override_animation(FadeIn) def _fade_in_override(self, **kwargs): return Create(self, **kwargs) class OverrideAnimationExample(Scene): def construct(self): self.play(FadeIn(MySquare())) """ def decorator(func): func._override_animation = animation_class return func return decorator ================================================ FILE: manim/animation/changing.py ================================================ """Animation of a mobject boundary and tracing of points.""" from __future__ import annotations __all__ = ["AnimatedBoundary", "TracedPath"] from collections.abc import Callable, Sequence from typing import Any, Self from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.color import ( BLUE_B, BLUE_D, BLUE_E, GREY_BROWN, WHITE, ParsableManimColor, ) from manim.utils.rate_functions import RateFunction, smooth class AnimatedBoundary(VGroup): """Boundary of a :class:`.VMobject` with animated color change. Examples -------- .. manim:: AnimatedBoundaryExample class AnimatedBoundaryExample(Scene): def construct(self): text = Text("So shiny!") boundary = AnimatedBoundary(text, colors=[RED, GREEN, BLUE], cycle_rate=3) self.add(text, boundary) self.wait(2) """ def __init__( self, vmobject: VMobject, colors: Sequence[ParsableManimColor] = [BLUE_D, BLUE_B, BLUE_E, GREY_BROWN], max_stroke_width: float = 3, cycle_rate: float = 0.5, back_and_forth: bool = True, draw_rate_func: RateFunction = smooth, fade_rate_func: RateFunction = smooth, **kwargs: Any, ): super().__init__(**kwargs) self.colors = colors self.max_stroke_width = max_stroke_width self.cycle_rate = cycle_rate self.back_and_forth = back_and_forth self.draw_rate_func = draw_rate_func self.fade_rate_func = fade_rate_func self.vmobject = vmobject self.boundary_copies = [ vmobject.copy().set_style(stroke_width=0, fill_opacity=0) for x in range(2) ] self.add(*self.boundary_copies) self.total_time = 0.0 self.add_updater(lambda m, dt: self.update_boundary_copies(dt)) def update_boundary_copies(self, dt: float) -> None: # Not actual time, but something which passes at # an altered rate to make the implementation below # cleaner time = self.total_time * self.cycle_rate growing, fading = self.boundary_copies colors = self.colors msw = self.max_stroke_width vmobject = self.vmobject index = int(time % len(colors)) alpha = time % 1 draw_alpha = self.draw_rate_func(alpha) fade_alpha = self.fade_rate_func(alpha) if self.back_and_forth and int(time) % 2 == 1: bounds = (1.0 - draw_alpha, 1.0) else: bounds = (0.0, draw_alpha) self.full_family_become_partial(growing, vmobject, *bounds) growing.set_stroke(colors[index], width=msw) if time >= 1: self.full_family_become_partial(fading, vmobject, 0, 1) fading.set_stroke(color=colors[index - 1], width=(1 - fade_alpha) * msw) self.total_time += dt def full_family_become_partial( self, mob1: VMobject, mob2: VMobject, a: float, b: float ) -> Self: family1 = mob1.family_members_with_points() family2 = mob2.family_members_with_points() for sm1, sm2 in zip(family1, family2, strict=False): sm1.pointwise_become_partial(sm2, a, b) return self class TracedPath(VMobject, metaclass=ConvertToOpenGL): """Traces the path of a point returned by a function call. Parameters ---------- traced_point_func The function to be traced. stroke_width The width of the trace. stroke_color The color of the trace. dissipating_time The time taken for the path to dissipate. Default set to ``None`` which disables dissipation. Examples -------- .. manim:: TracedPathExample class TracedPathExample(Scene): def construct(self): circ = Circle(color=RED).shift(4*LEFT) dot = Dot(color=RED).move_to(circ.get_start()) rolling_circle = VGroup(circ, dot) trace = TracedPath(circ.get_start) rolling_circle.add_updater(lambda m: m.rotate(-0.3)) self.add(trace, rolling_circle) self.play(rolling_circle.animate.shift(8*RIGHT), run_time=4, rate_func=linear) .. manim:: DissipatingPathExample class DissipatingPathExample(Scene): def construct(self): a = Dot(RIGHT * 2) b = TracedPath(a.get_center, dissipating_time=0.5, stroke_opacity=[0, 1]) self.add(a, b) self.play(a.animate(path_arc=PI / 4).shift(LEFT * 2)) self.play(a.animate(path_arc=-PI / 4).shift(LEFT * 2)) self.wait() """ def __init__( self, traced_point_func: Callable, stroke_width: float = 2, stroke_color: ParsableManimColor | None = WHITE, dissipating_time: float | None = None, **kwargs: Any, ) -> None: super().__init__(stroke_color=stroke_color, stroke_width=stroke_width, **kwargs) self.traced_point_func = traced_point_func self.dissipating_time = dissipating_time self.time = 1.0 if self.dissipating_time else None self.add_updater(self.update_path) def update_path(self, mob: Mobject, dt: float) -> None: new_point = self.traced_point_func() if not self.has_points(): self.start_new_path(new_point) self.add_line_to(new_point) if self.dissipating_time: assert self.time is not None self.time += dt if self.time - 1 > self.dissipating_time: nppcc = self.n_points_per_curve self.set_points(self.points[nppcc:]) ================================================ FILE: manim/animation/composition.py ================================================ """Tools for displaying multiple animations at once.""" from __future__ import annotations from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING, Any import numpy as np from manim._config import config from manim.animation.animation import Animation, prepare_animation from manim.constants import RendererType from manim.mobject.mobject import Group, Mobject from manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject from manim.scene.scene import Scene from manim.utils.iterables import remove_list_redundancies from manim.utils.parameter_parsing import flatten_iterable_parameters from manim.utils.rate_functions import linear if TYPE_CHECKING: from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup from manim.mobject.types.vectorized_mobject import VGroup __all__ = ["AnimationGroup", "Succession", "LaggedStart", "LaggedStartMap"] DEFAULT_LAGGED_START_LAG_RATIO: float = 0.05 class AnimationGroup(Animation): """Plays a group or series of :class:`~.Animation`. Parameters ---------- animations Sequence of :class:`~.Animation` objects to be played. group A group of multiple :class:`~.Mobject`. run_time The duration of the animation in seconds. rate_func The function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`) . lag_ratio Defines the delay after which the animation is applied to submobjects. A lag_ratio of ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played. Defaults to 0.0, meaning that all animations will be played together. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time. """ def __init__( self, *animations: Animation | Iterable[Animation], group: Group | VGroup | OpenGLGroup | OpenGLVGroup | None = None, run_time: float | None = None, rate_func: Callable[[float], float] = linear, lag_ratio: float = 0, **kwargs: Any, ): arg_anim = flatten_iterable_parameters(animations) self.animations = [prepare_animation(anim) for anim in arg_anim] self.rate_func = rate_func if group is None: mobjects = remove_list_redundancies( [anim.mobject for anim in self.animations if not anim.is_introducer()], ) if config["renderer"] == RendererType.OPENGL: self.group: Group | VGroup | OpenGLGroup | OpenGLVGroup = OpenGLGroup( *mobjects ) else: self.group = Group(*mobjects) else: self.group = group super().__init__( self.group, rate_func=self.rate_func, lag_ratio=lag_ratio, **kwargs ) self.run_time: float = self.init_run_time(run_time) def get_all_mobjects(self) -> Sequence[Mobject | OpenGLMobject]: return list(self.group) def begin(self) -> None: if not self.animations: raise ValueError( f"Trying to play {self} without animations, this is not supported. " "Please add at least one subanimation." ) self.anim_group_time = 0.0 if self.suspend_mobject_updating: self.group.suspend_updating() for anim in self.animations: anim.begin() def _setup_scene(self, scene: Scene) -> None: for anim in self.animations: anim._setup_scene(scene) def finish(self) -> None: for anim in self.animations: anim.finish() self.anims_begun[:] = True self.anims_finished[:] = True if self.suspend_mobject_updating: self.group.resume_updating() def clean_up_from_scene(self, scene: Scene) -> None: self._on_finish(scene) for anim in self.animations: if self.remover: anim.remover = self.remover anim.clean_up_from_scene(scene) def update_mobjects(self, dt: float) -> None: for anim in self.anims_with_timings["anim"][ self.anims_begun & ~self.anims_finished ]: anim.update_mobjects(dt) def init_run_time(self, run_time: float | None) -> float: """Calculates the run time of the animation, if different from ``run_time``. Parameters ---------- run_time The duration of the animation in seconds. Returns ------- run_time The duration of the animation in seconds. """ self.build_animations_with_timings() # Note: if lag_ratio < 1, then not necessarily the final animation's # end time will be the max end time! Therefore we must calculate the # maximum over all the end times, and not just take the last one. # Example: if you want to play 2 animations of 10s and 1s with a # lag_ratio of 0.1, the 1st one will end at t=10 and the 2nd one will # end at t=2, so the AnimationGroup will end at t=10. self.max_end_time = max(self.anims_with_timings["end"], default=0) return self.max_end_time if run_time is None else run_time def build_animations_with_timings(self) -> None: """Creates a list of triplets of the form (anim, start_time, end_time).""" run_times = np.array([anim.run_time for anim in self.animations]) num_animations = run_times.shape[0] dtype = [("anim", "O"), ("start", "f8"), ("end", "f8")] self.anims_with_timings: np.ndarray = np.zeros(num_animations, dtype=dtype) self.anims_begun: np.ndarray = np.zeros(num_animations, dtype=bool) self.anims_finished: np.ndarray = np.zeros(num_animations, dtype=bool) if num_animations == 0: return lags = run_times[:-1] * self.lag_ratio self.anims_with_timings["anim"] = self.animations self.anims_with_timings["start"][1:] = np.add.accumulate(lags) self.anims_with_timings["end"] = self.anims_with_timings["start"] + run_times def interpolate(self, alpha: float) -> None: # Note, if the run_time of AnimationGroup has been # set to something other than its default, these # times might not correspond to actual times, # e.g. of the surrounding scene. Instead they'd # be a rescaled version. But that's okay! anim_group_time = self.rate_func(alpha) * self.max_end_time time_goes_back = anim_group_time < self.anim_group_time # Only update ongoing animations awt = self.anims_with_timings new_begun = anim_group_time >= awt["start"] new_finished = anim_group_time > awt["end"] to_update = awt[ (self.anims_begun | new_begun) & (~self.anims_finished | ~new_finished) ] run_times = to_update["end"] - to_update["start"] with_zero_run_time = run_times == 0 run_times[with_zero_run_time] = 1 sub_alphas = (anim_group_time - to_update["start"]) / run_times if time_goes_back: sub_alphas[(sub_alphas < 0) | with_zero_run_time] = 0 else: sub_alphas[(sub_alphas > 1) | with_zero_run_time] = 1 for anim_to_update, sub_alpha in zip( to_update["anim"], sub_alphas, strict=True ): anim_to_update.interpolate(sub_alpha) self.anim_group_time = anim_group_time self.anims_begun = new_begun self.anims_finished = new_finished class Succession(AnimationGroup): """Plays a series of animations in succession. Parameters ---------- animations Sequence of :class:`~.Animation` objects to be played. lag_ratio Defines the delay after which the animation is applied to submobjects. A lag_ratio of ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played. Defaults to 1.0, meaning that the next animation will begin when 100% of the current animation has played. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time. Examples -------- .. manim:: SuccessionExample class SuccessionExample(Scene): def construct(self): dot1 = Dot(point=LEFT * 2 + UP * 2, radius=0.16, color=BLUE) dot2 = Dot(point=LEFT * 2 + DOWN * 2, radius=0.16, color=MAROON) dot3 = Dot(point=RIGHT * 2 + DOWN * 2, radius=0.16, color=GREEN) dot4 = Dot(point=RIGHT * 2 + UP * 2, radius=0.16, color=YELLOW) self.add(dot1, dot2, dot3, dot4) self.play(Succession( dot1.animate.move_to(dot2), dot2.animate.move_to(dot3), dot3.animate.move_to(dot4), dot4.animate.move_to(dot1) )) """ def __init__(self, *animations: Animation, lag_ratio: float = 1, **kwargs: Any): super().__init__(*animations, lag_ratio=lag_ratio, **kwargs) def begin(self) -> None: if not self.animations: raise ValueError( f"Trying to play {self} without animations, this is not supported. " "Please add at least one subanimation." ) self.update_active_animation(0) def finish(self) -> None: while self.active_animation is not None: self.next_animation() def update_mobjects(self, dt: float) -> None: if self.active_animation: self.active_animation.update_mobjects(dt) def _setup_scene(self, scene: Scene | None) -> None: if scene is None: return if self.is_introducer(): for anim in self.animations: if not anim.is_introducer() and anim.mobject is not None: scene.add(anim.mobject) self.scene = scene def update_active_animation(self, index: int) -> None: self.active_index = index if index >= len(self.animations): self.active_animation: Animation | None = None self.active_start_time: float | None = None self.active_end_time: float | None = None else: self.active_animation = self.animations[index] self.active_animation._setup_scene(self.scene) self.active_animation.begin() self.active_start_time = self.anims_with_timings[index]["start"] self.active_end_time = self.anims_with_timings[index]["end"] def next_animation(self) -> None: """Proceeds to the next animation. This method is called right when the active animation finishes. """ if self.active_animation is not None: self.active_animation.finish() self.update_active_animation(self.active_index + 1) def interpolate(self, alpha: float) -> None: current_time = self.rate_func(alpha) * self.max_end_time while self.active_end_time is not None and current_time >= self.active_end_time: self.next_animation() if self.active_animation is not None and self.active_start_time is not None: elapsed = current_time - self.active_start_time active_run_time = self.active_animation.run_time subalpha = elapsed / active_run_time if active_run_time != 0.0 else 1.0 self.active_animation.interpolate(subalpha) class LaggedStart(AnimationGroup): """Adjusts the timing of a series of :class:`~.Animation` according to ``lag_ratio``. Parameters ---------- animations Sequence of :class:`~.Animation` objects to be played. lag_ratio Defines the delay after which the animation is applied to submobjects. A lag_ratio of ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played. Defaults to 0.05, meaning that the next animation will begin when 5% of the current animation has played. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time. Examples -------- .. manim:: LaggedStartExample class LaggedStartExample(Scene): def construct(self): title = Text("lag_ratio = 0.25").to_edge(UP) dot1 = Dot(point=LEFT * 2 + UP, radius=0.16) dot2 = Dot(point=LEFT * 2, radius=0.16) dot3 = Dot(point=LEFT * 2 + DOWN, radius=0.16) line_25 = DashedLine( start=LEFT + UP * 2, end=LEFT + DOWN * 2, color=RED ) label = Text("25%", font_size=24).next_to(line_25, UP) self.add(title, dot1, dot2, dot3, line_25, label) self.play(LaggedStart( dot1.animate.shift(RIGHT * 4), dot2.animate.shift(RIGHT * 4), dot3.animate.shift(RIGHT * 4), lag_ratio=0.25, run_time=4 )) """ def __init__( self, *animations: Animation, lag_ratio: float = DEFAULT_LAGGED_START_LAG_RATIO, **kwargs: Any, ): super().__init__(*animations, lag_ratio=lag_ratio, **kwargs) class LaggedStartMap(LaggedStart): """Plays a series of :class:`~.Animation` while mapping a function to submobjects. Parameters ---------- animation_class :class:`~.Animation` to apply to mobject. mobject :class:`~.Mobject` whose submobjects the animation, and optionally the function, are to be applied. arg_creator Function which will be applied to :class:`~.Mobject`. run_time The duration of the animation in seconds. lag_ratio Defines the delay after which the animation is applied to submobjects. A lag_ratio of ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played. Defaults to 0.05, meaning that the next animation will begin when 5% of the current animation has played. This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time. kwargs Further keyword arguments that are passed to `animation_class`. Examples -------- .. manim:: LaggedStartMapExample class LaggedStartMapExample(Scene): def construct(self): title = Tex("LaggedStartMap").to_edge(UP, buff=LARGE_BUFF) dots = VGroup( *[Dot(radius=0.16) for _ in range(35)] ).arrange_in_grid(rows=5, cols=7, buff=MED_LARGE_BUFF) self.add(dots, title) # Animate yellow ripple effect for mob in dots, title: self.play(LaggedStartMap( ApplyMethod, mob, lambda m : (m.set_color, YELLOW), lag_ratio = 0.1, rate_func = there_and_back, run_time = 2 )) """ def __init__( self, animation_class: type[Animation], mobject: Mobject, arg_creator: Callable[[Mobject], Iterable[Any]] | None = None, run_time: float = 2, lag_ratio: float = DEFAULT_LAGGED_START_LAG_RATIO, **kwargs: Any, ): if arg_creator is None: def identity(mob: Mobject) -> Mobject: return mob arg_creator = identity args_list = [arg_creator(submob) for submob in mobject] anim_kwargs = dict(kwargs) if "lag_ratio" in anim_kwargs: anim_kwargs.pop("lag_ratio") animations = [animation_class(*args, **anim_kwargs) for args in args_list] super().__init__(*animations, run_time=run_time, lag_ratio=lag_ratio) ================================================ FILE: manim/animation/creation.py ================================================ r"""Animate the display or removal of a mobject from a scene. .. manim:: CreationModule :hide_source: from manim import ManimBanner class CreationModule(Scene): def construct(self): s1 = Square() s2 = Square() s3 = Square() s4 = Square() VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.9).shift(UP) s5 = Square() s6 = Square() s7 = Square() VGroup(s5, s6, s7).set_x(0).arrange(buff=2.6).shift(2 * DOWN) t1 = Text("Write", font_size=24).next_to(s1, UP) t2 = Text("AddTextLetterByLetter", font_size=24).next_to(s2, UP) t3 = Text("Create", font_size=24).next_to(s3, UP) t4 = Text("Uncreate", font_size=24).next_to(s4, UP) t5 = Text("DrawBorderThenFill", font_size=24).next_to(s5, UP) t6 = Text("ShowIncreasingSubsets", font_size=22).next_to(s6, UP) t7 = Text("ShowSubmobjectsOneByOne", font_size=22).next_to(s7, UP) self.add(s1, s2, s3, s4, s5, s6, s7, t1, t2, t3, t4, t5, t6, t7) texts = [Text("manim", font_size=29), Text("manim", font_size=29)] texts[0].move_to(s1.get_center()) texts[1].move_to(s2.get_center()) self.add(*texts) objs = [ManimBanner().scale(0.25) for _ in range(5)] objs[0].move_to(s3.get_center()) objs[1].move_to(s4.get_center()) objs[2].move_to(s5.get_center()) objs[3].move_to(s6.get_center()) objs[4].move_to(s7.get_center()) self.add(*objs) self.play( # text creation Write(texts[0]), AddTextLetterByLetter(texts[1]), # mobject creation Create(objs[0]), Uncreate(objs[1]), DrawBorderThenFill(objs[2]), ShowIncreasingSubsets(objs[3]), ShowSubmobjectsOneByOne(objs[4]), run_time=3, ) self.wait() """ from __future__ import annotations __all__ = [ "Create", "Uncreate", "DrawBorderThenFill", "Write", "Unwrite", "ShowPartial", "ShowIncreasingSubsets", "SpiralIn", "AddTextLetterByLetter", "RemoveTextLetterByLetter", "ShowSubmobjectsOneByOne", "AddTextWordByWord", "TypeWithCursor", "UntypeWithCursor", ] import itertools as it from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING import numpy as np if TYPE_CHECKING: from manim.mobject.text.text_mobject import Text from manim.scene.scene import Scene from manim.constants import RIGHT, TAU from manim.mobject.opengl.opengl_surface import OpenGLSurface from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.utils.color import ManimColor from .. import config from ..animation.animation import Animation from ..animation.composition import Succession from ..mobject.mobject import Group, Mobject from ..mobject.types.vectorized_mobject import VMobject from ..utils.bezier import integer_interpolate from ..utils.rate_functions import double_smooth, linear class ShowPartial(Animation): """Abstract class for Animations that show the VMobject partially. Raises ------ :class:`TypeError` If ``mobject`` is not an instance of :class:`~.VMobject`. See Also -------- :class:`Create`, :class:`~.ShowPassingFlash` """ def __init__( self, mobject: VMobject | OpenGLVMobject | OpenGLSurface | None, **kwargs, ): pointwise = getattr(mobject, "pointwise_become_partial", None) if not callable(pointwise): raise TypeError(f"{self.__class__.__name__} only works for VMobjects.") super().__init__(mobject, **kwargs) def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, alpha: float, ) -> None: submobject.pointwise_become_partial( starting_submobject, *self._get_bounds(alpha) ) def _get_bounds(self, alpha: float) -> tuple[float, float]: raise NotImplementedError("Please use Create or ShowPassingFlash") class Create(ShowPartial): """Incrementally show a VMobject. Parameters ---------- mobject The VMobject to animate. Raises ------ :class:`TypeError` If ``mobject`` is not an instance of :class:`~.VMobject`. Examples -------- .. manim:: CreateScene class CreateScene(Scene): def construct(self): self.play(Create(Square())) See Also -------- :class:`~.ShowPassingFlash` """ def __init__( self, mobject: VMobject | OpenGLVMobject | OpenGLSurface, lag_ratio: float = 1.0, introducer: bool = True, **kwargs, ) -> None: super().__init__(mobject, lag_ratio=lag_ratio, introducer=introducer, **kwargs) def _get_bounds(self, alpha: float) -> tuple[float, float]: return (0, alpha) class Uncreate(Create): """Like :class:`Create` but in reverse. Examples -------- .. manim:: ShowUncreate class ShowUncreate(Scene): def construct(self): self.play(Uncreate(Square())) See Also -------- :class:`Create` """ def __init__( self, mobject: VMobject | OpenGLVMobject, reverse_rate_function: bool = True, remover: bool = True, **kwargs, ) -> None: super().__init__( mobject, reverse_rate_function=reverse_rate_function, introducer=False, remover=remover, **kwargs, ) class DrawBorderThenFill(Animation): """Draw the border first and then show the fill. Examples -------- .. manim:: ShowDrawBorderThenFill class ShowDrawBorderThenFill(Scene): def construct(self): self.play(DrawBorderThenFill(Square(fill_opacity=1, fill_color=ORANGE))) """ def __init__( self, vmobject: VMobject | OpenGLVMobject, run_time: float = 2, rate_func: Callable[[float], float] = double_smooth, stroke_width: float = 2, stroke_color: str = None, introducer: bool = True, **kwargs, ) -> None: self._typecheck_input(vmobject) super().__init__( vmobject, run_time=run_time, introducer=introducer, rate_func=rate_func, **kwargs, ) self.stroke_width = stroke_width self.stroke_color = stroke_color self.outline = self.get_outline() def _typecheck_input(self, vmobject: VMobject | OpenGLVMobject) -> None: if not isinstance(vmobject, (VMobject, OpenGLVMobject)): raise TypeError( f"{self.__class__.__name__} only works for vectorized Mobjects" ) def begin(self) -> None: self.outline = self.get_outline() super().begin() def get_outline(self) -> Mobject: outline = self.mobject.copy() outline.set_fill(opacity=0) for sm in outline.family_members_with_points(): sm.set_stroke(color=self.get_stroke_color(sm), width=self.stroke_width) return outline def get_stroke_color(self, vmobject: VMobject | OpenGLVMobject) -> ManimColor: if self.stroke_color: return self.stroke_color elif vmobject.get_stroke_width() > 0: return vmobject.get_stroke_color() return vmobject.get_color() def get_all_mobjects(self) -> Sequence[Mobject]: return [*super().get_all_mobjects(), self.outline] def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, outline, alpha: float, ) -> None: # Fixme: not matching the parent class? What is outline doing here? index: int subalpha: float index, subalpha = integer_interpolate(0, 2, alpha) if index == 0: submobject.pointwise_become_partial(outline, 0, subalpha) submobject.match_style(outline) else: submobject.interpolate(outline, starting_submobject, subalpha) class Write(DrawBorderThenFill): """Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`. Examples -------- .. manim:: ShowWrite class ShowWrite(Scene): def construct(self): self.play(Write(Text("Hello", font_size=144))) .. manim:: ShowWriteReversed class ShowWriteReversed(Scene): def construct(self): self.play(Write(Text("Hello", font_size=144), reverse=True, remover=False)) Tests ----- Check that creating empty :class:`.Write` animations works:: >>> from manim import Write, Text >>> Write(Text('')) Write(Text('')) """ def __init__( self, vmobject: VMobject | OpenGLVMobject, rate_func: Callable[[float], float] = linear, reverse: bool = False, **kwargs, ) -> None: run_time: float | None = kwargs.pop("run_time", None) lag_ratio: float | None = kwargs.pop("lag_ratio", None) run_time, lag_ratio = self._set_default_config_from_length( vmobject, run_time, lag_ratio, ) self.reverse = reverse if "remover" not in kwargs: kwargs["remover"] = reverse super().__init__( vmobject, rate_func=rate_func, run_time=run_time, lag_ratio=lag_ratio, introducer=not reverse, **kwargs, ) def _set_default_config_from_length( self, vmobject: VMobject | OpenGLVMobject, run_time: float | None, lag_ratio: float | None, ) -> tuple[float, float]: length = len(vmobject.family_members_with_points()) if run_time is None: run_time = 1 if length < 15 else 2 if lag_ratio is None: lag_ratio = min(4.0 / max(1.0, length), 0.2) return run_time, lag_ratio def reverse_submobjects(self) -> None: self.mobject.invert(recursive=True) def begin(self) -> None: if self.reverse: self.reverse_submobjects() super().begin() def finish(self) -> None: super().finish() if self.reverse: self.reverse_submobjects() class Unwrite(Write): """Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`. Parameters ---------- reverse Set True to have the animation start erasing from the last submobject first. Examples -------- .. manim :: UnwriteReverseTrue class UnwriteReverseTrue(Scene): def construct(self): text = Tex("Alice and Bob").scale(3) self.add(text) self.play(Unwrite(text)) .. manim:: UnwriteReverseFalse class UnwriteReverseFalse(Scene): def construct(self): text = Tex("Alice and Bob").scale(3) self.add(text) self.play(Unwrite(text, reverse=False)) """ def __init__( self, vmobject: VMobject, rate_func: Callable[[float], float] = linear, reverse: bool = True, **kwargs, ) -> None: run_time: float | None = kwargs.pop("run_time", None) lag_ratio: float | None = kwargs.pop("lag_ratio", None) run_time, lag_ratio = self._set_default_config_from_length( vmobject, run_time, lag_ratio, ) super().__init__( vmobject, run_time=run_time, lag_ratio=lag_ratio, reverse_rate_function=True, reverse=reverse, **kwargs, ) class SpiralIn(Animation): r"""Create the Mobject with sub-Mobjects flying in on spiral trajectories. Parameters ---------- shapes The Mobject on which to be operated. scale_factor The factor used for scaling the effect. fade_in_fraction Fractional duration of initial fade-in of sub-Mobjects as they fly inward. Examples -------- .. manim :: SpiralInExample class SpiralInExample(Scene): def construct(self): pi = MathTex(r"\pi").scale(7) pi.shift(2.25 * LEFT + 1.5 * UP) circle = Circle(color=GREEN_C, fill_opacity=1).shift(LEFT) square = Square(color=BLUE_D, fill_opacity=1).shift(UP) shapes = VGroup(pi, circle, square) self.play(SpiralIn(shapes)) """ def __init__( self, shapes: Mobject, scale_factor: float = 8, fade_in_fraction=0.3, **kwargs, ) -> None: self.shapes = shapes.copy() self.scale_factor = scale_factor self.shape_center = shapes.get_center() self.fade_in_fraction = fade_in_fraction for shape in shapes: shape.final_position = shape.get_center() shape.initial_position = ( shape.final_position + (shape.final_position - self.shape_center) * self.scale_factor ) shape.move_to(shape.initial_position) shape.save_state() super().__init__(shapes, introducer=True, **kwargs) def interpolate_mobject(self, alpha: float) -> None: alpha = self.rate_func(alpha) for original_shape, shape in zip(self.shapes, self.mobject, strict=True): shape.restore() fill_opacity = original_shape.get_fill_opacity() stroke_opacity = original_shape.get_stroke_opacity() new_fill_opacity = min( fill_opacity, alpha * fill_opacity / self.fade_in_fraction ) new_stroke_opacity = min( stroke_opacity, alpha * stroke_opacity / self.fade_in_fraction ) shape.shift((shape.final_position - shape.initial_position) * alpha) shape.rotate(TAU * alpha, about_point=self.shape_center) shape.rotate(-TAU * alpha, about_point=shape.get_center_of_mass()) shape.set_fill(opacity=new_fill_opacity) shape.set_stroke(opacity=new_stroke_opacity) class ShowIncreasingSubsets(Animation): """Show one submobject at a time, leaving all previous ones displayed on screen. Examples -------- .. manim:: ShowIncreasingSubsetsScene class ShowIncreasingSubsetsScene(Scene): def construct(self): p = VGroup(Dot(), Square(), Triangle()) self.add(p) self.play(ShowIncreasingSubsets(p)) self.wait() """ def __init__( self, group: Mobject, suspend_mobject_updating: bool = False, int_func: Callable[[np.ndarray], np.ndarray] = np.floor, reverse_rate_function=False, **kwargs, ) -> None: self.all_submobs = list(group.submobjects) self.int_func = int_func for mobj in self.all_submobs: mobj.set_opacity(0) super().__init__( group, suspend_mobject_updating=suspend_mobject_updating, reverse_rate_function=reverse_rate_function, **kwargs, ) def interpolate_mobject(self, alpha: float) -> None: n_submobs = len(self.all_submobs) value = ( 1 - self.rate_func(alpha) if self.reverse_rate_function else self.rate_func(alpha) ) index = int(self.int_func(value * n_submobs)) self.update_submobject_list(index) def update_submobject_list(self, index: int) -> None: for mobj in self.all_submobs[:index]: mobj.set_opacity(1) for mobj in self.all_submobs[index:]: mobj.set_opacity(0) class AddTextLetterByLetter(ShowIncreasingSubsets): """Show a :class:`~.Text` letter by letter on the scene. Parameters ---------- time_per_char Frequency of appearance of the letters. .. tip:: This is currently only possible for class:`~.Text` and not for class:`~.MathTex` """ def __init__( self, text: Text, suspend_mobject_updating: bool = False, int_func: Callable[[np.ndarray], np.ndarray] = np.ceil, rate_func: Callable[[float], float] = linear, time_per_char: float = 0.1, run_time: float | None = None, reverse_rate_function=False, introducer=True, **kwargs, ) -> None: self.time_per_char = time_per_char # Check for empty text using family_members_with_points() if not text.family_members_with_points(): raise ValueError( f"The text mobject {text} does not seem to contain any characters." ) if run_time is None: # minimum time per character is 1/frame_rate, otherwise # the animation does not finish. run_time = np.max((1 / config.frame_rate, self.time_per_char)) * len(text) super().__init__( text, suspend_mobject_updating=suspend_mobject_updating, int_func=int_func, rate_func=rate_func, run_time=run_time, reverse_rate_function=reverse_rate_function, introducer=introducer, **kwargs, ) class RemoveTextLetterByLetter(AddTextLetterByLetter): """Remove a :class:`~.Text` letter by letter from the scene. Parameters ---------- time_per_char Frequency of appearance of the letters. .. tip:: This is currently only possible for class:`~.Text` and not for class:`~.MathTex` """ def __init__( self, text: Text, suspend_mobject_updating: bool = False, int_func: Callable[[np.ndarray], np.ndarray] = np.ceil, rate_func: Callable[[float], float] = linear, time_per_char: float = 0.1, run_time: float | None = None, reverse_rate_function=True, introducer=False, remover=True, **kwargs, ) -> None: super().__init__( text, suspend_mobject_updating=suspend_mobject_updating, int_func=int_func, rate_func=rate_func, time_per_char=time_per_char, run_time=run_time, reverse_rate_function=reverse_rate_function, introducer=introducer, remover=remover, **kwargs, ) class ShowSubmobjectsOneByOne(ShowIncreasingSubsets): """Show one submobject at a time, removing all previously displayed ones from screen.""" def __init__( self, group: Iterable[Mobject], int_func: Callable[[np.ndarray], np.ndarray] = np.ceil, **kwargs, ) -> None: new_group = Group(*group) super().__init__(new_group, int_func=int_func, **kwargs) def update_submobject_list(self, index: int) -> None: current_submobjects = self.all_submobs[:index] for mobj in current_submobjects[:-1]: mobj.set_opacity(0) if len(current_submobjects) > 0: current_submobjects[-1].set_opacity(1) # TODO, this is broken... class AddTextWordByWord(Succession): """Show a :class:`~.Text` word by word on the scene. Note: currently broken.""" def __init__( self, text_mobject: Text, run_time: float = None, time_per_char: float = 0.06, **kwargs, ) -> None: self.time_per_char = time_per_char tpc = self.time_per_char anims = it.chain( *( [ ShowIncreasingSubsets(word, run_time=tpc * len(word)), Animation(word, run_time=0.005 * len(word) ** 1.5), ] for word in text_mobject ) ) super().__init__(*anims, **kwargs) class TypeWithCursor(AddTextLetterByLetter): """Similar to :class:`~.AddTextLetterByLetter` , but with an additional cursor mobject at the end. Parameters ---------- time_per_char Frequency of appearance of the letters. cursor :class:`~.Mobject` shown after the last added letter. buff Controls how far away the cursor is to the right of the last added letter. keep_cursor_y If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter. leave_cursor_on Whether to show the cursor after the animation. .. tip:: This is currently only possible for class:`~.Text` and not for class:`~.MathTex`. Examples -------- .. manim:: InsertingTextExample :ref_classes: Blink class InsertingTextExample(Scene): def construct(self): text = Text("Inserting", color=PURPLE).scale(1.5).to_edge(LEFT) cursor = Rectangle( color = GREY_A, fill_color = GREY_A, fill_opacity = 1.0, height = 1.1, width = 0.5, ).move_to(text[0]) # Position the cursor self.play(TypeWithCursor(text, cursor)) self.play(Blink(cursor, blinks=2)) """ def __init__( self, text: Text, cursor: Mobject, buff: float = 0.1, keep_cursor_y: bool = True, leave_cursor_on: bool = True, time_per_char: float = 0.1, reverse_rate_function=False, introducer=True, **kwargs, ) -> None: self.cursor = cursor self.buff = buff self.keep_cursor_y = keep_cursor_y self.leave_cursor_on = leave_cursor_on super().__init__( text, time_per_char=time_per_char, reverse_rate_function=reverse_rate_function, introducer=introducer, **kwargs, ) def begin(self) -> None: self.y_cursor = self.cursor.get_y() self.cursor.initial_position = self.mobject.get_center() if self.keep_cursor_y: self.cursor.set_y(self.y_cursor) self.cursor.set_opacity(0) self.mobject.add(self.cursor) super().begin() def finish(self) -> None: if self.leave_cursor_on: self.cursor.set_opacity(1) else: self.cursor.set_opacity(0) self.mobject.remove(self.cursor) super().finish() def clean_up_from_scene(self, scene: Scene) -> None: if not self.leave_cursor_on: scene.remove(self.cursor) super().clean_up_from_scene(scene) def update_submobject_list(self, index: int) -> None: for mobj in self.all_submobs[:index]: mobj.set_opacity(1) for mobj in self.all_submobs[index:]: mobj.set_opacity(0) if index != 0: self.cursor.next_to( self.all_submobs[index - 1], RIGHT, buff=self.buff ).set_y(self.cursor.initial_position[1]) else: self.cursor.move_to(self.all_submobs[0]).set_y( self.cursor.initial_position[1] ) if self.keep_cursor_y: self.cursor.set_y(self.y_cursor) self.cursor.set_opacity(1) class UntypeWithCursor(TypeWithCursor): """Similar to :class:`~.RemoveTextLetterByLetter` , but with an additional cursor mobject at the end. Parameters ---------- time_per_char Frequency of appearance of the letters. cursor :class:`~.Mobject` shown after the last added letter. buff Controls how far away the cursor is to the right of the last added letter. keep_cursor_y If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter. leave_cursor_on Whether to show the cursor after the animation. .. tip:: This is currently only possible for class:`~.Text` and not for class:`~.MathTex`. Examples -------- .. manim:: DeletingTextExample :ref_classes: Blink class DeletingTextExample(Scene): def construct(self): text = Text("Deleting", color=PURPLE).scale(1.5).to_edge(LEFT) cursor = Rectangle( color = GREY_A, fill_color = GREY_A, fill_opacity = 1.0, height = 1.1, width = 0.5, ).move_to(text[0]) # Position the cursor self.play(UntypeWithCursor(text, cursor)) self.play(Blink(cursor, blinks=2)) """ def __init__( self, text: Text, cursor: VMobject | None = None, time_per_char: float = 0.1, reverse_rate_function=True, introducer=False, remover=True, **kwargs, ) -> None: super().__init__( text, cursor=cursor, time_per_char=time_per_char, reverse_rate_function=reverse_rate_function, introducer=introducer, remover=remover, **kwargs, ) ================================================ FILE: manim/animation/fading.py ================================================ """Fading in and out of view. .. manim:: Fading class Fading(Scene): def construct(self): tex_in = Tex("Fade", "In").scale(3) tex_out = Tex("Fade", "Out").scale(3) self.play(FadeIn(tex_in, shift=DOWN, scale=0.66)) self.play(ReplacementTransform(tex_in, tex_out)) self.play(FadeOut(tex_out, shift=DOWN * 2, scale=1.5)) """ from __future__ import annotations __all__ = [ "FadeOut", "FadeIn", ] from typing import Any import numpy as np from manim.mobject.opengl.opengl_mobject import OpenGLMobject from ..animation.transform import Transform from ..constants import ORIGIN from ..mobject.mobject import Group, Mobject from ..scene.scene import Scene class _Fade(Transform): """Fade :class:`~.Mobject` s in or out. Parameters ---------- mobjects The mobjects to be faded. shift The vector by which the mobject shifts while being faded. target_position The position to/from which the mobject moves while being faded in. In case another mobject is given as target position, its center is used. scale The factor by which the mobject is scaled initially before being rescaling to its original size while being faded in. """ def __init__( self, *mobjects: Mobject, shift: np.ndarray | None = None, target_position: np.ndarray | Mobject | None = None, scale: float = 1, **kwargs: Any, ) -> None: if not mobjects: raise ValueError("At least one mobject must be passed.") mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects) self.point_target = False if shift is None: if target_position is not None: if isinstance(target_position, (Mobject, OpenGLMobject)): target_position = target_position.get_center() shift = target_position - mobject.get_center() self.point_target = True else: shift = ORIGIN self.shift_vector = shift self.scale_factor = scale super().__init__(mobject, **kwargs) def _create_faded_mobject(self, fadeIn: bool) -> Mobject: """Create a faded, shifted and scaled copy of the mobject. Parameters ---------- fadeIn Whether the faded mobject is used to fade in. Returns ------- Mobject The faded, shifted and scaled copy of the mobject. """ faded_mobject: Mobject = self.mobject.copy() # type: ignore[assignment] faded_mobject.fade(1) direction_modifier = -1 if fadeIn and not self.point_target else 1 faded_mobject.shift(self.shift_vector * direction_modifier) faded_mobject.scale(self.scale_factor) return faded_mobject class FadeIn(_Fade): r"""Fade in :class:`~.Mobject` s. Parameters ---------- mobjects The mobjects to be faded in. shift The vector by which the mobject shifts while being faded in. target_position The position from which the mobject starts while being faded in. In case another mobject is given as target position, its center is used. scale The factor by which the mobject is scaled initially before being rescaling to its original size while being faded in. Examples -------- .. manim :: FadeInExample class FadeInExample(Scene): def construct(self): dot = Dot(UP * 2 + LEFT) self.add(dot) tex = Tex( "FadeIn with ", "shift ", r" or target\_position", " and scale" ).scale(1) animations = [ FadeIn(tex[0]), FadeIn(tex[1], shift=DOWN), FadeIn(tex[2], target_position=dot), FadeIn(tex[3], scale=1.5), ] self.play(AnimationGroup(*animations, lag_ratio=0.5)) """ def __init__(self, *mobjects: Mobject, **kwargs: Any) -> None: super().__init__(*mobjects, introducer=True, **kwargs) def create_target(self) -> Mobject: return self.mobject # type: ignore[return-value] def create_starting_mobject(self) -> Mobject: return self._create_faded_mobject(fadeIn=True) class FadeOut(_Fade): r"""Fade out :class:`~.Mobject` s. Parameters ---------- mobjects The mobjects to be faded out. shift The vector by which the mobject shifts while being faded out. target_position The position to which the mobject moves while being faded out. In case another mobject is given as target position, its center is used. scale The factor by which the mobject is scaled while being faded out. Examples -------- .. manim :: FadeInExample class FadeInExample(Scene): def construct(self): dot = Dot(UP * 2 + LEFT) self.add(dot) tex = Tex( "FadeOut with ", "shift ", r" or target\_position", " and scale" ).scale(1) animations = [ FadeOut(tex[0]), FadeOut(tex[1], shift=DOWN), FadeOut(tex[2], target_position=dot), FadeOut(tex[3], scale=0.5), ] self.play(AnimationGroup(*animations, lag_ratio=0.5)) """ def __init__(self, *mobjects: Mobject, **kwargs: Any) -> None: super().__init__(*mobjects, remover=True, **kwargs) def create_target(self) -> Mobject: return self._create_faded_mobject(fadeIn=False) def clean_up_from_scene(self, scene: Scene) -> None: super().clean_up_from_scene(scene) self.interpolate(0) ================================================ FILE: manim/animation/growing.py ================================================ """Animations that introduce mobjects to scene by growing them from points. .. manim:: Growing class Growing(Scene): def construct(self): square = Square() circle = Circle() triangle = Triangle() arrow = Arrow(LEFT, RIGHT) star = Star() VGroup(square, circle, triangle).set_x(0).arrange(buff=1.5).set_y(2) VGroup(arrow, star).move_to(DOWN).set_x(0).arrange(buff=1.5).set_y(-2) self.play(GrowFromPoint(square, ORIGIN)) self.play(GrowFromCenter(circle)) self.play(GrowFromEdge(triangle, DOWN)) self.play(GrowArrow(arrow)) self.play(SpinInFromNothing(star)) """ from __future__ import annotations __all__ = [ "GrowFromPoint", "GrowFromCenter", "GrowFromEdge", "GrowArrow", "SpinInFromNothing", ] from typing import TYPE_CHECKING, Any from ..animation.transform import Transform from ..constants import PI from ..utils.paths import spiral_path if TYPE_CHECKING: from manim.mobject.geometry.line import Arrow from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.typing import Point3DLike, Vector3DLike from manim.utils.color import ParsableManimColor from ..mobject.mobject import Mobject class GrowFromPoint(Transform): """Introduce an :class:`~.Mobject` by growing it from a point. Parameters ---------- mobject The mobjects to be introduced. point The point from which the mobject grows. point_color Initial color of the mobject before growing to its full size. Leave empty to match mobject's color. Examples -------- .. manim :: GrowFromPointExample class GrowFromPointExample(Scene): def construct(self): dot = Dot(3 * UR, color=GREEN) squares = [Square() for _ in range(4)] VGroup(*squares).set_x(0).arrange(buff=1) self.add(dot) self.play(GrowFromPoint(squares[0], ORIGIN)) self.play(GrowFromPoint(squares[1], [-2, 2, 0])) self.play(GrowFromPoint(squares[2], [3, -2, 0], RED)) self.play(GrowFromPoint(squares[3], dot, dot.get_color())) """ def __init__( self, mobject: Mobject, point: Point3DLike, point_color: ParsableManimColor | None = None, **kwargs: Any, ): self.point = point self.point_color = point_color super().__init__(mobject, introducer=True, **kwargs) def create_target(self) -> Mobject | OpenGLMobject: return self.mobject def create_starting_mobject(self) -> Mobject | OpenGLMobject: start = super().create_starting_mobject() start.scale(0) start.move_to(self.point) if self.point_color: start.set_color(self.point_color) return start class GrowFromCenter(GrowFromPoint): """Introduce an :class:`~.Mobject` by growing it from its center. Parameters ---------- mobject The mobjects to be introduced. point_color Initial color of the mobject before growing to its full size. Leave empty to match mobject's color. Examples -------- .. manim :: GrowFromCenterExample class GrowFromCenterExample(Scene): def construct(self): squares = [Square() for _ in range(2)] VGroup(*squares).set_x(0).arrange(buff=2) self.play(GrowFromCenter(squares[0])) self.play(GrowFromCenter(squares[1], point_color=RED)) """ def __init__( self, mobject: Mobject, point_color: ParsableManimColor | None = None, **kwargs: Any, ): point = mobject.get_center() super().__init__(mobject, point, point_color=point_color, **kwargs) class GrowFromEdge(GrowFromPoint): """Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges. Parameters ---------- mobject The mobjects to be introduced. edge The direction to seek bounding box edge of mobject. point_color Initial color of the mobject before growing to its full size. Leave empty to match mobject's color. Examples -------- .. manim :: GrowFromEdgeExample class GrowFromEdgeExample(Scene): def construct(self): squares = [Square() for _ in range(4)] VGroup(*squares).set_x(0).arrange(buff=1) self.play(GrowFromEdge(squares[0], DOWN)) self.play(GrowFromEdge(squares[1], RIGHT)) self.play(GrowFromEdge(squares[2], UR)) self.play(GrowFromEdge(squares[3], UP, point_color=RED)) """ def __init__( self, mobject: Mobject, edge: Vector3DLike, point_color: ParsableManimColor | None = None, **kwargs: Any, ): point = mobject.get_critical_point(edge) super().__init__(mobject, point, point_color=point_color, **kwargs) class GrowArrow(GrowFromPoint): """Introduce an :class:`~.Arrow` by growing it from its start toward its tip. Parameters ---------- arrow The arrow to be introduced. point_color Initial color of the arrow before growing to its full size. Leave empty to match arrow's color. Examples -------- .. manim :: GrowArrowExample class GrowArrowExample(Scene): def construct(self): arrows = [Arrow(2 * LEFT, 2 * RIGHT), Arrow(2 * DR, 2 * UL)] VGroup(*arrows).set_x(0).arrange(buff=2) self.play(GrowArrow(arrows[0])) self.play(GrowArrow(arrows[1], point_color=RED)) """ def __init__( self, arrow: Arrow, point_color: ParsableManimColor | None = None, **kwargs: Any ): point = arrow.get_start() super().__init__(arrow, point, point_color=point_color, **kwargs) def create_starting_mobject(self) -> Mobject | OpenGLMobject: start_arrow = self.mobject.copy() start_arrow.scale(0, scale_tips=True, about_point=self.point) if self.point_color: start_arrow.set_color(self.point_color) return start_arrow class SpinInFromNothing(GrowFromCenter): """Introduce an :class:`~.Mobject` spinning and growing it from its center. Parameters ---------- mobject The mobjects to be introduced. angle The amount of spinning before mobject reaches its full size. E.g. 2*PI means that the object will do one full spin before being fully introduced. point_color Initial color of the mobject before growing to its full size. Leave empty to match mobject's color. Examples -------- .. manim :: SpinInFromNothingExample class SpinInFromNothingExample(Scene): def construct(self): squares = [Square() for _ in range(3)] VGroup(*squares).set_x(0).arrange(buff=2) self.play(SpinInFromNothing(squares[0])) self.play(SpinInFromNothing(squares[1], angle=2 * PI)) self.play(SpinInFromNothing(squares[2], point_color=RED)) """ def __init__( self, mobject: Mobject, angle: float = PI / 2, point_color: ParsableManimColor | None = None, **kwargs: Any, ): self.angle = angle super().__init__( mobject, path_func=spiral_path(angle), point_color=point_color, **kwargs ) ================================================ FILE: manim/animation/indication.py ================================================ """Animations drawing attention to particular mobjects. Examples -------- .. manim:: Indications class Indications(Scene): def construct(self): indications = [ApplyWave,Circumscribe,Flash,FocusOn,Indicate,ShowPassingFlash,Wiggle] names = [Tex(i.__name__).scale(3) for i in indications] self.add(names[0]) for i in range(len(names)): if indications[i] is Flash: self.play(Flash(UP)) elif indications[i] is ShowPassingFlash: self.play(ShowPassingFlash(Underline(names[i]))) else: self.play(indications[i](names[i])) self.play(AnimationGroup( FadeOut(names[i], shift=UP*1.5), FadeIn(names[(i+1)%len(names)], shift=UP*1.5), )) """ from __future__ import annotations __all__ = [ "FocusOn", "Indicate", "Flash", "ShowPassingFlash", "ShowPassingFlashWithThinningStrokeWidth", "ApplyWave", "Circumscribe", "Wiggle", "Blink", ] from collections.abc import Iterable from typing import Any, Self import numpy as np from manim.mobject.geometry.arc import Circle, Dot from manim.mobject.geometry.line import Line from manim.mobject.geometry.polygram import Rectangle from manim.mobject.geometry.shape_matchers import SurroundingRectangle from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.scene.scene import Scene from .. import config from ..animation.animation import Animation from ..animation.composition import AnimationGroup, Succession from ..animation.creation import Create, ShowPartial, Uncreate from ..animation.fading import FadeIn, FadeOut from ..animation.movement import Homotopy from ..animation.transform import Transform from ..animation.updaters.update import UpdateFromFunc from ..constants import * from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VGroup, VMobject from ..typing import Point3D, Point3DLike, Vector3DLike from ..utils.bezier import interpolate, inverse_interpolate from ..utils.color import GREY, PURE_YELLOW, ParsableManimColor from ..utils.rate_functions import RateFunction, smooth, there_and_back, wiggle from ..utils.space_ops import normalize class FocusOn(Transform): """Shrink a spotlight to a position. Parameters ---------- focus_point The point at which to shrink the spotlight. If it is a :class:`.~Mobject` its center will be used. opacity The opacity of the spotlight. color The color of the spotlight. run_time The duration of the animation. Examples -------- .. manim:: UsingFocusOn class UsingFocusOn(Scene): def construct(self): dot = Dot(color=PURE_YELLOW).shift(DOWN) self.add(Tex("Focusing on the dot below:"), dot) self.play(FocusOn(dot)) self.wait() """ def __init__( self, focus_point: Point3DLike | Mobject, opacity: float = 0.2, color: ParsableManimColor = GREY, run_time: float = 2, **kwargs: Any, ): self.focus_point = focus_point self.color = color self.opacity = opacity remover = True starting_dot = Dot( radius=config["frame_x_radius"] + config["frame_y_radius"], stroke_width=0, fill_color=self.color, fill_opacity=0, ) super().__init__(starting_dot, run_time=run_time, remover=remover, **kwargs) def create_target(self) -> Dot: little_dot = Dot(radius=0) little_dot.set_fill(self.color, opacity=self.opacity) little_dot.add_updater(lambda d: d.move_to(self.focus_point)) return little_dot class Indicate(Transform): """Indicate a Mobject by temporarily resizing and recoloring it. Parameters ---------- mobject The mobject to indicate. scale_factor The factor by which the mobject will be temporally scaled color The color the mobject temporally takes. rate_func The function defining the animation progress at every point in time. kwargs Additional arguments to be passed to the :class:`~.Succession` constructor Examples -------- .. manim:: UsingIndicate class UsingIndicate(Scene): def construct(self): tex = Tex("Indicate").scale(3) self.play(Indicate(tex)) self.wait() """ def __init__( self, mobject: Mobject, scale_factor: float = 1.2, color: ParsableManimColor = PURE_YELLOW, rate_func: RateFunction = there_and_back, **kwargs: Any, ): self.color = color self.scale_factor = scale_factor super().__init__(mobject, rate_func=rate_func, **kwargs) def create_target(self) -> Mobject | OpenGLMobject: target = self.mobject.copy() target.scale(self.scale_factor) target.set_color(self.color) return target class Flash(AnimationGroup): """Send out lines in all directions. Parameters ---------- point The center of the flash lines. If it is a :class:`.~Mobject` its center will be used. line_length The length of the flash lines. num_lines The number of flash lines. flash_radius The distance from `point` at which the flash lines start. line_stroke_width The stroke width of the flash lines. color The color of the flash lines. time_width The time width used for the flash lines. See :class:`.~ShowPassingFlash` for more details. run_time The duration of the animation. kwargs Additional arguments to be passed to the :class:`~.Succession` constructor Examples -------- .. manim:: UsingFlash class UsingFlash(Scene): def construct(self): dot = Dot(color=PURE_YELLOW).shift(DOWN) self.add(Tex("Flash the dot below:"), dot) self.play(Flash(dot)) self.wait() .. manim:: FlashOnCircle class FlashOnCircle(Scene): def construct(self): radius = 2 circle = Circle(radius) self.add(circle) self.play(Flash( circle, line_length=1, num_lines=30, color=RED, flash_radius=radius+SMALL_BUFF, time_width=0.3, run_time=2, rate_func = rush_from )) """ def __init__( self, point: Point3DLike | Mobject, line_length: float = 0.2, num_lines: int = 12, flash_radius: float = 0.1, line_stroke_width: int = 3, color: ParsableManimColor = PURE_YELLOW, time_width: float = 1, run_time: float = 1.0, **kwargs: Any, ): if isinstance(point, Mobject): self.point: Point3D = point.get_center() else: self.point = np.asarray(point) self.color = color self.line_length = line_length self.num_lines = num_lines self.flash_radius = flash_radius self.line_stroke_width = line_stroke_width self.run_time = run_time self.time_width = time_width self.animation_config = kwargs self.lines = self.create_lines() animations = self.create_line_anims() super().__init__(*animations, group=self.lines) def create_lines(self) -> VGroup: lines = VGroup() for angle in np.arange(0, TAU, TAU / self.num_lines): line = Line(self.point, self.point + self.line_length * RIGHT) line.shift((self.flash_radius) * RIGHT) line.rotate(angle, about_point=self.point) lines.add(line) lines.set_color(self.color) lines.set_stroke(width=self.line_stroke_width) return lines def create_line_anims(self) -> Iterable[ShowPassingFlash]: return [ ShowPassingFlash( line, time_width=self.time_width, run_time=self.run_time, **self.animation_config, ) for line in self.lines ] class ShowPassingFlash(ShowPartial): r"""Show only a sliver of the VMobject each frame. Parameters ---------- mobject The mobject whose stroke is animated. time_width The length of the sliver relative to the length of the stroke. Examples -------- .. manim:: TimeWidthValues class TimeWidthValues(Scene): def construct(self): p = RegularPolygon(5, color=DARK_GRAY, stroke_width=6).scale(3) lbl = VMobject() 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)) self.play(ShowPassingFlash( p.copy().set_color(BLUE), run_time=2, time_width=time_width )) See Also -------- :class:`~.Create` """ def __init__( self, mobject: VMobject, time_width: float = 0.1, **kwargs: Any ) -> None: self.time_width = time_width super().__init__(mobject, remover=True, introducer=True, **kwargs) def _get_bounds(self, alpha: float) -> tuple[float, float]: tw = self.time_width upper = interpolate(0, 1 + tw, alpha) lower = upper - tw upper = min(upper, 1) lower = max(lower, 0) return (lower, upper) def clean_up_from_scene(self, scene: Scene) -> None: super().clean_up_from_scene(scene) for submob, start in self.get_all_families_zipped(): submob.pointwise_become_partial(start, 0, 1) class ShowPassingFlashWithThinningStrokeWidth(AnimationGroup): def __init__( self, vmobject: VMobject, n_segments: int = 10, time_width: float = 0.1, remover: bool = True, **kwargs: Any, ): self.n_segments = n_segments self.time_width = time_width self.remover = remover max_stroke_width = vmobject.get_stroke_width() max_time_width = kwargs.pop("time_width", self.time_width) super().__init__( *( ShowPassingFlash( vmobject.copy().set_stroke(width=stroke_width), time_width=time_width, **kwargs, ) for stroke_width, time_width in zip( np.linspace(0, max_stroke_width, self.n_segments), np.linspace(max_time_width, 0, self.n_segments), strict=True, ) ), ) class ApplyWave(Homotopy): """Send a wave through the Mobject distorting it temporarily. Parameters ---------- mobject The mobject to be distorted. direction The direction in which the wave nudges points of the shape amplitude The distance points of the shape get shifted wave_func The function defining the shape of one wave flank. time_width The length of the wave relative to the width of the mobject. ripples The number of ripples of the wave run_time The duration of the animation. Examples -------- .. manim:: ApplyingWaves class ApplyingWaves(Scene): def construct(self): tex = Tex("WaveWaveWaveWaveWave").scale(2) self.play(ApplyWave(tex)) self.play(ApplyWave( tex, direction=RIGHT, time_width=0.5, amplitude=0.3 )) self.play(ApplyWave( tex, rate_func=linear, ripples=4 )) """ def __init__( self, mobject: Mobject, direction: Vector3DLike = UP, amplitude: float = 0.2, wave_func: RateFunction = smooth, time_width: float = 1, ripples: int = 1, run_time: float = 2, **kwargs: Any, ): x_min = mobject.get_left()[0] x_max = mobject.get_right()[0] vect = amplitude * normalize(direction) def wave(t: float) -> float: # Creates a wave with n ripples from a simple rate_func # This wave is build up as follows: # The time is split into 2*ripples phases. In every phase the amplitude # either rises to one or goes down to zero. Consecutive ripples will have # their amplitudes in opposing directions (first ripple from 0 to 1 to 0, # second from 0 to -1 to 0 and so on). This is how two ripples would be # divided into phases: # ####|#### | | # ## | ## | | # ## | ## | | # #### | ####|#### | #### # | | ## | ## # | | ## | ## # | | ####|#### # However, this looks weird in the middle between two ripples. Therefore the # middle phases do actually use only one appropriately scaled version of the # rate like this: # 1 / 4 Time | 2 / 4 Time | 1 / 4 Time # ####|###### | # ## | ### | # ## | ## | # #### | # | #### # | ## | ## # | ### | ## # | ######|#### # Mirrored looks better in the way the wave is used. t = 1 - t # Clamp input if t >= 1 or t <= 0: return 0 phases = ripples * 2 phase = int(t * phases) if phase == 0: # First rising ripple return wave_func(t * phases) elif phase == phases - 1: # last ripple. Rising or falling depending on the number of ripples # The (ripples % 2)-term is used to make this distinction. t -= phase / phases # Time relative to the phase return (1 - wave_func(t * phases)) * (2 * (ripples % 2) - 1) else: # Longer phases: phase = int((phase - 1) / 2) t -= (2 * phase + 1) / phases # Similar to last ripple: return (1 - 2 * wave_func(t * ripples)) * (1 - 2 * ((phase) % 2)) def homotopy( x: float, y: float, z: float, t: float, ) -> tuple[float, float, float]: upper = interpolate(0, 1 + time_width, t) lower = upper - time_width relative_x = inverse_interpolate(x_min, x_max, x) wave_phase = inverse_interpolate(lower, upper, relative_x) nudge = wave(wave_phase) * vect return_value: tuple[float, float, float] = np.array([x, y, z]) + nudge return return_value super().__init__(homotopy, mobject, run_time=run_time, **kwargs) class Wiggle(Animation): """Wiggle a Mobject. Parameters ---------- mobject The mobject to wiggle. scale_value The factor by which the mobject will be temporarily scaled. rotation_angle The wiggle angle. n_wiggles The number of wiggles. scale_about_point The point about which the mobject gets scaled. rotate_about_point The point around which the mobject gets rotated. run_time The duration of the animation Examples -------- .. manim:: ApplyingWaves class ApplyingWaves(Scene): def construct(self): tex = Tex("Wiggle").scale(3) self.play(Wiggle(tex)) self.wait() """ def __init__( self, mobject: Mobject, scale_value: float = 1.1, rotation_angle: float = 0.01 * TAU, n_wiggles: int = 6, scale_about_point: Point3DLike | None = None, rotate_about_point: Point3DLike | None = None, run_time: float = 2, **kwargs: Any, ): self.scale_value = scale_value self.rotation_angle = rotation_angle self.n_wiggles = n_wiggles self.scale_about_point = scale_about_point if scale_about_point is not None: self.scale_about_point = np.array(scale_about_point) self.rotate_about_point = rotate_about_point if rotate_about_point is not None: self.rotate_about_point = np.array(rotate_about_point) super().__init__(mobject, run_time=run_time, **kwargs) def get_scale_about_point(self) -> Point3D: if self.scale_about_point is None: return self.mobject.get_center() return self.scale_about_point def get_rotate_about_point(self) -> Point3D: if self.rotate_about_point is None: return self.mobject.get_center() return self.rotate_about_point def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, alpha: float, ) -> Self: submobject.points[:, :] = starting_submobject.points submobject.scale( interpolate(1, self.scale_value, there_and_back(alpha)), about_point=self.get_scale_about_point(), ) submobject.rotate( wiggle(alpha, self.n_wiggles) * self.rotation_angle, about_point=self.get_rotate_about_point(), ) return self class Circumscribe(Succession): r"""Draw a temporary line surrounding the mobject. Parameters ---------- mobject The mobject to be circumscribed. shape The shape with which to surround the given mobject. Should be either :class:`~.Rectangle` or :class:`~.Circle` fade_in Whether to make the surrounding shape to fade in. It will be drawn otherwise. fade_out Whether to make the surrounding shape to fade out. It will be undrawn otherwise. time_width The time_width of the drawing and undrawing. Gets ignored if either `fade_in` or `fade_out` is `True`. buff The distance between the surrounding shape and the given mobject. color The color of the surrounding shape. run_time The duration of the entire animation. kwargs Additional arguments to be passed to the :class:`~.Succession` constructor Examples -------- .. manim:: UsingCircumscribe class UsingCircumscribe(Scene): def construct(self): lbl = Tex(r"Circum-\\scribe").scale(2) self.add(lbl) self.play(Circumscribe(lbl)) self.play(Circumscribe(lbl, Circle)) self.play(Circumscribe(lbl, fade_out=True)) self.play(Circumscribe(lbl, time_width=2)) self.play(Circumscribe(lbl, Circle, True)) """ def __init__( self, mobject: Mobject, shape: type[Rectangle] | type[Circle] = Rectangle, fade_in: bool = False, fade_out: bool = False, time_width: float = 0.3, buff: float = SMALL_BUFF, color: ParsableManimColor = PURE_YELLOW, run_time: float = 1, stroke_width: float = DEFAULT_STROKE_WIDTH, **kwargs: Any, ): if shape is Rectangle: frame: SurroundingRectangle | Circle = SurroundingRectangle( mobject, color=color, buff=buff, stroke_width=stroke_width, ) elif shape is Circle: frame = Circle(color=color, stroke_width=stroke_width).surround( mobject, buffer_factor=1, ) radius = frame.width / 2 frame.scale((radius + buff) / radius) else: raise ValueError("shape should be either Rectangle or Circle.") if fade_in and fade_out: super().__init__( FadeIn(frame, run_time=run_time / 2), FadeOut(frame, run_time=run_time / 2), **kwargs, ) elif fade_in: frame.reverse_direction() super().__init__( FadeIn(frame, run_time=run_time / 2), Uncreate(frame, run_time=run_time / 2), **kwargs, ) elif fade_out: super().__init__( Create(frame, run_time=run_time / 2), FadeOut(frame, run_time=run_time / 2), **kwargs, ) else: super().__init__( ShowPassingFlash(frame, time_width, run_time=run_time), **kwargs ) class Blink(Succession): """Blink the mobject. Parameters ---------- mobject The mobject to be blinked. time_on The duration that the mobject is shown for one blink. time_off The duration that the mobject is hidden for one blink. blinks The number of blinks hide_at_end Whether to hide the mobject at the end of the animation. kwargs Additional arguments to be passed to the :class:`~.Succession` constructor. Examples -------- .. manim:: BlinkingExample class BlinkingExample(Scene): def construct(self): text = Text("Blinking").scale(1.5) self.add(text) self.play(Blink(text, blinks=3)) """ def __init__( self, mobject: Mobject, time_on: float = 0.5, time_off: float = 0.5, blinks: int = 1, hide_at_end: bool = False, **kwargs: Any, ): animations = [ UpdateFromFunc( mobject, update_function=lambda mob: mob.set_opacity(1.0), run_time=time_on, ), UpdateFromFunc( mobject, update_function=lambda mob: mob.set_opacity(0.0), run_time=time_off, ), ] * blinks if not hide_at_end: animations.append( UpdateFromFunc( mobject, update_function=lambda mob: mob.set_opacity(1.0), run_time=time_on, ), ) super().__init__(*animations, **kwargs) ================================================ FILE: manim/animation/movement.py ================================================ """Animations related to movement.""" from __future__ import annotations __all__ = [ "Homotopy", "SmoothedVectorizedHomotopy", "ComplexHomotopy", "PhaseFlow", "MoveAlongPath", ] from collections.abc import Callable from typing import TYPE_CHECKING, Any import numpy as np from ..animation.animation import Animation from ..utils.rate_functions import linear if TYPE_CHECKING: from typing import Self from manim.mobject.types.vectorized_mobject import VMobject from manim.typing import MappingFunction, Point3D from manim.utils.rate_functions import RateFunction from ..mobject.mobject import Mobject class Homotopy(Animation): """A Homotopy. This is an animation transforming the points of a mobject according to the specified transformation function. With the parameter :math:`t` moving from 0 to 1 throughout the animation and :math:`(x, y, z)` describing the coordinates of the point of a mobject, the function passed to the ``homotopy`` keyword argument should transform the tuple :math:`(x, y, z, t)` to :math:`(x', y', z')`, the coordinates the original point is transformed to at time :math:`t`. Parameters ---------- homotopy A function mapping :math:`(x, y, z, t)` to :math:`(x', y', z')`. mobject The mobject transformed under the given homotopy. run_time The run time of the animation. apply_function_kwargs Keyword arguments propagated to :meth:`.Mobject.apply_function`. kwargs Further keyword arguments passed to the parent class. Examples -------- .. manim:: HomotopyExample class HomotopyExample(Scene): def construct(self): square = Square() def homotopy(x, y, z, t): if t <= 0.25: progress = t / 0.25 return (x, y + progress * 0.2 * np.sin(x), z) else: wave_progress = (t - 0.25) / 0.75 return (x, y + 0.2 * np.sin(x + 10 * wave_progress), z) self.play(Homotopy(homotopy, square, rate_func= linear, run_time=2)) """ def __init__( self, homotopy: Callable[[float, float, float, float], tuple[float, float, float]], mobject: Mobject, run_time: float = 3, apply_function_kwargs: dict[str, Any] | None = None, **kwargs: Any, ): self.homotopy = homotopy self.apply_function_kwargs = ( apply_function_kwargs if apply_function_kwargs is not None else {} ) super().__init__(mobject, run_time=run_time, **kwargs) def function_at_time_t(self, t: float) -> MappingFunction: def mapping_function(p: Point3D) -> Point3D: x, y, z = p return np.array(self.homotopy(x, y, z, t)) return mapping_function def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, alpha: float, ) -> Self: submobject.points = starting_submobject.points submobject.apply_function( self.function_at_time_t(alpha), **self.apply_function_kwargs, ) return self class SmoothedVectorizedHomotopy(Homotopy): def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, alpha: float, ) -> Self: assert isinstance(submobject, VMobject) super().interpolate_submobject(submobject, starting_submobject, alpha) submobject.make_smooth() return self class ComplexHomotopy(Homotopy): def __init__( self, complex_homotopy: Callable[[complex, float], float], mobject: Mobject, **kwargs: Any, ): """Complex Homotopy a function Cx[0, 1] to C""" def homotopy( x: float, y: float, z: float, t: float, ) -> tuple[float, float, float]: c = complex_homotopy(complex(x, y), t) return (c.real, c.imag, z) super().__init__(homotopy, mobject, **kwargs) class PhaseFlow(Animation): def __init__( self, function: Callable[[np.ndarray], np.ndarray], mobject: Mobject, virtual_time: float = 1, suspend_mobject_updating: bool = False, rate_func: RateFunction = linear, **kwargs: Any, ): self.virtual_time = virtual_time self.function = function super().__init__( mobject, suspend_mobject_updating=suspend_mobject_updating, rate_func=rate_func, **kwargs, ) def interpolate_mobject(self, alpha: float) -> None: if hasattr(self, "last_alpha"): dt = self.virtual_time * ( self.rate_func(alpha) - self.rate_func(self.last_alpha) ) self.mobject.apply_function(lambda p: p + dt * self.function(p)) self.last_alpha: float = alpha class MoveAlongPath(Animation): """Make one mobject move along the path of another mobject. .. manim:: MoveAlongPathExample class MoveAlongPathExample(Scene): def construct(self): d1 = Dot().set_color(ORANGE) l1 = Line(LEFT, RIGHT) l2 = VMobject() self.add(d1, l1, l2) l2.add_updater(lambda x: x.become(Line(LEFT, d1.get_center()).set_color(ORANGE))) self.play(MoveAlongPath(d1, l1), rate_func=linear) """ def __init__( self, mobject: Mobject, path: VMobject, suspend_mobject_updating: bool = False, **kwargs: Any, ): self.path = path super().__init__( mobject, suspend_mobject_updating=suspend_mobject_updating, **kwargs ) def interpolate_mobject(self, alpha: float) -> None: point = self.path.point_from_proportion(self.rate_func(alpha)) self.mobject.move_to(point) ================================================ FILE: manim/animation/numbers.py ================================================ """Animations for changing numbers.""" from __future__ import annotations __all__ = ["ChangingDecimal", "ChangeDecimalToValue"] from collections.abc import Callable from typing import Any from manim.mobject.text.numbers import DecimalNumber from ..animation.animation import Animation from ..utils.bezier import interpolate class ChangingDecimal(Animation): """Animate a :class:`~.DecimalNumber` to values specified by a user-supplied function. Parameters ---------- decimal_mob The :class:`~.DecimalNumber` instance to animate. number_update_func A function that returns the number to display at each point in the animation. suspend_mobject_updating If ``True``, the mobject is not updated outside this animation. Raises ------ TypeError If ``decimal_mob`` is not an instance of :class:`~.DecimalNumber`. Examples -------- .. manim:: ChangingDecimalExample class ChangingDecimalExample(Scene): def construct(self): number = DecimalNumber(0) self.add(number) self.play( ChangingDecimal( number, lambda a: 5 * a, run_time=3 ) ) self.wait() """ def __init__( self, decimal_mob: DecimalNumber, number_update_func: Callable[[float], float], suspend_mobject_updating: bool = False, **kwargs: Any, ) -> None: self.check_validity_of_input(decimal_mob) self.number_update_func = number_update_func super().__init__( decimal_mob, suspend_mobject_updating=suspend_mobject_updating, **kwargs ) def check_validity_of_input(self, decimal_mob: DecimalNumber) -> None: if not isinstance(decimal_mob, DecimalNumber): raise TypeError("ChangingDecimal can only take in a DecimalNumber") def interpolate_mobject(self, alpha: float) -> None: self.mobject.set_value(self.number_update_func(self.rate_func(alpha))) # type: ignore[attr-defined] class ChangeDecimalToValue(ChangingDecimal): """Animate a :class:`~.DecimalNumber` to a target value using linear interpolation. Parameters ---------- decimal_mob The :class:`~.DecimalNumber` instance to animate. target_number The target value to transition to. Examples -------- .. manim:: ChangeDecimalToValueExample class ChangeDecimalToValueExample(Scene): def construct(self): number = DecimalNumber(0) self.add(number) self.play(ChangeDecimalToValue(number, 10, run_time=3)) self.wait() """ def __init__( self, decimal_mob: DecimalNumber, target_number: int, **kwargs: Any ) -> None: start_number = decimal_mob.number super().__init__( decimal_mob, lambda a: interpolate(start_number, target_number, a), **kwargs ) ================================================ FILE: manim/animation/rotation.py ================================================ """Animations related to rotation.""" from __future__ import annotations __all__ = ["Rotating", "Rotate"] from collections.abc import Callable from typing import TYPE_CHECKING, Any from ..animation.animation import Animation from ..animation.transform import Transform from ..constants import OUT, PI, TAU from ..utils.rate_functions import linear if TYPE_CHECKING: from ..mobject.mobject import Mobject from ..mobject.opengl.opengl_mobject import OpenGLMobject from ..typing import Point3DLike, Vector3DLike class Rotating(Animation): """Animation that rotates a Mobject. Parameters ---------- mobject The mobject to be rotated. angle The rotation angle in radians. Predefined constants such as ``DEGREES`` can also be used to specify the angle in degrees. axis The rotation axis as a numpy vector. about_point The rotation center. about_edge If ``about_point`` is ``None``, this argument specifies the direction of the bounding box point to be taken as the rotation center. run_time The duration of the animation in seconds. rate_func The function defining the animation progress based on the relative runtime (see :mod:`~.rate_functions`) . **kwargs Additional keyword arguments passed to :class:`~.Animation`. Examples -------- .. manim:: RotatingDemo class RotatingDemo(Scene): def construct(self): circle = Circle(radius=1, color=BLUE) line = Line(start=ORIGIN, end=RIGHT) arrow = Arrow(start=ORIGIN, end=RIGHT, buff=0, color=GOLD) vg = VGroup(circle,line,arrow) self.add(vg) anim_kw = {"about_point": arrow.get_start(), "run_time": 1} self.play(Rotating(arrow, 180*DEGREES, **anim_kw)) self.play(Rotating(arrow, PI, **anim_kw)) self.play(Rotating(vg, PI, about_point=RIGHT)) self.play(Rotating(vg, PI, axis=UP, about_point=ORIGIN)) self.play(Rotating(vg, PI, axis=RIGHT, about_edge=UP)) self.play(vg.animate.move_to(ORIGIN)) .. manim:: RotatingDifferentAxis class RotatingDifferentAxis(ThreeDScene): def construct(self): axes = ThreeDAxes() cube = Cube() arrow2d = Arrow(start=[0, -1.2, 1], end=[0, 1.2, 1], color=YELLOW_E) cube_group = VGroup(cube,arrow2d) self.set_camera_orientation(gamma=0, phi=40*DEGREES, theta=40*DEGREES) self.add(axes, cube_group) play_kw = {"run_time": 1.5} self.play(Rotating(cube_group, PI), **play_kw) self.play(Rotating(cube_group, PI, axis=UP), **play_kw) self.play(Rotating(cube_group, 180*DEGREES, axis=RIGHT), **play_kw) self.wait(0.5) See also -------- :class:`~.Rotate`, :meth:`~.Mobject.rotate` """ def __init__( self, mobject: Mobject, angle: float = TAU, axis: Vector3DLike = OUT, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, run_time: float = 5, rate_func: Callable[[float], float] = linear, **kwargs: Any, ) -> None: self.angle = angle self.axis = axis self.about_point = about_point self.about_edge = about_edge super().__init__(mobject, run_time=run_time, rate_func=rate_func, **kwargs) def interpolate_mobject(self, alpha: float) -> None: self.mobject.become(self.starting_mobject) self.mobject.rotate( self.rate_func(alpha) * self.angle, axis=self.axis, about_point=self.about_point, about_edge=self.about_edge, ) class Rotate(Transform): """Animation that rotates a Mobject. Parameters ---------- mobject The mobject to be rotated. angle The rotation angle. axis The rotation axis as a numpy vector. about_point The rotation center. about_edge If ``about_point`` is ``None``, this argument specifies the direction of the bounding box point to be taken as the rotation center. Examples -------- .. manim:: UsingRotate class UsingRotate(Scene): def construct(self): self.play( Rotate( Square(side_length=0.5).shift(UP * 2), angle=2*PI, about_point=ORIGIN, rate_func=linear, ), Rotate(Square(side_length=0.5), angle=2*PI, rate_func=linear), ) See also -------- :class:`~.Rotating`, :meth:`~.Mobject.rotate` """ def __init__( self, mobject: Mobject, angle: float = PI, axis: Vector3DLike = OUT, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, **kwargs: Any, ) -> None: if "path_arc" not in kwargs: kwargs["path_arc"] = angle if "path_arc_axis" not in kwargs: kwargs["path_arc_axis"] = axis self.angle = angle self.axis = axis self.about_edge = about_edge self.about_point = about_point if self.about_point is None: self.about_point = mobject.get_center() super().__init__(mobject, path_arc_centers=self.about_point, **kwargs) def create_target(self) -> Mobject | OpenGLMobject: target = self.mobject.copy() target.rotate( self.angle, axis=self.axis, about_point=self.about_point, about_edge=self.about_edge, ) return target ================================================ FILE: manim/animation/specialized.py ================================================ from __future__ import annotations __all__ = ["Broadcast"] from collections.abc import Sequence from typing import Any from manim.animation.transform import Restore from manim.mobject.mobject import Mobject from ..constants import * from .composition import LaggedStart class Broadcast(LaggedStart): """Broadcast a mobject starting from an ``initial_width``, up to the actual size of the mobject. Parameters ---------- mobject The mobject to be broadcast. focal_point The center of the broadcast, by default ORIGIN. n_mobs The number of mobjects that emerge from the focal point, by default 5. initial_opacity The starting stroke opacity of the mobjects emitted from the broadcast, by default 1. final_opacity The final stroke opacity of the mobjects emitted from the broadcast, by default 0. initial_width The initial width of the mobjects, by default 0.0. remover Whether the mobjects should be removed from the scene after the animation, by default True. lag_ratio The time between each iteration of the mobject, by default 0.2. run_time The total duration of the animation, by default 3. kwargs Additional arguments to be passed to :class:`~.LaggedStart`. Examples --------- .. manim:: BroadcastExample class BroadcastExample(Scene): def construct(self): mob = Circle(radius=4, color=TEAL_A) self.play(Broadcast(mob)) """ def __init__( self, mobject: Mobject, focal_point: Sequence[float] = ORIGIN, n_mobs: int = 5, initial_opacity: float = 1, final_opacity: float = 0, initial_width: float = 0.0, remover: bool = True, lag_ratio: float = 0.2, run_time: float = 3, **kwargs: Any, ): self.focal_point = focal_point self.n_mobs = n_mobs self.initial_opacity = initial_opacity self.final_opacity = final_opacity self.initial_width = initial_width anims = [] # Works by saving the mob that is passed into the animation, scaling it to 0 (or the initial_width) and then restoring the original mob. fill_o = bool(mobject.fill_opacity) for _ in range(self.n_mobs): mob = mobject.copy() if fill_o: mob.set_opacity(self.final_opacity) else: mob.set_stroke(opacity=self.final_opacity) mob.move_to(self.focal_point) mob.save_state() mob.set(width=self.initial_width) if fill_o: mob.set_opacity(self.initial_opacity) else: mob.set_stroke(opacity=self.initial_opacity) anims.append(Restore(mob, remover=remover)) super().__init__(*anims, run_time=run_time, lag_ratio=lag_ratio, **kwargs) ================================================ FILE: manim/animation/speedmodifier.py ================================================ """Utilities for modifying the speed at which animations are played.""" from __future__ import annotations import inspect import types from collections.abc import Callable from typing import TYPE_CHECKING from numpy import piecewise from ..animation.animation import Animation, Wait, prepare_animation from ..animation.composition import AnimationGroup from ..mobject.mobject import Mobject, _AnimationBuilder from ..scene.scene import Scene if TYPE_CHECKING: from ..mobject.mobject import Updater __all__ = ["ChangeSpeed"] class ChangeSpeed(Animation): """Modifies the speed of passed animation. :class:`AnimationGroup` with different ``lag_ratio`` can also be used which combines multiple animations into one. The ``run_time`` of the passed animation is changed to modify the speed. Parameters ---------- anim Animation of which the speed is to be modified. speedinfo Contains nodes (percentage of ``run_time``) and its corresponding speed factor. rate_func Overrides ``rate_func`` of passed animation, applied before changing speed. Examples -------- .. manim:: SpeedModifierExample class SpeedModifierExample(Scene): def construct(self): a = Dot().shift(LEFT * 4) b = Dot().shift(RIGHT * 4) self.add(a, b) self.play( ChangeSpeed( AnimationGroup( a.animate(run_time=1).shift(RIGHT * 8), b.animate(run_time=1).shift(LEFT * 8), ), speedinfo={0.3: 1, 0.4: 0.1, 0.6: 0.1, 1: 1}, rate_func=linear, ) ) .. manim:: SpeedModifierUpdaterExample class SpeedModifierUpdaterExample(Scene): def construct(self): a = Dot().shift(LEFT * 4) self.add(a) ChangeSpeed.add_updater(a, lambda x, dt: x.shift(RIGHT * 4 * dt)) self.play( ChangeSpeed( Wait(2), speedinfo={0.4: 1, 0.5: 0.2, 0.8: 0.2, 1: 1}, affects_speed_updaters=True, ) ) .. manim:: SpeedModifierUpdaterExample2 class SpeedModifierUpdaterExample2(Scene): def construct(self): a = Dot().shift(LEFT * 4) self.add(a) ChangeSpeed.add_updater(a, lambda x, dt: x.shift(RIGHT * 4 * dt)) self.wait() self.play( ChangeSpeed( Wait(), speedinfo={1: 0}, affects_speed_updaters=True, ) ) """ dt = 0 is_changing_dt = False def __init__( self, anim: Animation | _AnimationBuilder, speedinfo: dict[float, float], rate_func: Callable[[float], float] | None = None, affects_speed_updaters: bool = True, **kwargs, ) -> None: if issubclass(type(anim), AnimationGroup): self.anim = type(anim)( *map(self.setup, anim.animations), group=anim.group, run_time=anim.run_time, rate_func=anim.rate_func, lag_ratio=anim.lag_ratio, ) else: self.anim = self.setup(anim) if affects_speed_updaters: assert ChangeSpeed.is_changing_dt is False, ( "Only one animation at a time can play that changes speed (dt) for ChangeSpeed updaters" ) ChangeSpeed.is_changing_dt = True self.t = 0 self.affects_speed_updaters = affects_speed_updaters self.rate_func = self.anim.rate_func if rate_func is None else rate_func # A function where, f(0) = 0, f'(0) = initial speed, f'( f-1(1) ) = final speed # Following function obtained when conditions applied to vertical parabola self.speed_modifier = lambda x, init_speed, final_speed: ( (final_speed**2 - init_speed**2) * x**2 / 4 + init_speed * x ) # f-1(1), returns x for which f(x) = 1 in `speed_modifier` function self.f_inv_1 = lambda init_speed, final_speed: 2 / (init_speed + final_speed) # if speed factors for the starting node (0) and the final node (1) are # not set, set them to 1 and the penultimate factor, respectively if 0 not in speedinfo: speedinfo[0] = 1 if 1 not in speedinfo: speedinfo[1] = sorted(speedinfo.items())[-1][1] self.speedinfo = dict(sorted(speedinfo.items())) self.functions = [] self.conditions = [] # Get the time taken by amimation if `run_time` is assumed to be 1 scaled_total_time = self.get_scaled_total_time() prevnode = 0 init_speed = self.speedinfo[0] curr_time = 0 for node, final_speed in list(self.speedinfo.items())[1:]: dur = node - prevnode def condition( t, curr_time=curr_time, init_speed=init_speed, final_speed=final_speed, dur=dur, ): lower_bound = curr_time / scaled_total_time upper_bound = ( curr_time + self.f_inv_1(init_speed, final_speed) * dur ) / scaled_total_time return lower_bound <= t <= upper_bound self.conditions.append(condition) def function( t, curr_time=curr_time, init_speed=init_speed, final_speed=final_speed, dur=dur, prevnode=prevnode, ): return ( self.speed_modifier( (scaled_total_time * t - curr_time) / dur, init_speed, final_speed, ) * dur + prevnode ) self.functions.append(function) curr_time += self.f_inv_1(init_speed, final_speed) * dur prevnode = node init_speed = final_speed def func(t): if t == 1: ChangeSpeed.is_changing_dt = False new_t = piecewise( self.rate_func(t), [condition(self.rate_func(t)) for condition in self.conditions], self.functions, ) if self.affects_speed_updaters: ChangeSpeed.dt = (new_t - self.t) * self.anim.run_time self.t = new_t return new_t self.anim.set_rate_func(func) super().__init__( self.anim.mobject, rate_func=self.rate_func, run_time=scaled_total_time * self.anim.run_time, **kwargs, ) def setup(self, anim): if type(anim) is Wait: anim.interpolate = types.MethodType( lambda self, alpha: self.rate_func(alpha), anim ) return prepare_animation(anim) def get_scaled_total_time(self) -> float: """The time taken by the animation under the assumption that the ``run_time`` is 1.""" prevnode = 0 init_speed = self.speedinfo[0] total_time = 0 for node, final_speed in list(self.speedinfo.items())[1:]: dur = node - prevnode total_time += dur * self.f_inv_1(init_speed, final_speed) prevnode = node init_speed = final_speed return total_time @classmethod def add_updater( cls, mobject: Mobject, update_function: Updater, index: int | None = None, call_updater: bool = False, ): """This static method can be used to apply speed change to updaters. This updater will follow speed and rate function of any :class:`.ChangeSpeed` animation that is playing with ``affects_speed_updaters=True``. By default, updater functions added via the usual :meth:`.Mobject.add_updater` method do not respect the change of animation speed. Parameters ---------- mobject The mobject to which the updater should be attached. update_function The function that is called whenever a new frame is rendered. index The position in the list of the mobject's updaters at which the function should be inserted. call_updater If ``True``, calls the update function when attaching it to the mobject. See also -------- :class:`.ChangeSpeed` :meth:`.Mobject.add_updater` """ if "dt" in inspect.signature(update_function).parameters: mobject.add_updater( lambda mob, dt: update_function( mob, ChangeSpeed.dt if ChangeSpeed.is_changing_dt else dt ), index=index, call_updater=call_updater, ) else: mobject.add_updater(update_function, index=index, call_updater=call_updater) def interpolate(self, alpha: float) -> None: self.anim.interpolate(alpha) def update_mobjects(self, dt: float) -> None: self.anim.update_mobjects(dt) def finish(self) -> None: ChangeSpeed.is_changing_dt = False self.anim.finish() def begin(self) -> None: self.anim.begin() def clean_up_from_scene(self, scene: Scene) -> None: self.anim.clean_up_from_scene(scene) def _setup_scene(self, scene) -> None: self.anim._setup_scene(scene) ================================================ FILE: manim/animation/transform.py ================================================ """Animations transforming one mobject into another.""" from __future__ import annotations __all__ = [ "Transform", "ReplacementTransform", "TransformFromCopy", "ClockwiseTransform", "CounterclockwiseTransform", "MoveToTarget", "ApplyMethod", "ApplyPointwiseFunction", "ApplyPointwiseFunctionToCenter", "FadeToColor", "FadeTransform", "FadeTransformPieces", "ScaleInPlace", "ShrinkToCenter", "Restore", "ApplyFunction", "ApplyMatrix", "ApplyComplexFunction", "CyclicReplace", "Swap", "TransformAnimations", ] import inspect import types from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING, Any import numpy as np from manim.data_structures import MethodWithArgs from manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject from .. import config from ..animation.animation import Animation from ..constants import ( DEFAULT_POINTWISE_FUNCTION_RUN_TIME, DEGREES, ORIGIN, OUT, RendererType, ) from ..mobject.mobject import Group, Mobject from ..utils.paths import path_along_arc, path_along_circles from ..utils.rate_functions import smooth, squish_rate_func if TYPE_CHECKING: from ..scene.scene import Scene from ..typing import Point3DLike, Point3DLike_Array class Transform(Animation): """A Transform transforms a Mobject into a target Mobject. Parameters ---------- mobject The :class:`.Mobject` to be transformed. It will be mutated to become the ``target_mobject``. target_mobject The target of the transformation. path_func A function defining the path that the points of the ``mobject`` are being moved along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`. path_arc The arc angle (in radians) that the points of ``mobject`` will follow to reach the points of the target if using a circular path arc, see ``path_arc_centers``. See also :func:`manim.utils.paths.path_along_arc`. path_arc_axis The axis to rotate along if using a circular path arc, see ``path_arc_centers``. path_arc_centers The center of the circular arcs along which the points of ``mobject`` are moved by the transformation. If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it. replace_mobject_with_target_in_scene Controls which mobject is replaced when the transformation is complete. If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape. Examples -------- .. manim :: TransformPathArc class TransformPathArc(Scene): def construct(self): def make_arc_path(start, end, arc_angle): points = [] p_fn = path_along_arc(arc_angle) # alpha animates between 0.0 and 1.0, where 0.0 # is the beginning of the animation and 1.0 is the end. for alpha in range(0, 11): points.append(p_fn(start, end, alpha / 10.0)) path = VMobject(stroke_color=YELLOW) path.set_points_smoothly(points) return path left = Circle(stroke_color=BLUE_E, fill_opacity=1.0, radius=0.5).move_to(LEFT * 2) colors = [TEAL_A, TEAL_B, TEAL_C, TEAL_D, TEAL_E, GREEN_A] # Positive angles move counter-clockwise, negative angles move clockwise. examples = [-90, 0, 30, 90, 180, 270] anims = [] for idx, angle in enumerate(examples): left_c = left.copy().shift((3 - idx) * UP) left_c.fill_color = colors[idx] right_c = left_c.copy().shift(4 * RIGHT) path_arc = make_arc_path(left_c.get_center(), right_c.get_center(), arc_angle=angle * DEGREES) desc = Text('%d°' % examples[idx]).next_to(left_c, LEFT) # Make the circles in front of the text in front of the arcs. self.add( path_arc.set_z_index(1), desc.set_z_index(2), left_c.set_z_index(3), ) anims.append(Transform(left_c, right_c, path_arc=angle * DEGREES)) self.play(*anims, run_time=2) self.wait() See also -------- :class:`~.ReplacementTransform`, :meth:`~.Mobject.interpolate`, :meth:`~.Mobject.align_data` """ def __init__( self, mobject: Mobject | None, target_mobject: Mobject | None = None, path_func: Callable | None = None, path_arc: float = 0, path_arc_axis: np.ndarray = OUT, path_arc_centers: Point3DLike | Point3DLike_Array | None = None, replace_mobject_with_target_in_scene: bool = False, **kwargs, ) -> None: self.path_arc_axis: np.ndarray = path_arc_axis self.path_arc_centers: Point3DLike | Point3DLike_Array | None = path_arc_centers self.path_arc: float = path_arc # path_func is a property a few lines below so it doesn't need to be set in any case if path_func is not None: self.path_func: Callable = path_func elif self.path_arc_centers is not None: self.path_func = path_along_circles( path_arc, self.path_arc_centers, self.path_arc_axis, ) self.replace_mobject_with_target_in_scene: bool = ( replace_mobject_with_target_in_scene ) self.target_mobject: Mobject = ( target_mobject if target_mobject is not None else Mobject() ) super().__init__(mobject, **kwargs) @property def path_arc(self) -> float: return self._path_arc @path_arc.setter def path_arc(self, path_arc: float) -> None: self._path_arc = path_arc self._path_func = path_along_arc( arc_angle=self._path_arc, axis=self.path_arc_axis, ) @property def path_func( self, ) -> Callable[ [Iterable[np.ndarray], Iterable[np.ndarray], float], Iterable[np.ndarray], ]: return self._path_func @path_func.setter def path_func( self, path_func: Callable[ [Iterable[np.ndarray], Iterable[np.ndarray], float], Iterable[np.ndarray], ], ) -> None: if path_func is not None: self._path_func = path_func def begin(self) -> None: # Use a copy of target_mobject for the align_data # call so that the actual target_mobject stays # preserved. self.target_mobject = self.create_target() self.target_copy = self.target_mobject.copy() # Note, this potentially changes the structure # of both mobject and target_mobject if config.renderer == RendererType.OPENGL: self.mobject.align_data_and_family(self.target_copy) else: self.mobject.align_data(self.target_copy) super().begin() def create_target(self) -> Mobject | OpenGLMobject: # Has no meaningful effect here, but may be useful # in subclasses return self.target_mobject def clean_up_from_scene(self, scene: Scene) -> None: super().clean_up_from_scene(scene) if self.replace_mobject_with_target_in_scene: scene.replace(self.mobject, self.target_mobject) def get_all_mobjects(self) -> Sequence[Mobject]: return [ self.mobject, self.starting_mobject, self.target_mobject, self.target_copy, ] def get_all_families_zipped(self) -> Iterable[tuple]: # more precise typing? mobs = [ self.mobject, self.starting_mobject, self.target_copy, ] if config.renderer == RendererType.OPENGL: return zip(*(mob.get_family() for mob in mobs), strict=True) return zip(*(mob.family_members_with_points() for mob in mobs), strict=True) def interpolate_submobject( self, submobject: Mobject, starting_submobject: Mobject, target_copy: Mobject, alpha: float, ) -> Transform: submobject.interpolate(starting_submobject, target_copy, alpha, self.path_func) return self class ReplacementTransform(Transform): """Replaces and morphs a mobject into a target mobject. Parameters ---------- mobject The starting :class:`~.Mobject`. target_mobject The target :class:`~.Mobject`. kwargs Further keyword arguments that are passed to :class:`Transform`. Examples -------- .. manim:: ReplacementTransformOrTransform :quality: low class ReplacementTransformOrTransform(Scene): def construct(self): # set up the numbers r_transform = VGroup(*[Integer(i) for i in range(1,4)]) text_1 = Text("ReplacementTransform", color=RED) r_transform.add(text_1) transform = VGroup(*[Integer(i) for i in range(4,7)]) text_2 = Text("Transform", color=BLUE) transform.add(text_2) ints = VGroup(r_transform, transform) texts = VGroup(text_1, text_2).scale(0.75) r_transform.arrange(direction=UP, buff=1) transform.arrange(direction=UP, buff=1) ints.arrange(buff=2) self.add(ints, texts) # The mobs replace each other and none are left behind self.play(ReplacementTransform(r_transform[0], r_transform[1])) self.play(ReplacementTransform(r_transform[1], r_transform[2])) # The mobs linger after the Transform() self.play(Transform(transform[0], transform[1])) self.play(Transform(transform[1], transform[2])) self.wait() """ def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None: super().__init__( mobject, target_mobject, replace_mobject_with_target_in_scene=True, **kwargs ) class TransformFromCopy(Transform): """Preserves a copy of the original VMobject and transforms only it's copy to the target VMobject""" def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None: super().__init__(target_mobject, mobject, **kwargs) def interpolate(self, alpha: float) -> None: super().interpolate(1 - alpha) class ClockwiseTransform(Transform): """Transforms the points of a mobject along a clockwise oriented arc. See also -------- :class:`.Transform`, :class:`.CounterclockwiseTransform` Examples -------- .. manim:: ClockwiseExample class ClockwiseExample(Scene): def construct(self): dl, dr = Dot(), Dot() sl, sr = Square(), Square() VGroup(dl, sl).arrange(DOWN).shift(2*LEFT) VGroup(dr, sr).arrange(DOWN).shift(2*RIGHT) self.add(dl, dr) self.wait() self.play( ClockwiseTransform(dl, sl), Transform(dr, sr) ) self.wait() """ def __init__( self, mobject: Mobject, target_mobject: Mobject, path_arc: float = -np.pi, **kwargs, ) -> None: super().__init__(mobject, target_mobject, path_arc=path_arc, **kwargs) class CounterclockwiseTransform(Transform): """Transforms the points of a mobject along a counterclockwise oriented arc. See also -------- :class:`.Transform`, :class:`.ClockwiseTransform` Examples -------- .. manim:: CounterclockwiseTransform_vs_Transform class CounterclockwiseTransform_vs_Transform(Scene): def construct(self): # set up the numbers c_transform = VGroup(DecimalNumber(number=3.141, num_decimal_places=3), DecimalNumber(number=1.618, num_decimal_places=3)) text_1 = Text("CounterclockwiseTransform", color=RED) c_transform.add(text_1) transform = VGroup(DecimalNumber(number=1.618, num_decimal_places=3), DecimalNumber(number=3.141, num_decimal_places=3)) text_2 = Text("Transform", color=BLUE) transform.add(text_2) ints = VGroup(c_transform, transform) texts = VGroup(text_1, text_2).scale(0.75) c_transform.arrange(direction=UP, buff=1) transform.arrange(direction=UP, buff=1) ints.arrange(buff=2) self.add(ints, texts) # The mobs move in clockwise direction for ClockwiseTransform() self.play(CounterclockwiseTransform(c_transform[0], c_transform[1])) # The mobs move straight up for Transform() self.play(Transform(transform[0], transform[1])) """ def __init__( self, mobject: Mobject, target_mobject: Mobject, path_arc: float = np.pi, **kwargs, ) -> None: super().__init__(mobject, target_mobject, path_arc=path_arc, **kwargs) class MoveToTarget(Transform): """Transforms a mobject to the mobject stored in its ``target`` attribute. After calling the :meth:`~.Mobject.generate_target` method, the :attr:`target` attribute of the mobject is populated with a copy of it. After modifying the attribute, playing the :class:`.MoveToTarget` animation transforms the original mobject into the modified one stored in the :attr:`target` attribute. Examples -------- .. manim:: MoveToTargetExample class MoveToTargetExample(Scene): def construct(self): c = Circle() c.generate_target() c.target.set_fill(color=GREEN, opacity=0.5) c.target.shift(2*RIGHT + UP).scale(0.5) self.add(c) self.play(MoveToTarget(c)) """ def __init__(self, mobject: Mobject, **kwargs) -> None: self.check_validity_of_input(mobject) super().__init__(mobject, mobject.target, **kwargs) def check_validity_of_input(self, mobject: Mobject) -> None: if not hasattr(mobject, "target"): raise ValueError( "MoveToTarget called on mobjectwithout attribute 'target'", ) class _MethodAnimation(MoveToTarget): def __init__(self, mobject: Mobject, methods: list[MethodWithArgs]) -> None: self.methods = methods super().__init__(mobject) def finish(self) -> None: for item in self.methods: item.method.__func__(self.mobject, *item.args, **item.kwargs) super().finish() class ApplyMethod(Transform): """Animates a mobject by applying a method. Note that only the method needs to be passed to this animation, it is not required to pass the corresponding mobject. Furthermore, this animation class only works if the method returns the modified mobject. Parameters ---------- method The method that will be applied in the animation. args Any positional arguments to be passed when applying the method. kwargs Any keyword arguments passed to :class:`~.Transform`. """ def __init__( self, method: Callable, *args, **kwargs ) -> None: # method typing (we want to specify Mobject method)? for args? self.check_validity_of_input(method) self.method = method self.method_args = args super().__init__(method.__self__, **kwargs) def check_validity_of_input(self, method: Callable) -> None: if not inspect.ismethod(method): raise ValueError( "Whoops, looks like you accidentally invoked " "the method you want to animate", ) assert isinstance(method.__self__, (Mobject, OpenGLMobject)) def create_target(self) -> Mobject: method = self.method # Make sure it's a list so that args.pop() works args = list(self.method_args) if len(args) > 0 and isinstance(args[-1], dict): method_kwargs = args.pop() else: method_kwargs = {} target = method.__self__.copy() method.__func__(target, *args, **method_kwargs) return target class ApplyPointwiseFunction(ApplyMethod): """Animation that applies a pointwise function to a mobject. Examples -------- .. manim:: WarpSquare :quality: low class WarpSquare(Scene): def construct(self): square = Square() self.play( ApplyPointwiseFunction( lambda point: complex_to_R3(np.exp(R3_to_complex(point))), square ) ) self.wait() """ def __init__( self, function: types.MethodType, mobject: Mobject, run_time: float = DEFAULT_POINTWISE_FUNCTION_RUN_TIME, **kwargs, ) -> None: super().__init__(mobject.apply_function, function, run_time=run_time, **kwargs) class ApplyPointwiseFunctionToCenter(ApplyPointwiseFunction): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function super().__init__(mobject.move_to, **kwargs) def begin(self) -> None: self.method_args = [self.function(self.mobject.get_center())] super().begin() class FadeToColor(ApplyMethod): """Animation that changes color of a mobject. Examples -------- .. manim:: FadeToColorExample class FadeToColorExample(Scene): def construct(self): self.play(FadeToColor(Text("Hello World!"), color=RED)) """ def __init__(self, mobject: Mobject, color: str, **kwargs) -> None: super().__init__(mobject.set_color, color, **kwargs) class ScaleInPlace(ApplyMethod): """Animation that scales a mobject by a certain factor. Examples -------- .. manim:: ScaleInPlaceExample class ScaleInPlaceExample(Scene): def construct(self): self.play(ScaleInPlace(Text("Hello World!"), 2)) """ def __init__(self, mobject: Mobject, scale_factor: float, **kwargs) -> None: super().__init__(mobject.scale, scale_factor, **kwargs) class ShrinkToCenter(ScaleInPlace): """Animation that makes a mobject shrink to center. Examples -------- .. manim:: ShrinkToCenterExample class ShrinkToCenterExample(Scene): def construct(self): self.play(ShrinkToCenter(Text("Hello World!"))) """ def __init__(self, mobject: Mobject, **kwargs) -> None: super().__init__(mobject, 0, **kwargs) class Restore(ApplyMethod): """Transforms a mobject to its last saved state. To save the state of a mobject, use the :meth:`~.Mobject.save_state` method. Examples -------- .. manim:: RestoreExample class RestoreExample(Scene): def construct(self): s = Square() s.save_state() self.play(FadeIn(s)) self.play(s.animate.set_color(PURPLE).set_opacity(0.5).shift(2*LEFT).scale(3)) self.play(s.animate.shift(5*DOWN).rotate(PI/4)) self.wait() self.play(Restore(s), run_time=2) """ def __init__(self, mobject: Mobject, **kwargs) -> None: super().__init__(mobject.restore, **kwargs) class ApplyFunction(Transform): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function super().__init__(mobject, **kwargs) def create_target(self) -> Any: target = self.function(self.mobject.copy()) if not isinstance(target, (Mobject, OpenGLMobject)): raise TypeError( "Functions passed to ApplyFunction must return object of type Mobject", ) return target class ApplyMatrix(ApplyPointwiseFunction): """Applies a matrix transform to an mobject. Parameters ---------- matrix The transformation matrix. mobject The :class:`~.Mobject`. about_point The origin point for the transform. Defaults to ``ORIGIN``. kwargs Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`. Examples -------- .. manim:: ApplyMatrixExample class ApplyMatrixExample(Scene): def construct(self): matrix = [[1, 1], [0, 2/3]] self.play(ApplyMatrix(matrix, Text("Hello World!")), ApplyMatrix(matrix, NumberPlane())) """ def __init__( self, matrix: np.ndarray, mobject: Mobject, about_point: np.ndarray = ORIGIN, **kwargs, ) -> None: matrix = self.initialize_matrix(matrix) def func(p): return np.dot(p - about_point, matrix.T) + about_point super().__init__(func, mobject, **kwargs) def initialize_matrix(self, matrix: np.ndarray) -> np.ndarray: matrix = np.array(matrix) if matrix.shape == (2, 2): new_matrix = np.identity(3) new_matrix[:2, :2] = matrix matrix = new_matrix elif matrix.shape != (3, 3): raise ValueError("Matrix has bad dimensions") return matrix class ApplyComplexFunction(ApplyMethod): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function method = mobject.apply_complex_function super().__init__(method, function, **kwargs) def _init_path_func(self) -> None: func1 = self.function(complex(1)) self.path_arc = np.log(func1).imag super()._init_path_func() ### class CyclicReplace(Transform): """An animation moving mobjects cyclically. In particular, this means: the first mobject takes the place of the second mobject, the second one takes the place of the third mobject, and so on. The last mobject takes the place of the first one. Parameters ---------- mobjects List of mobjects to be transformed. path_arc The angle of the arc (in radians) that the mobjects will follow to reach their target. kwargs Further keyword arguments that are passed to :class:`.Transform`. Examples -------- .. manim :: CyclicReplaceExample class CyclicReplaceExample(Scene): def construct(self): group = VGroup(Square(), Circle(), Triangle(), Star()) group.arrange(RIGHT) self.add(group) for _ in range(4): self.play(CyclicReplace(*group)) """ def __init__( self, *mobjects: Mobject, path_arc: float = 90 * DEGREES, **kwargs ) -> None: self.group = Group(*mobjects) super().__init__(self.group, path_arc=path_arc, **kwargs) def create_target(self) -> Group: target = self.group.copy() cycled_targets = [target[-1], *target[:-1]] for m1, m2 in zip(cycled_targets, self.group, strict=True): m1.move_to(m2) return target class Swap(CyclicReplace): pass # Renaming, more understandable for two entries # TODO, this may be deprecated...worth reimplementing? class TransformAnimations(Transform): def __init__( self, start_anim: Animation, end_anim: Animation, rate_func: Callable = squish_rate_func(smooth), **kwargs, ) -> None: self.start_anim = start_anim self.end_anim = end_anim if "run_time" in kwargs: self.run_time = kwargs.pop("run_time") else: self.run_time = max(start_anim.run_time, end_anim.run_time) for anim in start_anim, end_anim: anim.set_run_time(self.run_time) if ( start_anim.starting_mobject is not None and end_anim.starting_mobject is not None and start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points() ): start_anim.starting_mobject.align_data(end_anim.starting_mobject) for anim in start_anim, end_anim: if isinstance(anim, Transform) and anim.starting_mobject is not None: anim.starting_mobject.align_data(anim.target_mobject) super().__init__( start_anim.mobject, end_anim.mobject, rate_func=rate_func, **kwargs ) # Rewire starting and ending mobjects start_anim.mobject = self.starting_mobject end_anim.mobject = self.target_mobject def interpolate(self, alpha: float) -> None: self.start_anim.interpolate(alpha) self.end_anim.interpolate(alpha) super().interpolate(alpha) class FadeTransform(Transform): """Fades one mobject into another. Parameters ---------- mobject The starting :class:`~.Mobject`. target_mobject The target :class:`~.Mobject`. stretch Controls whether the target :class:`~.Mobject` is stretched during the animation. Default: ``True``. dim_to_match If the target mobject is not stretched automatically, this allows to adjust the initial scale of the target :class:`~.Mobject` while it is shifted in. Setting this to 0, 1, and 2, respectively, matches the length of the target with the length of the starting :class:`~.Mobject` in x, y, and z direction, respectively. kwargs Further keyword arguments are passed to the parent class. Examples -------- .. manim:: DifferentFadeTransforms class DifferentFadeTransforms(Scene): def construct(self): starts = [Rectangle(width=4, height=1) for _ in range(3)] VGroup(*starts).arrange(DOWN, buff=1).shift(3*LEFT) targets = [Circle(fill_opacity=1).scale(0.25) for _ in range(3)] VGroup(*targets).arrange(DOWN, buff=1).shift(3*RIGHT) self.play(*[FadeIn(s) for s in starts]) self.play( FadeTransform(starts[0], targets[0], stretch=True), FadeTransform(starts[1], targets[1], stretch=False, dim_to_match=0), FadeTransform(starts[2], targets[2], stretch=False, dim_to_match=1) ) self.play(*[FadeOut(mobj) for mobj in self.mobjects]) """ def __init__(self, mobject, target_mobject, stretch=True, dim_to_match=1, **kwargs): self.to_add_on_completion = target_mobject self.stretch = stretch self.dim_to_match = dim_to_match mobject.save_state() if config.renderer == RendererType.OPENGL: group = OpenGLGroup(mobject, target_mobject.copy()) else: group = Group(mobject, target_mobject.copy()) super().__init__(group, **kwargs) def begin(self): """Initial setup for the animation. The mobject to which this animation is bound is a group consisting of both the starting and the ending mobject. At the start, the ending mobject replaces the starting mobject (and is completely faded). In the end, it is set to be the other way around. """ self.ending_mobject = self.mobject.copy() Animation.begin(self) # Both 'start' and 'end' consists of the source and target mobjects. # At the start, the target should be faded replacing the source, # and at the end it should be the other way around. start, end = self.starting_mobject, self.ending_mobject for m0, m1 in ((start[1], start[0]), (end[0], end[1])): self.ghost_to(m0, m1) def ghost_to(self, source, target): """Replaces the source by the target and sets the opacity to 0. If the provided target has no points, and thus a location of [0, 0, 0] the source will simply fade out where it currently is. """ # mobject.replace() does not work if the target has no points. if target.get_num_points() or target.submobjects: source.replace(target, stretch=self.stretch, dim_to_match=self.dim_to_match) source.set_opacity(0) def get_all_mobjects(self) -> Sequence[Mobject]: return [ self.mobject, self.starting_mobject, self.ending_mobject, ] def get_all_families_zipped(self): return Animation.get_all_families_zipped(self) def clean_up_from_scene(self, scene): Animation.clean_up_from_scene(self, scene) scene.remove(self.mobject) self.mobject[0].restore() scene.add(self.to_add_on_completion) class FadeTransformPieces(FadeTransform): """Fades submobjects of one mobject into submobjects of another one. See also -------- :class:`~.FadeTransform` Examples -------- .. manim:: FadeTransformSubmobjects class FadeTransformSubmobjects(Scene): def construct(self): src = VGroup(Square(), Circle().shift(LEFT + UP)) src.shift(3*LEFT + 2*UP) src_copy = src.copy().shift(4*DOWN) target = VGroup(Circle(), Triangle().shift(RIGHT + DOWN)) target.shift(3*RIGHT + 2*UP) target_copy = target.copy().shift(4*DOWN) self.play(FadeIn(src), FadeIn(src_copy)) self.play( FadeTransform(src, target), FadeTransformPieces(src_copy, target_copy) ) self.play(*[FadeOut(mobj) for mobj in self.mobjects]) """ def begin(self): self.mobject[0].align_submobjects(self.mobject[1]) super().begin() def ghost_to(self, source, target): """Replaces the source submobjects by the target submobjects and sets the opacity to 0. """ for sm0, sm1 in zip(source.get_family(), target.get_family(), strict=True): super().ghost_to(sm0, sm1) ================================================ FILE: manim/animation/transform_matching_parts.py ================================================ """Animations that try to transform Mobjects while keeping track of identical parts.""" from __future__ import annotations __all__ = ["TransformMatchingShapes", "TransformMatchingTex"] from typing import TYPE_CHECKING import numpy as np from manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject from .._config import config from ..constants import RendererType from ..mobject.mobject import Group, Mobject from ..mobject.types.vectorized_mobject import VGroup, VMobject from .composition import AnimationGroup from .fading import FadeIn, FadeOut from .transform import FadeTransformPieces, Transform if TYPE_CHECKING: from ..scene.scene import Scene class TransformMatchingAbstractBase(AnimationGroup): """Abstract base class for transformations that keep track of matching parts. Subclasses have to implement the two static methods :meth:`~.TransformMatchingAbstractBase.get_mobject_parts` and :meth:`~.TransformMatchingAbstractBase.get_mobject_key`. Basically, this transformation first maps all submobjects returned by the ``get_mobject_parts`` method to certain keys by applying the ``get_mobject_key`` method. Then, submobjects with matching keys are transformed into each other. Parameters ---------- mobject The starting :class:`~.Mobject`. target_mobject The target :class:`~.Mobject`. transform_mismatches Controls whether submobjects without a matching key are transformed into each other by using :class:`~.Transform`. Default: ``False``. fade_transform_mismatches Controls whether submobjects without a matching key are transformed into each other by using :class:`~.FadeTransform`. Default: ``False``. key_map Optional. A dictionary mapping keys belonging to some of the starting mobject's submobjects (i.e., the return values of the ``get_mobject_key`` method) to some keys belonging to the target mobject's submobjects that should be transformed although the keys don't match. kwargs All further keyword arguments are passed to the submobject transformations. Note ---- If neither ``transform_mismatches`` nor ``fade_transform_mismatches`` are set to ``True``, submobjects without matching keys in the starting mobject are faded out in the direction of the unmatched submobjects in the target mobject, and unmatched submobjects in the target mobject are faded in from the direction of the unmatched submobjects in the start mobject. """ def __init__( self, mobject: Mobject, target_mobject: Mobject, transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, **kwargs, ): if isinstance(mobject, OpenGLVMobject): group_type = OpenGLVGroup elif isinstance(mobject, OpenGLMobject): group_type = OpenGLGroup elif isinstance(mobject, VMobject): group_type = VGroup else: group_type = Group source_map = self.get_shape_map(mobject) target_map = self.get_shape_map(target_mobject) if key_map is None: key_map = {} # Create two mobjects whose submobjects all match each other # according to whatever keys are used for source_map and # target_map transform_source = group_type() transform_target = group_type() for key in set(source_map).intersection(target_map): transform_source.add(source_map[key]) transform_target.add(target_map[key]) anims = [Transform(transform_source, transform_target, **kwargs)] # User can manually specify when one part should transform # into another despite not matching by using key_map key_mapped_source = group_type() key_mapped_target = group_type() for key1, key2 in key_map.items(): if key1 in source_map and key2 in target_map: key_mapped_source.add(source_map[key1]) key_mapped_target.add(target_map[key2]) source_map.pop(key1, None) target_map.pop(key2, None) if len(key_mapped_source) > 0: anims.append( FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs), ) fade_source = group_type() fade_target = group_type() for key in set(source_map).difference(target_map): fade_source.add(source_map[key]) for key in set(target_map).difference(source_map): fade_target.add(target_map[key]) fade_target_copy = fade_target.copy() if transform_mismatches: if "replace_mobject_with_target_in_scene" not in kwargs: kwargs["replace_mobject_with_target_in_scene"] = True anims.append(Transform(fade_source, fade_target, **kwargs)) elif fade_transform_mismatches: anims.append(FadeTransformPieces(fade_source, fade_target, **kwargs)) else: anims.append(FadeOut(fade_source, target_position=fade_target, **kwargs)) anims.append( FadeIn(fade_target_copy, target_position=fade_target, **kwargs), ) super().__init__(*anims) self.to_remove = [mobject, fade_target_copy] self.to_add = target_mobject def get_shape_map(self, mobject: Mobject) -> dict: shape_map = {} for sm in self.get_mobject_parts(mobject): key = self.get_mobject_key(sm) if key not in shape_map: if config["renderer"] == RendererType.OPENGL: shape_map[key] = OpenGLVGroup() else: shape_map[key] = VGroup() shape_map[key].add(sm) return shape_map def clean_up_from_scene(self, scene: Scene) -> None: # Interpolate all animations back to 0 to ensure source mobjects remain unchanged. for anim in self.animations: anim.interpolate(0) scene.remove(self.mobject) scene.remove(*self.to_remove) scene.add(self.to_add) @staticmethod def get_mobject_parts(mobject: Mobject): raise NotImplementedError("To be implemented in subclass.") @staticmethod def get_mobject_key(mobject: Mobject): raise NotImplementedError("To be implemented in subclass.") class TransformMatchingShapes(TransformMatchingAbstractBase): """An animation trying to transform groups by matching the shape of their submobjects. Two submobjects match if the hash of their point coordinates after normalization (i.e., after translation to the origin, fixing the submobject height at 1 unit, and rounding the coordinates to three decimal places) matches. See also -------- :class:`~.TransformMatchingAbstractBase` Examples -------- .. manim:: Anagram class Anagram(Scene): def construct(self): src = Text("the morse code") tar = Text("here come dots") self.play(Write(src)) self.wait(0.5) self.play(TransformMatchingShapes(src, tar, path_arc=PI/2)) self.wait(0.5) """ def __init__( self, mobject: Mobject, target_mobject: Mobject, transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, **kwargs, ): super().__init__( mobject, target_mobject, transform_mismatches=transform_mismatches, fade_transform_mismatches=fade_transform_mismatches, key_map=key_map, **kwargs, ) @staticmethod def get_mobject_parts(mobject: Mobject) -> list[Mobject]: return mobject.family_members_with_points() @staticmethod def get_mobject_key(mobject: Mobject) -> int: mobject.save_state() mobject.center() mobject.set(height=1) rounded_points = np.round(mobject.points, 3) + 0.0 result = hash(rounded_points.tobytes()) mobject.restore() return result class TransformMatchingTex(TransformMatchingAbstractBase): """A transformation trying to transform rendered LaTeX strings. Two submobjects match if their ``tex_string`` matches. See also -------- :class:`~.TransformMatchingAbstractBase` Examples -------- .. manim:: MatchingEquationParts class MatchingEquationParts(Scene): def construct(self): variables = VGroup(MathTex("a"), MathTex("b"), MathTex("c")).arrange_submobjects().shift(UP) eq1 = MathTex("{{x}}^2", "+", "{{y}}^2", "=", "{{z}}^2") eq2 = MathTex("{{a}}^2", "+", "{{b}}^2", "=", "{{c}}^2") eq3 = MathTex("{{a}}^2", "=", "{{c}}^2", "-", "{{b}}^2") self.add(eq1) self.wait(0.5) self.play(TransformMatchingTex(Group(eq1, variables), eq2)) self.wait(0.5) self.play(TransformMatchingTex(eq2, eq3)) self.wait(0.5) """ def __init__( self, mobject: Mobject, target_mobject: Mobject, transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, **kwargs, ): super().__init__( mobject, target_mobject, transform_mismatches=transform_mismatches, fade_transform_mismatches=fade_transform_mismatches, key_map=key_map, **kwargs, ) @staticmethod def get_mobject_parts(mobject: Mobject) -> list[Mobject]: if isinstance(mobject, (Group, VGroup, OpenGLGroup, OpenGLVGroup)): return [ p for s in mobject.submobjects for p in TransformMatchingTex.get_mobject_parts(s) ] else: assert hasattr(mobject, "tex_string") return mobject.submobjects @staticmethod def get_mobject_key(mobject: Mobject) -> str: return mobject.tex_string ================================================ FILE: manim/animation/updaters/__init__.py ================================================ """Animations and utility mobjects related to update functions. Modules ======= .. autosummary:: :toctree: ../reference ~mobject_update_utils ~update """ ================================================ FILE: manim/animation/updaters/mobject_update_utils.py ================================================ """Utility functions for continuous animation of mobjects.""" from __future__ import annotations __all__ = [ "assert_is_mobject_method", "always", "f_always", "always_redraw", "always_shift", "always_rotate", "turn_animation_into_updater", "cycle_animation", ] import inspect from collections.abc import Callable from typing import TYPE_CHECKING import numpy as np from manim.constants import DEGREES, RIGHT from manim.mobject.mobject import Mobject from manim.opengl import OpenGLMobject from manim.utils.space_ops import normalize if TYPE_CHECKING: from manim.animation.animation import Animation def assert_is_mobject_method(method: Callable) -> None: assert inspect.ismethod(method) mobject = method.__self__ assert isinstance(mobject, (Mobject, OpenGLMobject)) def always(method: Callable, *args, **kwargs) -> Mobject: assert_is_mobject_method(method) mobject = method.__self__ func = method.__func__ mobject.add_updater(lambda m: func(m, *args, **kwargs)) return mobject def f_always(method: Callable[[Mobject], None], *arg_generators, **kwargs) -> Mobject: """ More functional version of always, where instead of taking in args, it takes in functions which output the relevant arguments. """ assert_is_mobject_method(method) mobject = method.__self__ func = method.__func__ def updater(mob): args = [arg_generator() for arg_generator in arg_generators] func(mob, *args, **kwargs) mobject.add_updater(updater) return mobject def always_redraw(func: Callable[[], Mobject]) -> Mobject: """Redraw the mobject constructed by a function every frame. This function returns a mobject with an attached updater that continuously regenerates the mobject according to the specified function. Parameters ---------- func A function without (required) input arguments that returns a mobject. Examples -------- .. manim:: TangentAnimation class TangentAnimation(Scene): def construct(self): ax = Axes() sine = ax.plot(np.sin, color=RED) alpha = ValueTracker(0) point = always_redraw( lambda: Dot( sine.point_from_proportion(alpha.get_value()), color=BLUE ) ) tangent = always_redraw( lambda: TangentLine( sine, alpha=alpha.get_value(), color=YELLOW, length=4 ) ) self.add(ax, sine, point, tangent) self.play(alpha.animate.set_value(1), rate_func=linear, run_time=2) """ mob = func() mob.add_updater(lambda _: mob.become(func())) return mob def always_shift( mobject: Mobject, direction: np.ndarray[np.float64] = RIGHT, rate: float = 0.1 ) -> Mobject: """A mobject which is continuously shifted along some direction at a certain rate. Parameters ---------- mobject The mobject to shift. direction The direction to shift. The vector is normalized, the specified magnitude is not relevant. rate Length in Manim units which the mobject travels in one second along the specified direction. Examples -------- .. manim:: ShiftingSquare class ShiftingSquare(Scene): def construct(self): sq = Square().set_fill(opacity=1) tri = Triangle() VGroup(sq, tri).arrange(LEFT) # construct a square which is continuously # shifted to the right always_shift(sq, RIGHT, rate=5) self.add(sq) self.play(tri.animate.set_fill(opacity=1)) """ mobject.add_updater(lambda m, dt: m.shift(dt * rate * normalize(direction))) return mobject def always_rotate(mobject: Mobject, rate: float = 20 * DEGREES, **kwargs) -> Mobject: """A mobject which is continuously rotated at a certain rate. Parameters ---------- mobject The mobject to be rotated. rate The angle which the mobject is rotated by over one second. kwags Further arguments to be passed to :meth:`.Mobject.rotate`. Examples -------- .. manim:: SpinningTriangle class SpinningTriangle(Scene): def construct(self): tri = Triangle().set_fill(opacity=1).set_z_index(2) sq = Square().to_edge(LEFT) # will keep spinning while there is an animation going on always_rotate(tri, rate=2*PI, about_point=ORIGIN) self.add(tri, sq) self.play(sq.animate.to_edge(RIGHT), rate_func=linear, run_time=1) """ mobject.add_updater(lambda m, dt: m.rotate(dt * rate, **kwargs)) return mobject def turn_animation_into_updater( animation: Animation, cycle: bool = False, delay: float = 0, **kwargs ) -> Mobject: """ Add an updater to the animation's mobject which applies the interpolation and update functions of the animation If cycle is True, this repeats over and over. Otherwise, the updater will be popped upon completion The ``delay`` parameter is the delay (in seconds) before the animation starts.. Examples -------- .. manim:: WelcomeToManim class WelcomeToManim(Scene): def construct(self): words = Text("Welcome to") banner = ManimBanner().scale(0.5) VGroup(words, banner).arrange(DOWN) turn_animation_into_updater(Write(words, run_time=0.9)) self.add(words) self.wait(0.5) self.play(banner.expand(), run_time=0.5) """ mobject = animation.mobject animation.suspend_mobject_updating = False animation.begin() animation.total_time = -delay def update(m: Mobject, dt: float): if animation.total_time >= 0: run_time = animation.get_run_time() # handle zero/negative runtime safely if run_time <= 0: # instantly snap to final state once, then remove updater animation.interpolate(1) animation.update_mobjects(dt) animation.finish() m.remove_updater(update) return time_ratio = animation.total_time / run_time if cycle: alpha = time_ratio % 1 else: alpha = np.clip(time_ratio, 0, 1) if alpha >= 1: animation.finish() m.remove_updater(update) return animation.interpolate(alpha) animation.update_mobjects(dt) animation.total_time += dt mobject.add_updater(update) return mobject def cycle_animation(animation: Animation, **kwargs) -> Mobject: return turn_animation_into_updater(animation, cycle=True, **kwargs) ================================================ FILE: manim/animation/updaters/update.py ================================================ """Animations that update mobjects.""" from __future__ import annotations __all__ = ["UpdateFromFunc", "UpdateFromAlphaFunc", "MaintainPositionRelativeTo"] import operator as op from collections.abc import Callable from typing import TYPE_CHECKING, Any from manim.animation.animation import Animation if TYPE_CHECKING: from manim.mobject.mobject import Mobject class UpdateFromFunc(Animation): """ update_function of the form func(mobject), presumably to be used when the state of one mobject is dependent on another simultaneously animated mobject """ def __init__( self, mobject: Mobject, update_function: Callable[[Mobject], Any], suspend_mobject_updating: bool = False, **kwargs: Any, ) -> None: self.update_function = update_function super().__init__( mobject, suspend_mobject_updating=suspend_mobject_updating, **kwargs ) def interpolate_mobject(self, alpha: float) -> None: self.update_function(self.mobject) # type: ignore[arg-type] class UpdateFromAlphaFunc(UpdateFromFunc): def interpolate_mobject(self, alpha: float) -> None: self.update_function(self.mobject, self.rate_func(alpha)) # type: ignore[call-arg, arg-type] class MaintainPositionRelativeTo(Animation): def __init__( self, mobject: Mobject, tracked_mobject: Mobject, **kwargs: Any ) -> None: self.tracked_mobject = tracked_mobject self.diff = op.sub( mobject.get_center(), tracked_mobject.get_center(), ) super().__init__(mobject, **kwargs) def interpolate_mobject(self, alpha: float) -> None: target = self.tracked_mobject.get_center() location = self.mobject.get_center() self.mobject.shift(target - location + self.diff) ================================================ FILE: manim/camera/__init__.py ================================================ ================================================ FILE: manim/camera/camera.py ================================================ """A camera converts the mobjects contained in a Scene into an array of pixels.""" from __future__ import annotations __all__ = ["Camera", "BackgroundColoredVMobjectDisplayer"] import copy import itertools as it import operator as op import pathlib from collections.abc import Callable, Iterable from functools import reduce from typing import TYPE_CHECKING, Any, Self import cairo import numpy as np from PIL import Image from manim._config import config, logger from manim.constants import * from manim.mobject.mobject import Mobject from manim.mobject.types.point_cloud_mobject import PMobject from manim.mobject.types.vectorized_mobject import VMobject from manim.utils.color import ManimColor, ParsableManimColor, color_to_int_rgba from manim.utils.family import extract_mobject_family_members from manim.utils.images import get_full_raster_image_path from manim.utils.iterables import list_difference_update from manim.utils.space_ops import cross2d if TYPE_CHECKING: import numpy.typing as npt from manim.mobject.types.image_mobject import AbstractImageMobject from manim.typing import ( FloatRGBA_Array, FloatRGBALike_Array, ManimFloat, ManimInt, PixelArray, Point3D, Point3D_Array, ) LINE_JOIN_MAP = { LineJointType.AUTO: None, # TODO: this could be improved LineJointType.ROUND: cairo.LineJoin.ROUND, LineJointType.BEVEL: cairo.LineJoin.BEVEL, LineJointType.MITER: cairo.LineJoin.MITER, } CAP_STYLE_MAP = { CapStyleType.AUTO: None, # TODO: this could be improved CapStyleType.ROUND: cairo.LineCap.ROUND, CapStyleType.BUTT: cairo.LineCap.BUTT, CapStyleType.SQUARE: cairo.LineCap.SQUARE, } class Camera: """Base camera class. This is the object which takes care of what exactly is displayed on screen at any given moment. Parameters ---------- background_image The path to an image that should be the background image. If not set, the background is filled with :attr:`self.background_color` background What :attr:`background` is set to. By default, ``None``. pixel_height The height of the scene in pixels. pixel_width The width of the scene in pixels. kwargs Additional arguments (``background_color``, ``background_opacity``) to be set. """ def __init__( self, background_image: str | None = None, frame_center: Point3D = ORIGIN, image_mode: str = "RGBA", n_channels: int = 4, pixel_array_dtype: str = "uint8", cairo_line_width_multiple: float = 0.01, use_z_index: bool = True, background: PixelArray | None = None, pixel_height: int | None = None, pixel_width: int | None = None, frame_height: float | None = None, frame_width: float | None = None, frame_rate: float | None = None, background_color: ParsableManimColor | None = None, background_opacity: float | None = None, **kwargs: Any, ) -> None: self.background_image = background_image self.frame_center = frame_center self.image_mode = image_mode self.n_channels = n_channels self.pixel_array_dtype = pixel_array_dtype self.cairo_line_width_multiple = cairo_line_width_multiple self.use_z_index = use_z_index self.background = background self.background_colored_vmobject_displayer: ( BackgroundColoredVMobjectDisplayer | None ) = None if pixel_height is None: pixel_height = config["pixel_height"] self.pixel_height = pixel_height if pixel_width is None: pixel_width = config["pixel_width"] self.pixel_width = pixel_width if frame_height is None: frame_height = config["frame_height"] self.frame_height = frame_height if frame_width is None: frame_width = config["frame_width"] self.frame_width = frame_width if frame_rate is None: frame_rate = config["frame_rate"] self.frame_rate = frame_rate if background_color is None: self._background_color: ManimColor = ManimColor.parse( config["background_color"] ) else: self._background_color = ManimColor.parse(background_color) if background_opacity is None: self._background_opacity: float = config["background_opacity"] else: self._background_opacity = background_opacity # This one is in the same boat as the above, but it doesn't have the # same name as the corresponding key so it has to be handled on its own self.max_allowable_norm = config["frame_width"] self.rgb_max_val = np.iinfo(self.pixel_array_dtype).max self.pixel_array_to_cairo_context: dict[int, cairo.Context] = {} # Contains the correct method to process a list of Mobjects of the # corresponding class. If a Mobject is not an instance of a class in # this dict (or an instance of a class that inherits from a class in # this dict), then it cannot be rendered. self.init_background() self.resize_frame_shape() self.reset() def __deepcopy__(self, memo: Any) -> Camera: # This is to address a strange bug where deepcopying # will result in a segfault, which is somehow related # to the aggdraw library self.canvas = None return copy.copy(self) @property def background_color(self) -> ManimColor: return self._background_color @background_color.setter def background_color(self, color: ManimColor) -> None: self._background_color = color self.init_background() @property def background_opacity(self) -> float: return self._background_opacity @background_opacity.setter def background_opacity(self, alpha: float) -> None: self._background_opacity = alpha self.init_background() def type_or_raise( self, mobject: Mobject ) -> type[VMobject] | type[PMobject] | type[AbstractImageMobject] | type[Mobject]: """Return the type of mobject, if it is a type that can be rendered. If `mobject` is an instance of a class that inherits from a class that can be rendered, return the super class. For example, an instance of a Square is also an instance of VMobject, and these can be rendered. Therefore, `type_or_raise(Square())` returns True. Parameters ---------- mobject The object to take the type of. Notes ----- For a list of classes that can currently be rendered, see :meth:`display_funcs`. Returns ------- Type[:class:`~.Mobject`] The type of mobjects, if it can be rendered. Raises ------ :exc:`TypeError` When mobject is not an instance of a class that can be rendered. """ from ..mobject.types.image_mobject import AbstractImageMobject self.display_funcs: dict[ type[Mobject], Callable[[list[Mobject], PixelArray], Any] ] = { VMobject: self.display_multiple_vectorized_mobjects, # type: ignore[dict-item] PMobject: self.display_multiple_point_cloud_mobjects, # type: ignore[dict-item] AbstractImageMobject: self.display_multiple_image_mobjects, # type: ignore[dict-item] Mobject: lambda batch, pa: batch, # Do nothing } # We have to check each type in turn because we are dealing with # super classes. For example, if square = Square(), then # type(square) != VMobject, but isinstance(square, VMobject) == True. for _type in self.display_funcs: if isinstance(mobject, _type): return _type raise TypeError(f"Displaying an object of class {_type} is not supported") def reset_pixel_shape(self, new_height: float, new_width: float) -> None: """This method resets the height and width of a single pixel to the passed new_height and new_width. Parameters ---------- new_height The new height of the entire scene in pixels new_width The new width of the entire scene in pixels """ self.pixel_width = new_width self.pixel_height = new_height self.init_background() self.resize_frame_shape() self.reset() def resize_frame_shape(self, fixed_dimension: int = 0) -> None: """ Changes frame_shape to match the aspect ratio of the pixels, where fixed_dimension determines whether frame_height or frame_width remains fixed while the other changes accordingly. Parameters ---------- fixed_dimension If 0, height is scaled with respect to width else, width is scaled with respect to height. """ pixel_height = self.pixel_height pixel_width = self.pixel_width frame_height = self.frame_height frame_width = self.frame_width aspect_ratio = pixel_width / pixel_height if fixed_dimension == 0: frame_height = frame_width / aspect_ratio else: frame_width = aspect_ratio * frame_height self.frame_height = frame_height self.frame_width = frame_width def init_background(self) -> None: """Initialize the background. If self.background_image is the path of an image the image is set as background; else, the default background color fills the background. """ height = self.pixel_height width = self.pixel_width if self.background_image is not None: path = get_full_raster_image_path(self.background_image) image = Image.open(path).convert(self.image_mode) # TODO, how to gracefully handle backgrounds # with different sizes? self.background = np.array(image)[:height, :width] self.background = self.background.astype(self.pixel_array_dtype) else: background_rgba = color_to_int_rgba( self.background_color, self.background_opacity, ) self.background = np.zeros( (height, width, self.n_channels), dtype=self.pixel_array_dtype, ) self.background[:, :] = background_rgba def get_image( self, pixel_array: PixelArray | list | tuple | None = None ) -> Image.Image: """Returns an image from the passed pixel array, or from the current frame if the passed pixel array is none. Parameters ---------- pixel_array The pixel array from which to get an image, by default None Returns ------- PIL.Image.Image The PIL image of the array. """ if pixel_array is None: pixel_array = self.pixel_array return Image.fromarray(pixel_array, mode=self.image_mode) def convert_pixel_array( self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False ) -> PixelArray: """Converts a pixel array from values that have floats in then to proper RGB values. Parameters ---------- pixel_array Pixel array to convert. convert_from_floats Whether or not to convert float values to ints, by default False Returns ------- np.array The new, converted pixel array. """ retval = np.array(pixel_array) if convert_from_floats: retval = np.apply_along_axis( lambda f: (f * self.rgb_max_val).astype(self.pixel_array_dtype), 2, retval, ) return retval def set_pixel_array( self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False ) -> None: """Sets the pixel array of the camera to the passed pixel array. Parameters ---------- pixel_array The pixel array to convert and then set as the camera's pixel array. convert_from_floats Whether or not to convert float values to proper RGB values, by default False """ converted_array: PixelArray = self.convert_pixel_array( pixel_array, convert_from_floats ) if not ( hasattr(self, "pixel_array") and self.pixel_array.shape == converted_array.shape ): self.pixel_array: PixelArray = converted_array else: # Set in place self.pixel_array[:, :, :] = converted_array[:, :, :] def set_background( self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False ) -> None: """Sets the background to the passed pixel_array after converting to valid RGB values. Parameters ---------- pixel_array The pixel array to set the background to. convert_from_floats Whether or not to convert floats values to proper RGB valid ones, by default False """ self.background = self.convert_pixel_array(pixel_array, convert_from_floats) # TODO, this should live in utils, not as a method of Camera def make_background_from_func( self, coords_to_colors_func: Callable[[np.ndarray], np.ndarray] ) -> PixelArray: """ Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats. Parameters ---------- coords_to_colors_func The function whose input is an (x,y) pair of coordinates and whose return values must be the colors for that point Returns ------- np.array The pixel array which can then be passed to set_background. """ logger.info("Starting set_background") coords = self.get_coords_of_all_pixels() new_background = np.apply_along_axis(coords_to_colors_func, 2, coords) logger.info("Ending set_background") return self.convert_pixel_array(new_background, convert_from_floats=True) def set_background_from_func( self, coords_to_colors_func: Callable[[np.ndarray], np.ndarray] ) -> None: """ Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats. Parameters ---------- coords_to_colors_func The function whose input is an (x,y) pair of coordinates and whose return values must be the colors for that point """ self.set_background(self.make_background_from_func(coords_to_colors_func)) def reset(self) -> Self: """Resets the camera's pixel array to that of the background Returns ------- Camera The camera object after setting the pixel array. """ self.set_pixel_array(self.background) return self def set_frame_to_background(self, background: PixelArray) -> None: self.set_pixel_array(background) #### def get_mobjects_to_display( self, mobjects: Iterable[Mobject], include_submobjects: bool = True, excluded_mobjects: list | None = None, ) -> list[Mobject]: """Used to get the list of mobjects to display with the camera. Parameters ---------- mobjects The Mobjects include_submobjects Whether or not to include the submobjects of mobjects, by default True excluded_mobjects Any mobjects to exclude, by default None Returns ------- list list of mobjects """ if include_submobjects: mobjects = extract_mobject_family_members( mobjects, use_z_index=self.use_z_index, only_those_with_points=True, ) if excluded_mobjects: all_excluded = extract_mobject_family_members( excluded_mobjects, use_z_index=self.use_z_index, ) mobjects = list_difference_update(mobjects, all_excluded) return list(mobjects) def is_in_frame(self, mobject: Mobject) -> bool: """Checks whether the passed mobject is in frame or not. Parameters ---------- mobject The mobject for which the checking needs to be done. Returns ------- bool True if in frame, False otherwise. """ fc = self.frame_center fh = self.frame_height fw = self.frame_width return not reduce( op.or_, [ mobject.get_right()[0] < fc[0] - fw / 2, mobject.get_bottom()[1] > fc[1] + fh / 2, mobject.get_left()[0] > fc[0] + fw / 2, mobject.get_top()[1] < fc[1] - fh / 2, ], ) def capture_mobject(self, mobject: Mobject, **kwargs: Any) -> None: """Capture mobjects by storing it in :attr:`pixel_array`. This is a single-mobject version of :meth:`capture_mobjects`. Parameters ---------- mobject Mobject to capture. kwargs Keyword arguments to be passed to :meth:`get_mobjects_to_display`. """ return self.capture_mobjects([mobject], **kwargs) def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None: """Capture mobjects by printing them on :attr:`pixel_array`. This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video. Parameters ---------- mobjects Mobjects to capture. kwargs Keyword arguments to be passed to :meth:`get_mobjects_to_display`. Notes ----- For a list of classes that can currently be rendered, see :meth:`display_funcs`. """ # The mobjects will be processed in batches (or runs) of mobjects of # the same type. That is, if the list mobjects contains objects of # types [VMobject, VMobject, VMobject, PMobject, PMobject, VMobject], # then they will be captured in three batches: [VMobject, VMobject, # VMobject], [PMobject, PMobject], and [VMobject]. This must be done # without altering their order. it.groupby computes exactly this # partition while at the same time preserving order. mobjects = self.get_mobjects_to_display(mobjects, **kwargs) for group_type, group in it.groupby(mobjects, self.type_or_raise): self.display_funcs[group_type](list(group), self.pixel_array) # Methods associated with svg rendering # NOTE: None of the methods below have been mentioned outside of their definitions. Their DocStrings are not as # detailed as possible. def get_cached_cairo_context(self, pixel_array: PixelArray) -> cairo.Context | None: """Returns the cached cairo context of the passed pixel array if it exists, and None if it doesn't. Parameters ---------- pixel_array The pixel array to check. Returns ------- cairo.Context The cached cairo context. """ return self.pixel_array_to_cairo_context.get(id(pixel_array), None) def cache_cairo_context(self, pixel_array: PixelArray, ctx: cairo.Context) -> None: """Caches the passed Pixel array into a Cairo Context Parameters ---------- pixel_array The pixel array to cache ctx The context to cache it into. """ self.pixel_array_to_cairo_context[id(pixel_array)] = ctx def get_cairo_context(self, pixel_array: PixelArray) -> cairo.Context: """Returns the cairo context for a pixel array after caching it to self.pixel_array_to_cairo_context If that array has already been cached, it returns the cached version instead. Parameters ---------- pixel_array The Pixel array to get the cairo context of. Returns ------- cairo.Context The cairo context of the pixel array. """ cached_ctx = self.get_cached_cairo_context(pixel_array) if cached_ctx: return cached_ctx pw = self.pixel_width ph = self.pixel_height fw = self.frame_width fh = self.frame_height fc = self.frame_center surface = cairo.ImageSurface.create_for_data( pixel_array.data, cairo.FORMAT_ARGB32, pw, ph, ) ctx = cairo.Context(surface) ctx.scale(pw, ph) ctx.set_matrix( cairo.Matrix( (pw / fw), 0, 0, -(ph / fh), (pw / 2) - fc[0] * (pw / fw), (ph / 2) + fc[1] * (ph / fh), ), ) self.cache_cairo_context(pixel_array, ctx) return ctx def display_multiple_vectorized_mobjects( self, vmobjects: list[VMobject], pixel_array: PixelArray ) -> None: """Displays multiple VMobjects in the pixel_array Parameters ---------- vmobjects list of VMobjects to display pixel_array The pixel array """ if len(vmobjects) == 0: return batch_image_pairs = it.groupby(vmobjects, lambda vm: vm.get_background_image()) for image, batch in batch_image_pairs: if image: self.display_multiple_background_colored_vmobjects(batch, pixel_array) else: self.display_multiple_non_background_colored_vmobjects( batch, pixel_array, ) def display_multiple_non_background_colored_vmobjects( self, vmobjects: Iterable[VMobject], pixel_array: PixelArray ) -> None: """Displays multiple VMobjects in the cairo context, as long as they don't have background colors. Parameters ---------- vmobjects list of the VMobjects pixel_array The Pixel array to add the VMobjects to. """ ctx = self.get_cairo_context(pixel_array) for vmobject in vmobjects: self.display_vectorized(vmobject, ctx) def display_vectorized(self, vmobject: VMobject, ctx: cairo.Context) -> Self: """Displays a VMobject in the cairo context Parameters ---------- vmobject The Vectorized Mobject to display ctx The cairo context to use. Returns ------- Camera The camera object """ self.set_cairo_context_path(ctx, vmobject) self.apply_stroke(ctx, vmobject, background=True) self.apply_fill(ctx, vmobject) self.apply_stroke(ctx, vmobject) return self def set_cairo_context_path(self, ctx: cairo.Context, vmobject: VMobject) -> Self: """Sets a path for the cairo context with the vmobject passed Parameters ---------- ctx The cairo context vmobject The VMobject Returns ------- Camera Camera object after setting cairo_context_path """ points = self.transform_points_pre_display(vmobject, vmobject.points) # TODO, shouldn't this be handled in transform_points_pre_display? # points = points - self.get_frame_center() if len(points) == 0: return self ctx.new_path() subpaths = vmobject.gen_subpaths_from_points_2d(points) for subpath in subpaths: quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath) ctx.new_sub_path() start = subpath[0] ctx.move_to(*start[:2]) for _p0, p1, p2, p3 in quads: ctx.curve_to(*p1[:2], *p2[:2], *p3[:2]) if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): ctx.close_path() return self def set_cairo_context_color( self, ctx: cairo.Context, rgbas: FloatRGBALike_Array, vmobject: VMobject ) -> Self: """Sets the color of the cairo context Parameters ---------- ctx The cairo context rgbas The RGBA array with which to color the context. vmobject The VMobject with which to set the color. Returns ------- Camera The camera object """ if len(rgbas) == 1: # Use reversed rgb because cairo surface is # encodes it in reverse order ctx.set_source_rgba(*rgbas[0][2::-1], rgbas[0][3]) else: points = vmobject.get_gradient_start_and_end_points() points = self.transform_points_pre_display(vmobject, points) pat = cairo.LinearGradient(*it.chain(*(point[:2] for point in points))) offsets = np.linspace(0, 1, len(rgbas)) for rgba, offset in zip(rgbas, offsets, strict=True): pat.add_color_stop_rgba(offset, *rgba[2::-1], rgba[3]) ctx.set_source(pat) return self def apply_fill(self, ctx: cairo.Context, vmobject: VMobject) -> Self: """Fills the cairo context Parameters ---------- ctx The cairo context vmobject The VMobject Returns ------- Camera The camera object. """ self.set_cairo_context_color(ctx, self.get_fill_rgbas(vmobject), vmobject) ctx.fill_preserve() return self def apply_stroke( self, ctx: cairo.Context, vmobject: VMobject, background: bool = False ) -> Self: """Applies a stroke to the VMobject in the cairo context. Parameters ---------- ctx The cairo context vmobject The VMobject background Whether or not to consider the background when applying this stroke width, by default False Returns ------- Camera The camera object with the stroke applied. """ width = vmobject.get_stroke_width(background) if width == 0: return self self.set_cairo_context_color( ctx, self.get_stroke_rgbas(vmobject, background=background), vmobject, ) ctx.set_line_width( width * self.cairo_line_width_multiple * (self.frame_width / self.frame_width), # This ensures lines have constant width as you zoom in on them. ) if vmobject.joint_type != LineJointType.AUTO: ctx.set_line_join(LINE_JOIN_MAP[vmobject.joint_type]) if vmobject.cap_style != CapStyleType.AUTO: ctx.set_line_cap(CAP_STYLE_MAP[vmobject.cap_style]) ctx.stroke_preserve() return self def get_stroke_rgbas( self, vmobject: VMobject, background: bool = False ) -> FloatRGBA_Array: """Gets the RGBA array for the stroke of the passed VMobject. Parameters ---------- vmobject The VMobject background Whether or not to consider the background when getting the stroke RGBAs, by default False Returns ------- np.ndarray The RGBA array of the stroke. """ return vmobject.get_stroke_rgbas(background) def get_fill_rgbas(self, vmobject: VMobject) -> FloatRGBA_Array: """Returns the RGBA array of the fill of the passed VMobject Parameters ---------- vmobject The VMobject Returns ------- np.array The RGBA Array of the fill of the VMobject """ return vmobject.get_fill_rgbas() def get_background_colored_vmobject_displayer( self, ) -> BackgroundColoredVMobjectDisplayer: """Returns the background_colored_vmobject_displayer if it exists or makes one and returns it if not. Returns ------- BackgroundColoredVMobjectDisplayer Object that displays VMobjects that have the same color as the background. """ if self.background_colored_vmobject_displayer is None: self.background_colored_vmobject_displayer = ( BackgroundColoredVMobjectDisplayer(self) ) return self.background_colored_vmobject_displayer def display_multiple_background_colored_vmobjects( self, cvmobjects: Iterable[VMobject], pixel_array: PixelArray ) -> Self: """Displays multiple vmobjects that have the same color as the background. Parameters ---------- cvmobjects List of Colored VMobjects pixel_array The pixel array. Returns ------- Camera The camera object. """ displayer = self.get_background_colored_vmobject_displayer() cvmobject_pixel_array = displayer.display(*cvmobjects) self.overlay_rgba_array(pixel_array, cvmobject_pixel_array) return self # Methods for other rendering # NOTE: Out of the following methods, only `transform_points_pre_display` and `points_to_pixel_coords` have been mentioned outside of their definitions. # As a result, the other methods do not have as detailed docstrings as would be preferred. def display_multiple_point_cloud_mobjects( self, pmobjects: Iterable[PMobject], pixel_array: PixelArray ) -> None: """Displays multiple PMobjects by modifying the passed pixel array. Parameters ---------- pmobjects List of PMobjects pixel_array The pixel array to modify. """ for pmobject in pmobjects: self.display_point_cloud( pmobject, pmobject.points, pmobject.rgbas, self.adjusted_thickness(pmobject.stroke_width), pixel_array, ) def display_point_cloud( self, pmobject: PMobject, points: Point3D_Array, rgbas: FloatRGBA_Array, thickness: float, pixel_array: PixelArray, ) -> None: """Displays a PMobject by modifying the pixel array suitably. TODO: Write a description for the rgbas argument. Parameters ---------- pmobject Point Cloud Mobject points The points to display in the point cloud mobject rgbas thickness The thickness of each point of the PMobject pixel_array The pixel array to modify. """ if len(points) == 0: return pixel_coords = self.points_to_pixel_coords(pmobject, points) pixel_coords = self.thickened_coordinates(pixel_coords, thickness) rgba_len = pixel_array.shape[2] rgbas = (self.rgb_max_val * rgbas).astype(self.pixel_array_dtype) target_len = len(pixel_coords) factor = target_len // len(rgbas) rgbas = np.array([rgbas] * factor).reshape((target_len, rgba_len)) on_screen_indices = self.on_screen_pixels(pixel_coords) pixel_coords = pixel_coords[on_screen_indices] rgbas = rgbas[on_screen_indices] ph = self.pixel_height pw = self.pixel_width flattener = np.array([1, pw], dtype="int") flattener = flattener.reshape((2, 1)) indices = np.dot(pixel_coords, flattener)[:, 0] indices = indices.astype("int") new_pa = pixel_array.reshape((ph * pw, rgba_len)) new_pa[indices] = rgbas pixel_array[:, :] = new_pa.reshape((ph, pw, rgba_len)) def display_multiple_image_mobjects( self, image_mobjects: Iterable[AbstractImageMobject], pixel_array: PixelArray, ) -> None: """Displays multiple image mobjects by modifying the passed pixel_array. Parameters ---------- image_mobjects list of ImageMobjects pixel_array The pixel array to modify. """ for image_mobject in image_mobjects: self.display_image_mobject(image_mobject, pixel_array) def display_image_mobject( self, image_mobject: AbstractImageMobject, pixel_array: np.ndarray ) -> None: """Display an :class:`~.ImageMobject` by changing the ``pixel_array`` suitably. Parameters ---------- image_mobject The :class:`~.ImageMobject` to display. pixel_array The pixel array to put the :class:`~.ImageMobject` in. """ sub_image = Image.fromarray(image_mobject.get_pixel_array(), mode="RGBA") original_coords = np.array( [ [0, 0], [sub_image.width, 0], [0, sub_image.height], [sub_image.width, sub_image.height], ] ) target_coords = self.points_to_subpixel_coords( image_mobject, image_mobject.points ) int_target_coords = target_coords.astype(np.int64) # Temporarily translate target coords to upper left corner to calculate the # smallest possible size for the target image. shift_vector = np.array( [ min(*[x for x, y in int_target_coords]), min(*[y for x, y in int_target_coords]), ] ) target_coords -= shift_vector int_target_coords -= shift_vector target_size = ( max(*[x for x, y in int_target_coords]), max(*[y for x, y in int_target_coords]), ) # Check that the quadrilateral of the transformed image can actually contain any # pixels by checking that its height from the longest side is longer than 0.5 pixels. # If it's not, do not render the image. Otherwise, the perspective transform # coefficients below might have broken values due to the extreme distortion (for # example, when the image is perpendicular to the camera). ordered_vertices = [target_coords[i] for i in (0, 1, 3, 2)] sides = [ordered_vertices[(i + 1) % 4] - ordered_vertices[i] for i in range(4)] side_lengths_in_pixels = np.linalg.norm(sides, axis=1) longest_side_index = np.argmax(side_lengths_in_pixels) longest_side = sides[longest_side_index] longest_side_length_in_pixels = side_lengths_in_pixels[longest_side_index] if longest_side_length_in_pixels == 0: return previous_side = sides[(longest_side_index - 1) % 4] next_side = sides[(longest_side_index - 1) % 4] # height = area / base h1 = abs(cross2d(longest_side, previous_side)) / longest_side_length_in_pixels h2 = abs(cross2d(longest_side, next_side)) / longest_side_length_in_pixels height_from_longest_side_in_pixels = max(h1, h2) if height_from_longest_side_in_pixels < 0.5: return # Use PIL.Image.Image.transform() to apply a perspective transform to the image. # The transform coefficients must be calculated. The following is adapted from: # https://pc-pillow.readthedocs.io/en/latest/Image_class/Image_transform.html#transform-perspective-coefficients # https://stackoverflow.com/questions/14177744/how-does-perspective-transformation-work-in-pil # The derivation can be found here: # https://web.archive.org/web/20150222120106/xenia.media.mit.edu/~cwren/interpolator/ homography_matrix = [] for (x, y), (X, Y) in zip(target_coords, original_coords, strict=True): homography_matrix.append([x, y, 1, 0, 0, 0, -X * x, -X * y]) homography_matrix.append([0, 0, 0, x, y, 1, -Y * x, -Y * y]) A = np.array(homography_matrix, dtype=np.float64) b = original_coords.reshape(8).astype(np.float64) try: transform_coefficients = np.linalg.solve(A, b) except np.linalg.LinAlgError: # The matrix A might be singular if three points are collinear. # In this case, do nothing and return. return sub_image = sub_image.transform( size=target_size, # Use the smallest possible size for speed. method=Image.Transform.PERSPECTIVE, data=transform_coefficients, resample=image_mobject.resampling_algorithm, ) # Paste into an image as large as the camera's pixel array. full_image = Image.fromarray( np.zeros((self.pixel_height, self.pixel_width)), mode="RGBA", ) full_image.paste( sub_image, box=( shift_vector[0], shift_vector[1], shift_vector[0] + target_size[0], shift_vector[1] + target_size[1], ), ) # Paint on top of existing pixel array. self.overlay_PIL_image(pixel_array, full_image) def overlay_rgba_array( self, pixel_array: np.ndarray, new_array: np.ndarray ) -> None: """Overlays an RGBA array on top of the given Pixel array. Parameters ---------- pixel_array The original pixel array to modify. new_array The new pixel array to overlay. """ self.overlay_PIL_image(pixel_array, self.get_image(new_array)) def overlay_PIL_image(self, pixel_array: np.ndarray, image: Image) -> None: """Overlays a PIL image on the passed pixel array. Parameters ---------- pixel_array The Pixel array image The Image to overlay. """ pixel_array[:, :] = np.array( Image.alpha_composite(self.get_image(pixel_array), image), dtype="uint8", ) def adjust_out_of_range_points(self, points: np.ndarray) -> np.ndarray: """If any of the points in the passed array are out of the viable range, they are adjusted suitably. Parameters ---------- points The points to adjust Returns ------- np.array The adjusted points. """ if not np.any(points > self.max_allowable_norm): return points norms = np.apply_along_axis(np.linalg.norm, 1, points) violator_indices = norms > self.max_allowable_norm violators = points[violator_indices, :] violator_norms = norms[violator_indices] reshaped_norms = np.repeat( violator_norms.reshape((len(violator_norms), 1)), points.shape[1], 1, ) rescaled = self.max_allowable_norm * violators / reshaped_norms points[violator_indices] = rescaled return points def transform_points_pre_display( self, mobject: Mobject, points: Point3D_Array, ) -> Point3D_Array: # TODO: Write more detailed docstrings for this method. # NOTE: There seems to be an unused argument `mobject`. # Subclasses (like ThreeDCamera) may want to # adjust points further before they're shown if not np.all(np.isfinite(points)): # TODO, print some kind of warning about # mobject having invalid points? points = np.zeros((1, 3)) return points def points_to_subpixel_coords( self, mobject: Mobject, points: Point3D_Array, ) -> npt.NDArray[ ManimFloat ]: # TODO: Write more detailed docstrings for this method. points = self.transform_points_pre_display(mobject, points) shifted_points = points - self.frame_center result = np.zeros((len(points), 2)) pixel_height = self.pixel_height pixel_width = self.pixel_width frame_height = self.frame_height frame_width = self.frame_width width_mult = pixel_width / frame_width width_add = pixel_width / 2 height_mult = pixel_height / frame_height height_add = pixel_height / 2 # Flip on y-axis as you go height_mult *= -1 result[:, 0] = shifted_points[:, 0] * width_mult + width_add result[:, 1] = shifted_points[:, 1] * height_mult + height_add return result def points_to_pixel_coords( self, mobject: Mobject, points: Point3D_Array, ) -> npt.NDArray[ManimInt]: # TODO: Write more detailed docstrings for this method. return self.points_to_subpixel_coords(mobject, points).astype(np.int64) def on_screen_pixels(self, pixel_coords: np.ndarray) -> PixelArray: """Returns array of pixels that are on the screen from a given array of pixel_coordinates Parameters ---------- pixel_coords The pixel coords to check. Returns ------- np.array The pixel coords on screen. """ return reduce( op.and_, [ pixel_coords[:, 0] >= 0, pixel_coords[:, 0] < self.pixel_width, pixel_coords[:, 1] >= 0, pixel_coords[:, 1] < self.pixel_height, ], ) def adjusted_thickness(self, thickness: float) -> float: """Computes the adjusted stroke width for a zoomed camera. Parameters ---------- thickness The stroke width of a mobject. Returns ------- float The adjusted stroke width that reflects zooming in with the camera. """ # TODO: This seems...unsystematic big_sum: float = op.add(config["pixel_height"], config["pixel_width"]) this_sum: float = op.add(self.pixel_height, self.pixel_width) factor = big_sum / this_sum return 1 + (thickness - 1) * factor def get_thickening_nudges(self, thickness: float) -> PixelArray: """Determine a list of vectors used to nudge two-dimensional pixel coordinates. Parameters ---------- thickness Returns ------- np.array """ thickness = int(thickness) _range = list(range(-thickness // 2 + 1, thickness // 2 + 1)) return np.array(list(it.product(_range, _range))) def thickened_coordinates( self, pixel_coords: np.ndarray, thickness: float ) -> PixelArray: """Returns thickened coordinates for a passed array of pixel coords and a thickness to thicken by. Parameters ---------- pixel_coords Pixel coordinates thickness Thickness Returns ------- np.array Array of thickened pixel coords. """ nudges = self.get_thickening_nudges(thickness) pixel_coords = np.array([pixel_coords + nudge for nudge in nudges]) size = pixel_coords.size return pixel_coords.reshape((size // 2, 2)) # TODO, reimplement using cairo matrix def get_coords_of_all_pixels(self) -> PixelArray: """Returns the cartesian coordinates of each pixel. Returns ------- np.ndarray The array of cartesian coordinates. """ # These are in x, y order, to help me keep things straight full_space_dims = np.array([self.frame_width, self.frame_height]) full_pixel_dims = np.array([self.pixel_width, self.pixel_height]) # These are addressed in the same y, x order as in pixel_array, but the values in them # are listed in x, y order uncentered_pixel_coords = np.indices([self.pixel_height, self.pixel_width])[ ::-1 ].transpose(1, 2, 0) uncentered_space_coords = ( uncentered_pixel_coords * full_space_dims ) / full_pixel_dims # Could structure above line's computation slightly differently, but figured (without much # thought) multiplying by frame_shape first, THEN dividing by pixel_shape, is probably # better than the other order, for avoiding underflow quantization in the division (whereas # overflow is unlikely to be a problem) centered_space_coords = uncentered_space_coords - (full_space_dims / 2) # Have to also flip the y coordinates to account for pixel array being listed in # top-to-bottom order, opposite of screen coordinate convention centered_space_coords = centered_space_coords * (1, -1) return centered_space_coords # NOTE: The methods of the following class have not been mentioned outside of their definitions. # Their DocStrings are not as detailed as preferred. class BackgroundColoredVMobjectDisplayer: """Auxiliary class that handles displaying vectorized mobjects with a set background image. Parameters ---------- camera Camera object to use. """ def __init__(self, camera: Camera): self.camera = camera self.file_name_to_pixel_array_map: dict[str, PixelArray] = {} self.pixel_array = np.array(camera.pixel_array) self.reset_pixel_array() def reset_pixel_array(self) -> None: self.pixel_array[:, :] = 0 def resize_background_array( self, background_array: PixelArray, new_width: float, new_height: float, mode: str = "RGBA", ) -> PixelArray: """Resizes the pixel array representing the background. Parameters ---------- background_array The pixel new_width The new width of the background new_height The new height of the background mode The PIL image mode, by default "RGBA" Returns ------- np.array The numpy pixel array of the resized background. """ image = Image.fromarray(background_array) image = image.convert(mode) resized_image = image.resize((new_width, new_height)) return np.array(resized_image) def resize_background_array_to_match( self, background_array: PixelArray, pixel_array: PixelArray ) -> PixelArray: """Resizes the background array to match the passed pixel array. Parameters ---------- background_array The prospective pixel array. pixel_array The pixel array whose width and height should be matched. Returns ------- np.array The resized background array. """ height, width = pixel_array.shape[:2] mode = "RGBA" if pixel_array.shape[2] == 4 else "RGB" return self.resize_background_array(background_array, width, height, mode) def get_background_array( self, image: Image.Image | pathlib.Path | str ) -> PixelArray: """Gets the background array that has the passed file_name. Parameters ---------- image The background image or its file name. Returns ------- np.ndarray The pixel array of the image. """ image_key = str(image) if image_key in self.file_name_to_pixel_array_map: return self.file_name_to_pixel_array_map[image_key] if isinstance(image, str): full_path = get_full_raster_image_path(image) image = Image.open(full_path) back_array = np.array(image) pixel_array = self.pixel_array if not np.all(pixel_array.shape == back_array.shape): back_array = self.resize_background_array_to_match(back_array, pixel_array) self.file_name_to_pixel_array_map[image_key] = back_array return back_array def display(self, *cvmobjects: VMobject) -> PixelArray | None: """Displays the colored VMobjects. Parameters ---------- *cvmobjects The VMobjects Returns ------- np.array The pixel array with the `cvmobjects` displayed. """ batch_image_pairs = it.groupby(cvmobjects, lambda cv: cv.get_background_image()) curr_array = None for image, batch in batch_image_pairs: background_array = self.get_background_array(image) pixel_array = self.pixel_array self.camera.display_multiple_non_background_colored_vmobjects( batch, pixel_array, ) new_array = np.array( (background_array * pixel_array.astype("float") / 255), dtype=self.camera.pixel_array_dtype, ) if curr_array is None: curr_array = new_array else: curr_array = np.maximum(curr_array, new_array) self.reset_pixel_array() return curr_array ================================================ FILE: manim/camera/mapping_camera.py ================================================ """A camera module that supports spatial mapping between objects for distortion effects.""" from __future__ import annotations __all__ = ["MappingCamera", "OldMultiCamera", "SplitScreenCamera"] import math import numpy as np from ..camera.camera import Camera from ..mobject.types.vectorized_mobject import VMobject from ..utils.config_ops import DictAsObject # TODO: Add an attribute to mobjects under which they can specify that they should just # map their centers but remain otherwise undistorted (useful for labels, etc.) class MappingCamera(Camera): """Parameters ---------- mapping_func : callable Function to map 3D points to new 3D points (identity by default). min_num_curves : int Minimum number of curves for VMobjects to avoid visual glitches. allow_object_intrusion : bool If True, modifies original mobjects; else works on copies. kwargs : dict Additional arguments passed to Camera base class. """ def __init__( self, mapping_func=lambda p: p, min_num_curves=50, allow_object_intrusion=False, **kwargs, ): self.mapping_func = mapping_func self.min_num_curves = min_num_curves self.allow_object_intrusion = allow_object_intrusion super().__init__(**kwargs) def points_to_pixel_coords(self, mobject, points): # Map points with custom function before converting to pixels return super().points_to_pixel_coords( mobject, np.apply_along_axis(self.mapping_func, 1, points), ) def capture_mobjects(self, mobjects, **kwargs): """Capture mobjects for rendering after applying the spatial mapping. Copies mobjects unless intrusion is allowed, and ensures vector objects have enough curves for smooth distortion. """ mobjects = self.get_mobjects_to_display(mobjects, **kwargs) if self.allow_object_intrusion: mobject_copies = mobjects else: mobject_copies = [mobject.copy() for mobject in mobjects] for mobject in mobject_copies: if ( isinstance(mobject, VMobject) and 0 < mobject.get_num_curves() < self.min_num_curves ): mobject.insert_n_curves(self.min_num_curves) super().capture_mobjects( mobject_copies, include_submobjects=False, excluded_mobjects=None, ) # Note: This allows layering of multiple cameras onto the same portion of the pixel array, # the later cameras overwriting the former # # TODO: Add optional separator borders between cameras (or perhaps peel this off into a # CameraPlusOverlay class) # TODO, the classes below should likely be deleted class OldMultiCamera(Camera): """Parameters ---------- cameras_with_start_positions : tuple Tuples of (Camera, (start_y, start_x)) indicating camera and its pixel offset on the final frame. """ def __init__(self, *cameras_with_start_positions, **kwargs): self.shifted_cameras = [ DictAsObject( { "camera": camera_with_start_positions[0], "start_x": camera_with_start_positions[1][1], "start_y": camera_with_start_positions[1][0], "end_x": camera_with_start_positions[1][1] + camera_with_start_positions[0].pixel_width, "end_y": camera_with_start_positions[1][0] + camera_with_start_positions[0].pixel_height, }, ) for camera_with_start_positions in cameras_with_start_positions ] super().__init__(**kwargs) def capture_mobjects(self, mobjects, **kwargs): for shifted_camera in self.shifted_cameras: shifted_camera.camera.capture_mobjects(mobjects, **kwargs) self.pixel_array[ shifted_camera.start_y : shifted_camera.end_y, shifted_camera.start_x : shifted_camera.end_x, ] = shifted_camera.camera.pixel_array def set_background(self, pixel_array, **kwargs): for shifted_camera in self.shifted_cameras: shifted_camera.camera.set_background( pixel_array[ shifted_camera.start_y : shifted_camera.end_y, shifted_camera.start_x : shifted_camera.end_x, ], **kwargs, ) def set_pixel_array(self, pixel_array, **kwargs): super().set_pixel_array(pixel_array, **kwargs) for shifted_camera in self.shifted_cameras: shifted_camera.camera.set_pixel_array( pixel_array[ shifted_camera.start_y : shifted_camera.end_y, shifted_camera.start_x : shifted_camera.end_x, ], **kwargs, ) def init_background(self): super().init_background() for shifted_camera in self.shifted_cameras: shifted_camera.camera.init_background() # A OldMultiCamera which, when called with two full-size cameras, initializes itself # as a split screen, also taking care to resize each individual camera within it class SplitScreenCamera(OldMultiCamera): """Initializes a split screen camera setup with two side-by-side cameras. Parameters ---------- left_camera : Camera right_camera : Camera kwargs : dict """ def __init__(self, left_camera, right_camera, **kwargs): Camera.__init__(self, **kwargs) # to set attributes such as pixel_width self.left_camera = left_camera self.right_camera = right_camera half_width = math.ceil(self.pixel_width / 2) for camera in [self.left_camera, self.right_camera]: camera.reset_pixel_shape(camera.pixel_height, half_width) super().__init__( (left_camera, (0, 0)), (right_camera, (0, half_width)), ) ================================================ FILE: manim/camera/moving_camera.py ================================================ """Defines the MovingCamera class, a camera that can pan and zoom through a scene. .. SEEALSO:: :mod:`.moving_camera_scene` """ from __future__ import annotations __all__ = ["MovingCamera"] from collections.abc import Iterable from typing import Any, Literal, overload from cairo import Context from manim.typing import PixelArray, Point3D, Point3DLike from .. import config from ..camera.camera import Camera from ..constants import DOWN, LEFT, RIGHT, UP from ..mobject.frame import ScreenRectangle from ..mobject.mobject import Mobject, _AnimationBuilder from ..utils.color import WHITE, ManimColor class MovingCamera(Camera): """A camera that follows and matches the size and position of its 'frame', a Rectangle (or similar Mobject). The frame defines the region of space the camera displays and can move or resize dynamically. .. SEEALSO:: :class:`.MovingCameraScene` """ def __init__( self, frame: Mobject | None = None, fixed_dimension: int = 0, # width default_frame_stroke_color: ManimColor = WHITE, default_frame_stroke_width: int = 0, **kwargs: Any, ): """Frame is a Mobject, (should almost certainly be a rectangle) determining which region of space the camera displays """ self.fixed_dimension = fixed_dimension self.default_frame_stroke_color = default_frame_stroke_color self.default_frame_stroke_width = default_frame_stroke_width if frame is None: frame = ScreenRectangle(height=config["frame_height"]) frame.set_stroke( self.default_frame_stroke_color, self.default_frame_stroke_width, ) self.frame = frame super().__init__(**kwargs) # TODO, make these work for a rotated frame @property def frame_height(self) -> float: """Returns the height of the frame. Returns ------- float The height of the frame. """ return self.frame.height @frame_height.setter def frame_height(self, frame_height: float) -> None: """Sets the height of the frame in MUnits. Parameters ---------- frame_height The new frame_height. """ self.frame.stretch_to_fit_height(frame_height) @property def frame_width(self) -> float: """Returns the width of the frame Returns ------- float The width of the frame. """ return self.frame.width @frame_width.setter def frame_width(self, frame_width: float) -> None: """Sets the width of the frame in MUnits. Parameters ---------- frame_width The new frame_width. """ self.frame.stretch_to_fit_width(frame_width) @property def frame_center(self) -> Point3D: """Returns the centerpoint of the frame in cartesian coordinates. Returns ------- np.array The cartesian coordinates of the center of the frame. """ return self.frame.get_center() @frame_center.setter def frame_center(self, frame_center: Point3DLike | Mobject) -> None: """Sets the centerpoint of the frame. Parameters ---------- frame_center The point to which the frame must be moved. If is of type mobject, the frame will be moved to the center of that mobject. """ self.frame.move_to(frame_center) def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None: # self.reset_frame_center() # self.realign_frame_shape() super().capture_mobjects(mobjects, **kwargs) def get_cached_cairo_context(self, pixel_array: PixelArray) -> None: """Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame. So no caching. """ return None def cache_cairo_context(self, pixel_array: PixelArray, ctx: Context) -> None: """Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame. So no caching. """ pass # def reset_frame_center(self): # self.frame_center = self.frame.get_center() # def realign_frame_shape(self): # height, width = self.frame_shape # if self.fixed_dimension == 0: # self.frame_shape = (height, self.frame.width # else: # self.frame_shape = (self.frame.height, width) # self.resize_frame_shape(fixed_dimension=self.fixed_dimension) def get_mobjects_indicating_movement(self) -> list[Mobject]: """Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving Returns ------- list[Mobject] """ return [self.frame] @overload def auto_zoom( self, mobjects: Iterable[Mobject], margin: float, only_mobjects_in_frame: bool, animate: Literal[False], ) -> Mobject: ... @overload def auto_zoom( self, mobjects: Iterable[Mobject], margin: float, only_mobjects_in_frame: bool, animate: Literal[True], ) -> _AnimationBuilder: ... def auto_zoom( self, mobjects: Iterable[Mobject], margin: float = 0, only_mobjects_in_frame: bool = False, animate: bool = True, ) -> _AnimationBuilder | Mobject: """Zooms on to a given array of mobjects (or a singular mobject) and automatically resizes to frame all the mobjects. .. NOTE:: This method only works when 2D-objects in the XY-plane are considered, it will not work correctly when the camera has been rotated. Parameters ---------- mobjects The mobject or array of mobjects that the camera will focus on. margin The width of the margin that is added to the frame (optional, 0 by default). only_mobjects_in_frame If set to ``True``, only allows focusing on mobjects that are already in frame. animate If set to ``False``, applies the changes instead of returning the corresponding animation Returns ------- Union[_AnimationBuilder, ScreenRectangle] _AnimationBuilder that zooms the camera view to a given list of mobjects or ScreenRectangle with position and size updated to zoomed position. """ ( scene_critical_x_left, scene_critical_x_right, scene_critical_y_up, scene_critical_y_down, ) = self._get_bounding_box(mobjects, only_mobjects_in_frame) # calculate center x and y x = (scene_critical_x_left + scene_critical_x_right) / 2 y = (scene_critical_y_up + scene_critical_y_down) / 2 # calculate proposed width and height of zoomed scene new_width = abs(scene_critical_x_left - scene_critical_x_right) new_height = abs(scene_critical_y_up - scene_critical_y_down) m_target = self.frame.animate if animate else self.frame # zoom to fit all mobjects along the side that has the largest size if new_width / self.frame.width > new_height / self.frame.height: return m_target.set_x(x).set_y(y).set(width=new_width + margin) else: return m_target.set_x(x).set_y(y).set(height=new_height + margin) def _get_bounding_box( self, mobjects: Iterable[Mobject], only_mobjects_in_frame: bool ) -> tuple[float, float, float, float]: bounding_box_located = False scene_critical_x_left: float = 0 scene_critical_x_right: float = 1 scene_critical_y_up: float = 1 scene_critical_y_down: float = 0 for m in mobjects: if (m == self.frame) or ( only_mobjects_in_frame and not self.is_in_frame(m) ): # detected camera frame, should not be used to calculate final position of camera continue # initialize scene critical points with first mobjects critical points if not bounding_box_located: scene_critical_x_left = m.get_critical_point(LEFT)[0] scene_critical_x_right = m.get_critical_point(RIGHT)[0] scene_critical_y_up = m.get_critical_point(UP)[1] scene_critical_y_down = m.get_critical_point(DOWN)[1] bounding_box_located = True else: if m.get_critical_point(LEFT)[0] < scene_critical_x_left: scene_critical_x_left = m.get_critical_point(LEFT)[0] if m.get_critical_point(RIGHT)[0] > scene_critical_x_right: scene_critical_x_right = m.get_critical_point(RIGHT)[0] if m.get_critical_point(UP)[1] > scene_critical_y_up: scene_critical_y_up = m.get_critical_point(UP)[1] if m.get_critical_point(DOWN)[1] < scene_critical_y_down: scene_critical_y_down = m.get_critical_point(DOWN)[1] if not bounding_box_located: raise Exception( "Could not determine bounding box of the mobjects given to 'auto_zoom'." ) return ( scene_critical_x_left, scene_critical_x_right, scene_critical_y_up, scene_critical_y_down, ) ================================================ FILE: manim/camera/multi_camera.py ================================================ """A camera supporting multiple perspectives.""" from __future__ import annotations __all__ = ["MultiCamera"] from collections.abc import Iterable from typing import Any, Self from manim.mobject.mobject import Mobject from manim.mobject.types.image_mobject import ImageMobjectFromCamera from ..camera.moving_camera import MovingCamera from ..utils.iterables import list_difference_update class MultiCamera(MovingCamera): """Camera Object that allows for multiple perspectives.""" def __init__( self, image_mobjects_from_cameras: Iterable[ImageMobjectFromCamera] | None = None, allow_cameras_to_capture_their_own_display: bool = False, **kwargs: Any, ) -> None: """Initialises the MultiCamera Parameters ---------- image_mobjects_from_cameras kwargs Any valid keyword arguments of MovingCamera. """ self.image_mobjects_from_cameras: list[ImageMobjectFromCamera] = [] if image_mobjects_from_cameras is not None: for imfc in image_mobjects_from_cameras: self.add_image_mobject_from_camera(imfc) self.allow_cameras_to_capture_their_own_display = ( allow_cameras_to_capture_their_own_display ) super().__init__(**kwargs) def add_image_mobject_from_camera( self, image_mobject_from_camera: ImageMobjectFromCamera ) -> None: """Adds an ImageMobject that's been obtained from the camera into the list ``self.image_mobject_from_cameras`` Parameters ---------- image_mobject_from_camera The ImageMobject to add to self.image_mobject_from_cameras """ # A silly method to have right now, but maybe there are things # we want to guarantee about any imfc's added later. imfc = image_mobject_from_camera assert isinstance(imfc.camera, MovingCamera) self.image_mobjects_from_cameras.append(imfc) def update_sub_cameras(self) -> None: """Reshape sub_camera pixel_arrays""" for imfc in self.image_mobjects_from_cameras: pixel_height, pixel_width = self.pixel_array.shape[:2] # imfc.camera.frame_shape = ( # imfc.camera.frame.height, # imfc.camera.frame.width, # ) imfc.camera.reset_pixel_shape( int(pixel_height * imfc.height / self.frame_height), int(pixel_width * imfc.width / self.frame_width), ) def reset(self) -> Self: """Resets the MultiCamera. Returns ------- MultiCamera The reset MultiCamera """ for imfc in self.image_mobjects_from_cameras: imfc.camera.reset() super().reset() return self def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None: self.update_sub_cameras() for imfc in self.image_mobjects_from_cameras: to_add = list(mobjects) if not self.allow_cameras_to_capture_their_own_display: to_add = list_difference_update(to_add, imfc.get_family()) imfc.camera.capture_mobjects(to_add, **kwargs) super().capture_mobjects(mobjects, **kwargs) def get_mobjects_indicating_movement(self) -> list[Mobject]: """Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving Returns ------- list """ return [self.frame] + [ imfc.camera.frame for imfc in self.image_mobjects_from_cameras ] ================================================ FILE: manim/camera/three_d_camera.py ================================================ """A camera that can be positioned and oriented in three-dimensional space.""" from __future__ import annotations __all__ = ["ThreeDCamera"] from collections.abc import Callable, Iterable from typing import Any import numpy as np from manim.mobject.mobject import Mobject from manim.mobject.three_d.three_d_utils import ( get_3d_vmob_end_corner, get_3d_vmob_end_corner_unit_normal, get_3d_vmob_start_corner, get_3d_vmob_start_corner_unit_normal, ) from manim.mobject.types.vectorized_mobject import VMobject from manim.mobject.value_tracker import ValueTracker from manim.typing import ( FloatRGBA_Array, MatrixMN, Point3D, Point3D_Array, Point3DLike, ) from .. import config from ..camera.camera import Camera from ..constants import * from ..mobject.types.point_cloud_mobject import Point from ..utils.color import get_shaded_rgb from ..utils.family import extract_mobject_family_members from ..utils.space_ops import rotation_about_z, rotation_matrix class ThreeDCamera(Camera): def __init__( self, focal_distance: float = 20.0, shading_factor: float = 0.2, default_distance: float = 5.0, light_source_start_point: Point3DLike = 9 * DOWN + 7 * LEFT + 10 * OUT, should_apply_shading: bool = True, exponential_projection: bool = False, phi: float = 0, theta: float = -90 * DEGREES, gamma: float = 0, zoom: float = 1, **kwargs: Any, ): """Initializes the ThreeDCamera Parameters ---------- *kwargs Any keyword argument of Camera. """ self._frame_center = Point(kwargs.get("frame_center", ORIGIN), stroke_width=0) super().__init__(**kwargs) self.focal_distance = focal_distance self.phi = phi self.theta = theta self.gamma = gamma self.zoom = zoom self.shading_factor = shading_factor self.default_distance = default_distance self.light_source_start_point = light_source_start_point self.light_source = Point(self.light_source_start_point) self.should_apply_shading = should_apply_shading self.exponential_projection = exponential_projection self.max_allowable_norm = 3 * config["frame_width"] self.phi_tracker = ValueTracker(self.phi) self.theta_tracker = ValueTracker(self.theta) self.focal_distance_tracker = ValueTracker(self.focal_distance) self.gamma_tracker = ValueTracker(self.gamma) self.zoom_tracker = ValueTracker(self.zoom) self.fixed_orientation_mobjects: dict[Mobject, Callable[[], Point3D]] = {} self.fixed_in_frame_mobjects: set[Mobject] = set() self.reset_rotation_matrix() @property def frame_center(self) -> Point3D: return self._frame_center.points[0] @frame_center.setter def frame_center(self, point: Point3DLike) -> None: self._frame_center.move_to(point) def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None: self.reset_rotation_matrix() super().capture_mobjects(mobjects, **kwargs) def get_value_trackers(self) -> list[ValueTracker]: """A list of :class:`ValueTrackers <.ValueTracker>` of phi, theta, focal_distance, gamma and zoom. Returns ------- list list of ValueTracker objects """ return [ self.phi_tracker, self.theta_tracker, self.focal_distance_tracker, self.gamma_tracker, self.zoom_tracker, ] def modified_rgbas( self, vmobject: VMobject, rgbas: FloatRGBA_Array ) -> FloatRGBA_Array: if not self.should_apply_shading: return rgbas if vmobject.shade_in_3d and (vmobject.get_num_points() > 0): light_source_point = self.light_source.points[0] if len(rgbas) < 2: shaded_rgbas = rgbas.repeat(2, axis=0) else: shaded_rgbas = np.array(rgbas[:2]) shaded_rgbas[0, :3] = get_shaded_rgb( shaded_rgbas[0, :3], get_3d_vmob_start_corner(vmobject), get_3d_vmob_start_corner_unit_normal(vmobject), light_source_point, ) shaded_rgbas[1, :3] = get_shaded_rgb( shaded_rgbas[1, :3], get_3d_vmob_end_corner(vmobject), get_3d_vmob_end_corner_unit_normal(vmobject), light_source_point, ) return shaded_rgbas return rgbas def get_stroke_rgbas( self, vmobject: VMobject, background: bool = False, ) -> FloatRGBA_Array: # NOTE : DocStrings From parent return self.modified_rgbas(vmobject, vmobject.get_stroke_rgbas(background)) def get_fill_rgbas( self, vmobject: VMobject ) -> FloatRGBA_Array: # NOTE : DocStrings From parent return self.modified_rgbas(vmobject, vmobject.get_fill_rgbas()) def get_mobjects_to_display( self, *args: Any, **kwargs: Any ) -> list[Mobject]: # NOTE : DocStrings From parent mobjects = super().get_mobjects_to_display(*args, **kwargs) rot_matrix = self.get_rotation_matrix() def z_key(mob: Mobject) -> float: if not (hasattr(mob, "shade_in_3d") and mob.shade_in_3d): return np.inf # type: ignore[no-any-return] # Assign a number to a three dimensional mobjects # based on how close it is to the camera distance: float = np.dot(mob.get_z_index_reference_point(), rot_matrix.T)[2] return distance return sorted(mobjects, key=z_key) def get_phi(self) -> float: """Returns the Polar angle (the angle off Z_AXIS) phi. Returns ------- float The Polar angle in radians. """ return self.phi_tracker.get_value() def get_theta(self) -> float: """Returns the Azimuthal i.e the angle that spins the camera around the Z_AXIS. Returns ------- float The Azimuthal angle in radians. """ return self.theta_tracker.get_value() def get_focal_distance(self) -> float: """Returns focal_distance of the Camera. Returns ------- float The focal_distance of the Camera in MUnits. """ return self.focal_distance_tracker.get_value() def get_gamma(self) -> float: """Returns the rotation of the camera about the vector from the ORIGIN to the Camera. Returns ------- float The angle of rotation of the camera about the vector from the ORIGIN to the Camera in radians """ return self.gamma_tracker.get_value() def get_zoom(self) -> float: """Returns the zoom amount of the camera. Returns ------- float The zoom amount of the camera. """ return self.zoom_tracker.get_value() def set_phi(self, value: float) -> None: """Sets the polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians. Parameters ---------- value The new value of the polar angle in radians. """ self.phi_tracker.set_value(value) def set_theta(self, value: float) -> None: """Sets the azimuthal angle i.e the angle that spins the camera around Z_AXIS in radians. Parameters ---------- value The new value of the azimuthal angle in radians. """ self.theta_tracker.set_value(value) def set_focal_distance(self, value: float) -> None: """Sets the focal_distance of the Camera. Parameters ---------- value The focal_distance of the Camera. """ self.focal_distance_tracker.set_value(value) def set_gamma(self, value: float) -> None: """Sets the angle of rotation of the camera about the vector from the ORIGIN to the Camera. Parameters ---------- value The new angle of rotation of the camera. """ self.gamma_tracker.set_value(value) def set_zoom(self, value: float) -> None: """Sets the zoom amount of the camera. Parameters ---------- value The zoom amount of the camera. """ self.zoom_tracker.set_value(value) def reset_rotation_matrix(self) -> None: """Sets the value of self.rotation_matrix to the matrix corresponding to the current position of the camera """ self.rotation_matrix = self.generate_rotation_matrix() def get_rotation_matrix(self) -> MatrixMN: """Returns the matrix corresponding to the current position of the camera. Returns ------- np.array The matrix corresponding to the current position of the camera. """ return self.rotation_matrix def generate_rotation_matrix(self) -> MatrixMN: """Generates a rotation matrix based off the current position of the camera. Returns ------- np.array The matrix corresponding to the current position of the camera. """ phi = self.get_phi() theta = self.get_theta() gamma = self.get_gamma() matrices = [ rotation_about_z(-theta - 90 * DEGREES), rotation_matrix(-phi, RIGHT), rotation_about_z(gamma), ] result = np.identity(3) for matrix in matrices: result = np.dot(matrix, result) return result def project_points(self, points: Point3D_Array) -> Point3D_Array: """Applies the current rotation_matrix as a projection matrix to the passed array of points. Parameters ---------- points The list of points to project. Returns ------- np.array The points after projecting. """ frame_center = self.frame_center focal_distance = self.get_focal_distance() zoom = self.get_zoom() rot_matrix = self.get_rotation_matrix() points = points - frame_center points = np.dot(points, rot_matrix.T) zs = points[:, 2] for i in 0, 1: if self.exponential_projection: # Proper projection would involve multiplying # x and y by d / (d-z). But for points with high # z value that causes weird artifacts, and applying # the exponential helps smooth it out. factor = np.exp(zs / focal_distance) lt0 = zs < 0 factor[lt0] = focal_distance / (focal_distance - zs[lt0]) else: factor = focal_distance / (focal_distance - zs) factor[(focal_distance - zs) < 0] = 10**6 points[:, i] *= factor * zoom return points def project_point(self, point: Point3D) -> Point3D: """Applies the current rotation_matrix as a projection matrix to the passed point. Parameters ---------- point The point to project. Returns ------- np.array The point after projection. """ return self.project_points(point.reshape((1, 3)))[0, :] def transform_points_pre_display( self, mobject: Mobject, points: Point3D_Array, ) -> Point3D_Array: # TODO: Write Docstrings for this Method. points = super().transform_points_pre_display(mobject, points) fixed_orientation = mobject in self.fixed_orientation_mobjects fixed_in_frame = mobject in self.fixed_in_frame_mobjects if fixed_in_frame: return points if fixed_orientation: center_func = self.fixed_orientation_mobjects[mobject] center = center_func() new_center = self.project_point(center) return points + (new_center - center) else: return self.project_points(points) def add_fixed_orientation_mobjects( self, *mobjects: Mobject, use_static_center_func: bool = False, center_func: Callable[[], Point3D] | None = None, ) -> None: """This method allows the mobject to have a fixed orientation, even when the camera moves around. E.G If it was passed through this method, facing the camera, it will continue to face the camera even as the camera moves. Highly useful when adding labels to graphs and the like. Parameters ---------- *mobjects The mobject whose orientation must be fixed. use_static_center_func Whether or not to use the function that takes the mobject's center as centerpoint, by default False center_func The function which returns the centerpoint with respect to which the mobject will be oriented, by default None """ # This prevents the computation of mobject.get_center # every single time a projection happens def get_static_center_func(mobject: Mobject) -> Callable[[], Point3D]: point = mobject.get_center() return lambda: point for mobject in mobjects: if center_func: func = center_func elif use_static_center_func: func = get_static_center_func(mobject) else: func = mobject.get_center for submob in mobject.get_family(): self.fixed_orientation_mobjects[submob] = func def add_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: """This method allows the mobject to have a fixed position, even when the camera moves around. E.G If it was passed through this method, at the top of the frame, it will continue to be displayed at the top of the frame. Highly useful when displaying Titles or formulae or the like. Parameters ---------- **mobjects The mobject to fix in frame. """ for mobject in extract_mobject_family_members(mobjects): self.fixed_in_frame_mobjects.add(mobject) def remove_fixed_orientation_mobjects(self, *mobjects: Mobject) -> None: """If a mobject was fixed in its orientation by passing it through :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing. The Mobject will no longer have a fixed orientation. Parameters ---------- mobjects The mobjects whose orientation need not be fixed any longer. """ for mobject in extract_mobject_family_members(mobjects): if mobject in self.fixed_orientation_mobjects: del self.fixed_orientation_mobjects[mobject] def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: """If a mobject was fixed in frame by passing it through :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing. The Mobject will no longer be fixed in frame. Parameters ---------- mobjects The mobjects which need not be fixed in frame any longer. """ for mobject in extract_mobject_family_members(mobjects): if mobject in self.fixed_in_frame_mobjects: self.fixed_in_frame_mobjects.remove(mobject) ================================================ FILE: manim/cli/__init__.py ================================================ """The Manim CLI, and the available commands for ``manim``. This page is a work in progress. Please run ``manim`` or ``manim --help`` in your terminal to find more information on the following commands. Available commands ------------------ .. autosummary:: :toctree: ../reference cfg checkhealth init plugins render """ ================================================ FILE: manim/cli/cfg/__init__.py ================================================ ================================================ FILE: manim/cli/cfg/group.py ================================================ """Manim's cfg subcommand. Manim's cfg subcommand is accessed in the command-line interface via ``manim cfg``. Here you can specify options, subcommands, and subgroups for the cfg group. """ from __future__ import annotations import contextlib from ast import literal_eval from pathlib import Path from typing import Any, cast import cloup from rich.errors import StyleSyntaxError from rich.style import Style from manim._config import cli_ctx_settings, console from manim._config.utils import config_file_paths, make_config_parser from manim.constants import EPILOG from manim.utils.file_ops import guarantee_existence, open_file RICH_COLOUR_INSTRUCTIONS: str = """ [red]The default colour is used by the input statement. If left empty, the default colour will be used.[/red] [magenta] For a full list of styles, visit[/magenta] [green]https://rich.readthedocs.io/en/latest/style.html[/green] """ RICH_NON_STYLE_ENTRIES: list[str] = ["log.width", "log.height", "log.timestamps"] __all__ = [ "value_from_string", "value_from_string", "is_valid_style", "replace_keys", "cfg", "write", "show", "export", ] def value_from_string(value: str) -> str | int | bool: """Extract the literal of proper datatype from a ``value`` string. Parameters ---------- value The value to check get the literal from. Returns ------- :class:`str` | :class:`int` | :class:`bool` The literal of appropriate datatype. """ with contextlib.suppress(SyntaxError, ValueError): value = literal_eval(value) return value def _is_expected_datatype( value: str, expected: str, validate_style: bool = False ) -> bool: """Check whether the literal from ``value`` is the same datatype as the literal from ``expected``. If ``validate_style`` is ``True``, also check if the style given by ``value`` is valid, according to ``rich``. Parameters ---------- value The string of the value to check, obtained from reading the user input. expected The string of the literal datatype which must be matched by ``value``. This is obtained from reading the ``cfg`` file. validate_style Whether or not to confirm if ``value`` is a valid style, according to ``rich``. Default is ``False``. Returns ------- :class:`bool` Whether or not the literal from ``value`` matches the datatype of the literal from ``expected``. """ value_literal = value_from_string(value) ExpectedLiteralType = type(value_from_string(expected)) return isinstance(value_literal, ExpectedLiteralType) and ( (isinstance(value_literal, str) and is_valid_style(value_literal)) if validate_style else True ) def is_valid_style(style: str) -> bool: """Checks whether the entered color style is valid, according to ``rich``. Parameters ---------- style The style to check whether it is valid. Returns ------- :class:`bool` Whether the color style is valid or not, according to ``rich``. """ try: Style.parse(style) return True except StyleSyntaxError: return False def replace_keys(default: dict[str, Any]) -> dict[str, Any]: """Replace ``_`` with ``.`` and vice versa in a dictionary's keys for ``rich``. Parameters ---------- default The dictionary whose keys will be checked and replaced. Returns ------- :class:`dict` The dictionary whose keys are modified by replacing ``_`` with ``.`` and vice versa. """ for key in default: if "_" in key: temp = default[key] del default[key] key = key.replace("_", ".") default[key] = temp else: temp = default[key] del default[key] key = key.replace(".", "_") default[key] = temp return default @cloup.group( context_settings=cli_ctx_settings, invoke_without_command=True, no_args_is_help=True, epilog=EPILOG, help="Manages Manim configuration files.", ) @cloup.pass_context def cfg(ctx: cloup.Context) -> None: """Responsible for the cfg subcommand.""" pass @cfg.command(context_settings=cli_ctx_settings, no_args_is_help=True) @cloup.option( "-l", "--level", type=cloup.Choice(["user", "cwd"], case_sensitive=False), default="cwd", help="Specify if this config is for user or the working directory.", ) @cloup.option("-o", "--open", "openfile", is_flag=True) def write(level: str | None = None, openfile: bool = False) -> None: config_paths = config_file_paths() console.print( "[yellow bold]Manim Configuration File Writer[/yellow bold]", justify="center", ) USER_CONFIG_MSG = f"""A configuration file at [yellow]{config_paths[1]}[/yellow] has been created with your required changes. This will be used when running the manim command. If you want to override this config, you will have to create a manim.cfg in the local directory, where you want those changes to be overridden.""" CWD_CONFIG_MSG = f"""A configuration file at [yellow]{config_paths[2]}[/yellow] has been created. To save your config please save that file and place it in your current working directory, from where you run the manim command.""" parser = make_config_parser() if not openfile: action = "save this as" for category in parser: console.print(f"{category}", style="bold green underline") default = cast(dict[str, Any], parser[category]) if category == "logger": console.print(RICH_COLOUR_INSTRUCTIONS) default = replace_keys(default) for key in default: # All the cfg entries for logger need to be validated as styles, # as long as they aren't setting the log width or height etc if category == "logger" and key not in RICH_NON_STYLE_ENTRIES: desc = "style" style = default[key] else: desc = "value" style = None console.print(f"Enter the {desc} for {key} ", style=style, end="") if category != "logger" or key in RICH_NON_STYLE_ENTRIES: defaultval = ( repr(default[key]) if isinstance(value_from_string(default[key]), str) else default[key] ) console.print(f"(defaults to {defaultval}) :", end="") try: temp = input() except EOFError: raise Exception( """Not enough values in input. You may have added a new entry to default.cfg, in which case you will have to modify write_cfg_subcmd_input to account for it.""", ) from None if temp: while temp and not _is_expected_datatype( temp, default[key], bool(style), ): console.print( f"[red bold]Invalid {desc}. Try again.[/red bold]", ) console.print( f"Enter the {desc} for {key}:", style=style, end="", ) temp = input() default[key] = temp.replace("%", "%%") default = replace_keys(default) if category == "logger" else default parser[category] = { i: v.replace("%", "%%") for i, v in dict(default).items() } else: action = "open" if level is None: console.print( f"Do you want to {action} the default config for this User?(y/n)[[n]]", style="dim purple", end="", ) action_to_userpath = input() else: action_to_userpath = "" if action_to_userpath.lower() == "y" or level == "user": cfg_file_path = config_paths[1] guarantee_existence(config_paths[1].parents[0]) console.print(USER_CONFIG_MSG) else: cfg_file_path = config_paths[2] guarantee_existence(config_paths[2].parents[0]) console.print(CWD_CONFIG_MSG) with cfg_file_path.open("w") as fp: parser.write(fp) if openfile: open_file(cfg_file_path) @cfg.command(context_settings=cli_ctx_settings) def show() -> None: console.print("CONFIG FILES READ", style="bold green underline") for path in config_file_paths(): if path.exists(): console.print(f"{path}") console.print() parser = make_config_parser() rich_non_style_entries = [a.replace(".", "_") for a in RICH_NON_STYLE_ENTRIES] for category in parser: console.print(f"{category}", style="bold green underline") for entry in parser[category]: if category == "logger" and entry not in rich_non_style_entries: console.print(f"{entry} :", end="") console.print( f" {parser[category][entry]}", style=parser[category][entry], ) else: console.print(f"{entry} : {parser[category][entry]}") console.print("\n") @cfg.command(context_settings=cli_ctx_settings) @cloup.option("-d", "--directory", default=Path.cwd()) @cloup.pass_context def export(ctx: cloup.Context, directory: str) -> None: directory_path = Path(directory) if directory_path.absolute == Path.cwd().absolute: console.print( """You are reading the config from the same directory you are exporting to. This means that the exported config will overwrite the config for this directory. Are you sure you want to continue? (y/n)""", style="red bold", end="", ) proceed = input().lower() == "y" else: proceed = True if proceed: if not directory_path.is_dir(): console.print(f"Creating folder: {directory}.", style="red bold") directory_path.mkdir(parents=True, exist_ok=True) ctx.invoke(write) from_path = Path.cwd() / "manim.cfg" to_path = directory_path / "manim.cfg" console.print(f"Exported final Config at {from_path} to {to_path}.") else: console.print("Aborted...", style="red bold") ================================================ FILE: manim/cli/checkhealth/__init__.py ================================================ ================================================ FILE: manim/cli/checkhealth/checks.py ================================================ """Auxiliary module for the checkhealth subcommand, contains the actual check implementations. """ from __future__ import annotations import os import shutil from collections.abc import Callable from typing import Protocol, cast __all__ = ["HEALTH_CHECKS"] class HealthCheckFunction(Protocol): description: str recommendation: str skip_on_failed: list[str] post_fail_fix_hook: Callable[..., object] | None __name__: str def __call__(self) -> bool: ... HEALTH_CHECKS: list[HealthCheckFunction] = [] def healthcheck( description: str, recommendation: str, skip_on_failed: list[HealthCheckFunction | str] | None = None, post_fail_fix_hook: Callable[..., object] | None = None, ) -> Callable[[Callable[[], bool]], HealthCheckFunction]: """Decorator used for declaring health checks. This decorator attaches some data to a function, which is then added to a a list containing all checks. Parameters ---------- description A brief description of this check, displayed when the ``checkhealth`` subcommand is run. recommendation Help text which is displayed in case the check fails. skip_on_failed A list of check functions which, if they fail, cause the current check to be skipped. post_fail_fix_hook A function that is meant to (interactively) help to fix the detected problem, if possible. This is only called upon explicit confirmation of the user. Returns ------- Callable[Callable[[], bool], :class:`HealthCheckFunction`] A decorator which converts a function into a health check function, as required by the ``checkhealth`` subcommand. """ new_skip_on_failed: list[str] if skip_on_failed is None: new_skip_on_failed = [] else: new_skip_on_failed = [ skip.__name__ if callable(skip) else skip for skip in skip_on_failed ] def wrapper(func: Callable[[], bool]) -> HealthCheckFunction: health_func = cast(HealthCheckFunction, func) health_func.description = description health_func.recommendation = recommendation health_func.skip_on_failed = new_skip_on_failed health_func.post_fail_fix_hook = post_fail_fix_hook HEALTH_CHECKS.append(health_func) return health_func return wrapper @healthcheck( description="Checking whether manim is on your PATH", recommendation=( "The command is currently not on your system's PATH.\n\n" "You can work around this by calling the manim module directly " "via instead of just .\n\n" "To fix the PATH issue properly: " "Usually, the Python package installer pip issues a warning " "during the installation which contains more information. " "Consider reinstalling manim via " "followed by to see the warning again, " "then consult the internet on how to modify your system's " "PATH variable." ), ) def is_manim_on_path() -> bool: """Check whether ``manim`` is in ``PATH``. Returns ------- :class:`bool` Whether ``manim`` is in ``PATH`` or not. """ path_to_manim = shutil.which("manim") return path_to_manim is not None @healthcheck( description="Checking whether the executable belongs to manim", recommendation=( "The command does not belong to your installed version " "of this library, it likely belongs to manimgl / manimlib.\n\n" "Run manim via or via , or uninstall " "and reinstall manim via to fix this." ), skip_on_failed=[is_manim_on_path], ) def is_manim_executable_associated_to_this_library() -> bool: """Check whether the ``manim`` executable in ``PATH`` is associated to this library. To verify this, the executable should look like this: .. code-block:: python #!/.../python import sys from manim.__main__ import main if __name__ == "__main__": sys.exit(main()) Returns ------- :class:`bool` Whether the ``manim`` executable in ``PATH`` is associated to this library or not. """ path_to_manim = shutil.which("manim") assert path_to_manim is not None with open(path_to_manim, "rb") as manim_binary: manim_exec = manim_binary.read() # first condition below corresponds to the executable being # some sort of python script. second condition happens when # the executable is actually a Windows batch file. return b"manim.__main__" in manim_exec or b'"%~dp0\\manim"' in manim_exec @healthcheck( description="Checking whether latex is available", recommendation=( "Manim cannot find on your system's PATH. " "You will not be able to use Tex and MathTex mobjects " "in your scenes.\n\n" "Consult our installation instructions " "at https://docs.manim.community/en/stable/installation.html " "or search the web for instructions on how to install a " "LaTeX distribution on your operating system." ), ) def is_latex_available() -> bool: """Check whether ``latex`` is in ``PATH`` and can be executed. Returns ------- :class:`bool` Whether ``latex`` is in ``PATH`` and can be executed or not. """ path_to_latex = shutil.which("latex") return path_to_latex is not None and os.access(path_to_latex, os.X_OK) @healthcheck( description="Checking whether dvisvgm is available", recommendation=( "Manim could find , but not on your system's " "PATH. Make sure your installed LaTeX distribution comes with " "dvisvgm and consider installing a larger distribution if it " "does not." ), skip_on_failed=[is_latex_available], ) def is_dvisvgm_available() -> bool: """Check whether ``dvisvgm`` is in ``PATH`` and can be executed. Returns ------- :class:`bool` Whether ``dvisvgm`` is in ``PATH`` and can be executed or not. """ path_to_dvisvgm = shutil.which("dvisvgm") return path_to_dvisvgm is not None and os.access(path_to_dvisvgm, os.X_OK) ================================================ FILE: manim/cli/checkhealth/commands.py ================================================ """A CLI utility helping to diagnose problems with your Manim installation. """ from __future__ import annotations import sys import timeit import click import cloup from manim.cli.checkhealth.checks import HEALTH_CHECKS, HealthCheckFunction __all__ = ["checkhealth"] @cloup.command( context_settings=None, ) def checkhealth() -> None: """This subcommand checks whether Manim is installed correctly and has access to its required (and optional) system dependencies. """ click.echo(f"Python executable: {sys.executable}\n") click.echo("Checking whether your installation of Manim Community is healthy...") failed_checks: list[HealthCheckFunction] = [] for check in HEALTH_CHECKS: click.echo(f"- {check.description} ... ", nl=False) if any( failed_check.__name__ in check.skip_on_failed for failed_check in failed_checks ): click.secho("SKIPPED", fg="blue") continue check_result = check() if check_result: click.secho("PASSED", fg="green") else: click.secho("FAILED", fg="red") failed_checks.append(check) click.echo() if failed_checks: click.echo( "There are problems with your installation, " "here are some recommendations to fix them:" ) for ind, failed_check in enumerate(failed_checks): click.echo(failed_check.recommendation) if ind + 1 < len(failed_checks): click.confirm("Continue with next recommendation?") else: # no problems detected! click.echo("No problems detected, your installation seems healthy!") render_test_scene = click.confirm( "Would you like to render and preview a test scene?" ) if render_test_scene: import manim as mn class CheckHealthDemo(mn.Scene): def _inner_construct(self) -> None: banner = mn.ManimBanner().shift(mn.UP * 0.5) self.play(banner.create()) self.wait(0.5) self.play(banner.expand()) self.wait(0.5) text_left = mn.Text("All systems operational!") formula_right = mn.MathTex(r"\oint_{\gamma} f(z)~dz = 0") text_tex_group = mn.VGroup(text_left, formula_right) text_tex_group.arrange(mn.RIGHT, buff=1).next_to(banner, mn.DOWN) self.play(mn.Write(text_tex_group)) self.wait(0.5) self.play( mn.FadeOut(banner, shift=mn.UP), mn.FadeOut(text_tex_group, shift=mn.DOWN), ) def construct(self) -> None: self.execution_time = timeit.timeit(self._inner_construct, number=1) with mn.tempconfig({"preview": True, "disable_caching": True}): scene = CheckHealthDemo() scene.render() click.echo(f"Scene rendered in {scene.execution_time:.2f} seconds.") ================================================ FILE: manim/cli/default_group.py ================================================ """``DefaultGroup`` allows a subcommand to act as the main command. In particular, this class is what allows ``manim`` to act as ``manim render``. .. note:: This is a vendored version of https://github.com/click-contrib/click-default-group/ under the BSD 3-Clause "New" or "Revised" License. This library isn't used as a dependency, as we need to inherit from :class:`cloup.Group` instead of :class:`click.Group`. """ from __future__ import annotations import warnings from collections.abc import Callable from typing import TYPE_CHECKING, Any import cloup from manim.utils.deprecation import deprecated __all__ = ["DefaultGroup"] if TYPE_CHECKING: from click import Command, Context class DefaultGroup(cloup.Group): """Invokes a subcommand marked with ``default=True`` if any subcommand is not chosen. Parameters ---------- *args Positional arguments to forward to :class:`cloup.Group`. **kwargs Keyword arguments to forward to :class:`cloup.Group`. The keyword ``ignore_unknown_options`` must be set to ``False``. Attributes ---------- default_cmd_name : str | None The name of the default command, if specified through the ``default`` keyword argument. Otherwise, this is set to ``None``. default_if_no_args : bool Whether to include or not the default command, if no command arguments are supplied. This can be specified through the ``default_if_no_args`` keyword argument. Default is ``False``. """ def __init__(self, *args: Any, **kwargs: Any): # To resolve as the default command. if not kwargs.get("ignore_unknown_options", True): raise ValueError("Default group accepts unknown options") self.ignore_unknown_options = True self.default_cmd_name: str | None = kwargs.pop("default", None) self.default_if_no_args: bool = kwargs.pop("default_if_no_args", False) super().__init__(*args, **kwargs) def set_default_command(self, command: Command) -> None: """Sets a command function as the default command. Parameters ---------- command The command to set as default. """ cmd_name = command.name self.add_command(command) self.default_cmd_name = cmd_name def parse_args(self, ctx: Context, args: list[str]) -> list[str]: """Parses the list of ``args`` by forwarding it to :meth:`cloup.Group.parse_args`. Before doing so, if :attr:`default_if_no_args` is set to ``True`` and ``args`` is empty, this function appends to it the name of the default command specified by :attr:`default_cmd_name`. Parameters ---------- ctx The Click context. args A list of arguments. If it's empty and :attr:`default_if_no_args` is ``True``, append the name of the default command to it. Returns ------- list[str] The parsed arguments. """ if not args and self.default_if_no_args and self.default_cmd_name: args.insert(0, self.default_cmd_name) parsed_args: list[str] = super().parse_args(ctx, args) return parsed_args def get_command(self, ctx: Context, cmd_name: str) -> Command | None: """Get a command function by its name, by forwarding the arguments to :meth:`cloup.Group.get_command`. If ``cmd_name`` does not match any of the command names in :attr:`commands`, attempt to get the default command instead. Parameters ---------- ctx The Click context. cmd_name The name of the command to get. Returns ------- :class:`click.Command` | None The command, if found. Otherwise, ``None``. """ if cmd_name not in self.commands and self.default_cmd_name: # No command name matched. ctx.meta["arg0"] = cmd_name cmd_name = self.default_cmd_name return super().get_command(ctx, cmd_name) def resolve_command( self, ctx: Context, args: list[str] ) -> tuple[str | None, Command | None, list[str]]: """Given a list of ``args`` given by a CLI, find a command which matches the first element, and return its name (``cmd_name``), the command function itself (``cmd``) and the rest of the arguments which shall be passed to the function (``cmd_args``). If not found, return ``None``, ``None`` and the rest of the arguments. After resolving the command, if the Click context given by ``ctx`` contains an ``arg0`` attribute in its :attr:`click.Context.meta` dictionary, insert it as the first element of the returned ``cmd_args``. Parameters ---------- ctx The Click context. cmd_name The name of the command to get. Returns ------- cmd_name : str | None The command name, if found. Otherwise, ``None``. cmd : :class:`click.Command` | None The command, if found. Otherwise, ``None``. cmd_args : list[str] The rest of the arguments to be passed to ``cmd``. """ cmd_name, cmd, args = super().resolve_command(ctx, args) if "arg0" in ctx.meta: args.insert(0, ctx.meta["arg0"]) if cmd is not None: cmd_name = cmd.name return cmd_name, cmd, args @deprecated def command( self, *args: Any, **kwargs: Any ) -> Callable[[Callable[..., object]], Command]: """Return a decorator which converts any function into the default subcommand for this :class:`DefaultGroup`. .. warning:: This method is deprecated. Use the ``default`` parameter of :class:`DefaultGroup` or :meth:`set_default_command` instead. Parameters ---------- *args Positional arguments to pass to :meth:`cloup.Group.command`. **kwargs Keyword arguments to pass to :meth:`cloup.Group.command`. Returns ------- Callable[[Callable[..., object]], click.Command] A decorator which transforms its input into this :class:`DefaultGroup`'s default subcommand. """ default = kwargs.pop("default", False) decorator: Callable[[Callable[..., object]], Command] = super().command( *args, **kwargs ) if not default: return decorator warnings.warn( "Use default param of DefaultGroup or set_default_command() instead", DeprecationWarning, stacklevel=1, ) def _decorator(f: Callable) -> Command: cmd = decorator(f) self.set_default_command(cmd) return cmd return _decorator ================================================ FILE: manim/cli/init/__init__.py ================================================ ================================================ FILE: manim/cli/init/commands.py ================================================ """Manim's init subcommand. Manim's init subcommand is accessed in the command-line interface via ``manim init``. Here you can specify options, subcommands, and subgroups for the init group. """ from __future__ import annotations import configparser from pathlib import Path from typing import Any import click import cloup from manim._config import console from manim.constants import CONTEXT_SETTINGS, EPILOG, QUALITIES from manim.utils.file_ops import ( add_import_statement, copy_template_files, get_template_names, get_template_path, ) CFG_DEFAULTS = { "frame_rate": 30, "background_color": "BLACK", "background_opacity": 1, "scene_names": "Default", "resolution": (1920, 1080), } __all__ = ["select_resolution", "update_cfg", "project", "scene"] def select_resolution() -> tuple[int, int]: """Prompts input of type click.Choice from user. Presents options from QUALITIES constant. Returns ------- tuple[int, int] Tuple containing height and width. """ resolution_options: list[tuple[int, int]] = [ (quality[1]["pixel_height"], quality[1]["pixel_width"]) for quality in QUALITIES.items() ] resolution_options.pop() choice = click.prompt( "\nSelect resolution:\n", type=cloup.Choice([f"{i[0]}p" for i in resolution_options]), show_default=False, default="480p", ) matches = [res for res in resolution_options if f"{res[0]}p" == choice] return matches[0] def update_cfg(cfg_dict: dict[str, Any], project_cfg_path: Path) -> None: """Update the ``manim.cfg`` file after reading it from the specified ``project_cfg_path``. Parameters ---------- cfg_dict Values used to update ``manim.cfg`` which is found in ``project_cfg_path``. project_cfg_path Path of the ``manim.cfg`` file. """ config = configparser.ConfigParser() config.read(project_cfg_path) cli_config = config["CLI"] for key, value in cfg_dict.items(): if key == "resolution": cli_config["pixel_height"] = str(value[0]) cli_config["pixel_width"] = str(value[1]) else: cli_config[key] = str(value) with project_cfg_path.open("w") as conf: config.write(conf) @cloup.command( context_settings=CONTEXT_SETTINGS, epilog=EPILOG, ) @cloup.argument("project_name", type=cloup.Path(path_type=Path), required=False) @cloup.option( "-d", "--default", "default_settings", is_flag=True, help="Default settings for project creation.", nargs=1, ) def project(default_settings: bool, **kwargs: Any) -> None: """Creates a new project. PROJECT_NAME is the name of the folder in which the new project will be initialized. """ project_name: Path if kwargs["project_name"]: project_name = kwargs["project_name"] else: project_name = click.prompt("Project Name", type=Path) # in the future when implementing a full template system. Choices are going to be saved in some sort of config file for templates template_name = click.prompt( "Template", type=click.Choice(get_template_names(), False), default="Default", ) if project_name.is_dir(): console.print( f"\nFolder [red]{project_name}[/red] exists. Please type another name\n", ) else: project_name.mkdir() new_cfg: dict[str, Any] = {} new_cfg_path = Path.resolve(project_name / "manim.cfg") if not default_settings: for key, value in CFG_DEFAULTS.items(): if key == "scene_names": new_cfg[key] = template_name + "Template" elif key == "resolution": new_cfg[key] = select_resolution() else: new_cfg[key] = click.prompt(f"\n{key}", default=value) console.print("\n", new_cfg) if click.confirm("Do you want to continue?", default=True, abort=True): copy_template_files(project_name, template_name) update_cfg(new_cfg, new_cfg_path) else: copy_template_files(project_name, template_name) update_cfg(CFG_DEFAULTS, new_cfg_path) @cloup.command( context_settings=CONTEXT_SETTINGS, no_args_is_help=True, epilog=EPILOG, ) @cloup.argument("scene_name", type=str, required=True) @cloup.argument("file_name", type=str, required=False) def scene(**kwargs: Any) -> None: """Inserts a SCENE to an existing FILE or creates a new FILE. SCENE is the name of the scene that will be inserted. FILE is the name of file in which the SCENE will be inserted. """ template_name: str = click.prompt( "template", type=click.Choice(get_template_names(), False), default="Default", ) scene = (get_template_path() / f"{template_name}.mtp").resolve().read_text() scene = scene.replace(template_name + "Template", kwargs["scene_name"], 1) if kwargs["file_name"]: file_name = Path(kwargs["file_name"]) if file_name.suffix != ".py": file_name = file_name.with_suffix(file_name.suffix + ".py") if file_name.is_file(): # file exists so we are going to append new scene to that file with file_name.open("a") as f: f.write("\n\n\n" + scene) else: # file does not exist so we create a new file, append the scene and prepend the import statement file_name.write_text("\n\n\n" + scene) add_import_statement(file_name) else: # file name is not provided so we assume it is main.py # if main.py does not exist we do not continue with Path("main.py").open("a") as f: f.write("\n\n\n" + scene) @cloup.group( context_settings=CONTEXT_SETTINGS, invoke_without_command=True, no_args_is_help=True, epilog=EPILOG, help="Create a new project or insert a new scene.", ) @cloup.pass_context def init(ctx: cloup.Context) -> None: pass init.add_command(project) init.add_command(scene) ================================================ FILE: manim/cli/plugins/__init__.py ================================================ ================================================ FILE: manim/cli/plugins/commands.py ================================================ """Manim's plugin subcommand. Manim's plugin subcommand is accessed in the command-line interface via ``manim plugin``. Here you can specify options, subcommands, and subgroups for the plugin group. """ from __future__ import annotations import cloup from manim.constants import CONTEXT_SETTINGS, EPILOG from manim.plugins.plugins_flags import list_plugins __all__ = ["plugins"] @cloup.command( context_settings=CONTEXT_SETTINGS, no_args_is_help=True, epilog=EPILOG, help="Manages Manim plugins.", ) @cloup.option( "-l", "--list", "list_available", is_flag=True, help="List available plugins.", ) def plugins(list_available: bool) -> None: """Print a list of all available plugins when calling ``manim plugins -l`` or ``manim plugins --list``. Parameters ---------- list_available If the ``-l`` or ``-list`` option is passed to ``manim plugins``, this parameter will be set to ``True``, which will print a list of all available plugins. """ if list_available: list_plugins() ================================================ FILE: manim/cli/render/__init__.py ================================================ ================================================ FILE: manim/cli/render/commands.py ================================================ """Manim's default subcommand, render. Manim's render subcommand is accessed in the command-line interface via ``manim``, but can be more explicitly accessed with ``manim render``. Here you can specify options, and arguments for the render command. """ from __future__ import annotations import http.client import json import sys import urllib.error import urllib.request from argparse import Namespace from pathlib import Path from typing import Any, cast import cloup from manim import __version__ from manim._config import ( config, console, error_console, logger, tempconfig, ) from manim.cli.render.ease_of_access_options import ease_of_access_options from manim.cli.render.global_options import global_options from manim.cli.render.output_options import output_options from manim.cli.render.render_options import render_options from manim.constants import EPILOG, RendererType from manim.utils.module_ops import scene_classes_from_file __all__ = ["render"] class ClickArgs(Namespace): def __init__(self, args: dict[str, Any]) -> None: for name in args: setattr(self, name, args[name]) def _get_kwargs(self) -> list[tuple[str, Any]]: return list(self.__dict__.items()) def __eq__(self, other: object) -> bool: if not isinstance(other, ClickArgs): return NotImplemented return vars(self) == vars(other) def __contains__(self, key: str) -> bool: return key in self.__dict__ def __repr__(self) -> str: return str(self.__dict__) @cloup.command( context_settings=None, no_args_is_help=True, epilog=EPILOG, ) @cloup.argument("file", type=cloup.Path(path_type=Path), required=True) @cloup.argument("scene_names", required=False, nargs=-1) @global_options @output_options @render_options @ease_of_access_options def render(**kwargs: Any) -> ClickArgs | dict[str, Any]: """Render SCENE(S) from the input FILE. FILE is the file path of the script or a config file. SCENES is an optional list of scenes in the file. """ if kwargs["save_as_gif"]: logger.warning("--save_as_gif is deprecated, please use --format=gif instead!") kwargs["format"] = "gif" if kwargs["save_pngs"]: logger.warning("--save_pngs is deprecated, please use --format=png instead!") kwargs["format"] = "png" if kwargs["show_in_file_browser"]: logger.warning( "The short form of show_in_file_browser is deprecated and will be moved to support --format.", ) click_args = ClickArgs(kwargs) if kwargs["jupyter"]: return click_args config.digest_args(click_args) file = Path(config.input_file) if config.renderer == RendererType.OPENGL: from manim.renderer.opengl_renderer import OpenGLRenderer try: renderer = OpenGLRenderer() keep_running = True while keep_running: for SceneClass in scene_classes_from_file(file): with tempconfig({}): scene = SceneClass(renderer) rerun = scene.render() if rerun or config["write_all"]: renderer.num_plays = 0 continue else: keep_running = False break if config["write_all"]: keep_running = False except Exception: error_console.print_exception() sys.exit(1) else: for SceneClass in scene_classes_from_file(file): try: with tempconfig({}): scene = SceneClass() scene.render() except Exception: error_console.print_exception() sys.exit(1) if config.notify_outdated_version: manim_info_url = "https://pypi.org/pypi/manim/json" warn_prompt = "Cannot check if latest release of manim is installed" try: with urllib.request.urlopen( urllib.request.Request(manim_info_url), timeout=10, ) as response: response = cast(http.client.HTTPResponse, response) json_data = json.loads(response.read()) except urllib.error.HTTPError: logger.debug("HTTP Error: %s", warn_prompt) except urllib.error.URLError: logger.debug("URL Error: %s", warn_prompt) except json.JSONDecodeError: logger.debug( "Error while decoding JSON from %r: %s", manim_info_url, warn_prompt ) except Exception: logger.debug("Something went wrong: %s", warn_prompt) else: stable = json_data["info"]["version"] if stable != __version__: console.print( f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.", ) console.print( "You should consider upgrading via [yellow]pip install -U manim[/yellow]", ) return kwargs ================================================ FILE: manim/cli/render/ease_of_access_options.py ================================================ from __future__ import annotations from cloup import Choice, option, option_group __all__ = ["ease_of_access_options"] ease_of_access_options = option_group( "Ease of access options", option( "--progress_bar", default=None, show_default=False, type=Choice( ["display", "leave", "none"], case_sensitive=False, ), help="Display progress bars and/or keep them displayed.", ), option( "-p", "--preview", is_flag=True, help="Preview the Scene's animation. OpenGL does a live preview in a " "popup window. Cairo opens the rendered video file in the system " "default media player.", default=None, ), option( "-f", "--show_in_file_browser", is_flag=True, help="Show the output file in the file browser.", default=None, ), option( "--jupyter", is_flag=True, help="Using jupyter notebook magic.", default=None, ), ) ================================================ FILE: manim/cli/render/global_options.py ================================================ from __future__ import annotations import logging import re import sys from typing import TYPE_CHECKING from cloup import Choice, option, option_group if TYPE_CHECKING: from click import Context, Option __all__ = ["global_options"] logger = logging.getLogger("manim") def validate_gui_location( ctx: Context, param: Option, value: str | None ) -> tuple[int, int] | None: """If the ``value`` string is given, extract from it the GUI location, which should be in any of these formats: 'x;y', 'x,y' or 'x-y'. Parameters ---------- ctx The Click context. param A Click option. value The optional string which will be parsed. Returns ------- tuple[int, int] | None If ``value`` is ``None``, the return value is ``None``. Otherwise, it's the ``(x, y)`` location for the GUI. Raises ------ ValueError If ``value`` has an invalid format. """ if value is None: return None try: x_offset, y_offset = map(int, re.split(r"[;,\-]", value)) except Exception: logger.error("GUI location option is invalid.") sys.exit() return (x_offset, y_offset) global_options = option_group( "Global options", option( "-c", "--config_file", help="Specify the configuration file to use for render settings.", default=None, ), option( "--custom_folders", is_flag=True, default=None, help="Use the folders defined in the [custom_folders] section of the " "config file to define the output folder structure.", ), option( "--disable_caching", is_flag=True, default=None, help="Disable the use of the cache (still generates cache files).", ), option( "--flush_cache", is_flag=True, help="Remove cached partial movie files.", default=None, ), option("--tex_template", help="Specify a custom TeX template file.", default=None), option( "-v", "--verbosity", type=Choice( ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], case_sensitive=False, ), help="Verbosity of CLI output. Changes ffmpeg log level unless 5+.", default=None, ), option( "--notify_outdated_version/--silent", is_flag=True, default=None, help="Display warnings for outdated installation.", ), option( "--enable_gui", is_flag=True, help="Enable GUI interaction.", default=None, ), option( "--gui_location", default=None, callback=validate_gui_location, help="Starting location for the GUI.", ), option( "--fullscreen", is_flag=True, help="Expand the window to its maximum possible size.", default=None, ), option( "--enable_wireframe", is_flag=True, help="Enable wireframe debugging mode in opengl.", default=None, ), option( "--force_window", is_flag=True, help="Force window to open when using the opengl renderer, intended for debugging as it may impact performance", default=None, ), option( "--dry_run", is_flag=True, help="Renders animations without outputting image or video files and disables the window", default=None, ), option( "--no_latex_cleanup", is_flag=True, help="Prevents deletion of .aux, .dvi, and .log files produced by Tex and MathTex.", default=None, ), option( "--preview_command", help="The command used to preview the output file (for example vlc for video files)", default=None, ), option( "--seed", type=int, help="Set the random seed to allow reproducibility.", default=None, ), ) ================================================ FILE: manim/cli/render/output_options.py ================================================ from __future__ import annotations from cloup import IntRange, Path, option, option_group __all__ = ["output_options"] output_options = option_group( "Output options", option( "-o", "--output_file", type=str, default=None, help="Specify the filename(s) of the rendered scene(s).", ), option( "-0", "--zero_pad", type=IntRange(0, 9), default=None, help="Zero padding for PNG file names.", ), option( "--write_to_movie", is_flag=True, default=None, help="Write the video rendered with opengl to a file.", ), option( "--media_dir", type=Path(), default=None, help="Path to store rendered videos and latex.", ), option( "--log_dir", type=Path(), help="Path to store render logs.", default=None, ), option( "--log_to_file", is_flag=True, default=None, help="Log terminal output to file.", ), ) ================================================ FILE: manim/cli/render/render_options.py ================================================ from __future__ import annotations import logging import re import sys from typing import TYPE_CHECKING from cloup import Choice, option, option_group from manim.constants import QUALITIES, RendererType if TYPE_CHECKING: from click import Context, Option __all__ = ["render_options"] logger = logging.getLogger("manim") def validate_scene_range( ctx: Context, param: Option, value: str | None ) -> tuple[int] | tuple[int, int] | None: """If the ``value`` string is given, extract from it the scene range, which should be in any of these formats: 'start', 'start;end', 'start,end' or 'start-end'. Otherwise, return ``None``. Parameters ---------- ctx The Click context. param A Click option. value The optional string which will be parsed. Returns ------- tuple[int] | tuple[int, int] | None If ``value`` is ``None``, the return value is ``None``. Otherwise, it's the scene range, given by a tuple which may contain a single value ``start`` or two values ``start`` and ``end``. Raises ------ ValueError If ``value`` has an invalid format. """ if value is None: return None try: start = int(value) return (start,) except Exception: pass try: start, end = map(int, re.split(r"[;,\-]", value)) except Exception: logger.error("Couldn't determine a range for -n option.") sys.exit() return start, end def validate_resolution( ctx: Context, param: Option, value: str | None ) -> tuple[int, int] | None: """If the ``value`` string is given, extract from it the resolution, which should be in any of these formats: 'W;H', 'W,H' or 'W-H'. Otherwise, return ``None``. Parameters ---------- ctx The Click context. param A Click option. value The optional string which will be parsed. Returns ------- tuple[int, int] | None If ``value`` is ``None``, the return value is ``None``. Otherwise, it's the resolution as a ``(W, H)`` tuple. Raises ------ ValueError If ``value`` has an invalid format. """ if value is None: return None try: width, height = map(int, re.split(r"[;,\-]", value)) except Exception: logger.error("Resolution option is invalid.") sys.exit() return width, height render_options = option_group( "Render Options", option( "-n", "--from_animation_number", callback=validate_scene_range, help="Start rendering from n_0 until n_1. If n_1 is left unspecified, " "renders all scenes after n_0.", default=None, ), option( "-a", "--write_all", is_flag=True, help="Render all scenes in the input file.", default=None, ), option( "--format", type=Choice(["png", "gif", "mp4", "webm", "mov"], case_sensitive=False), default=None, ), option( "-s", "--save_last_frame", default=None, is_flag=True, help="Render and save only the last frame of a scene as a PNG image.", ), option( "-q", "--quality", default=None, type=Choice( list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])), case_sensitive=False, ), help="Render quality at the follow resolution framerates, respectively: " + ", ".join( reversed( [ f"{q['pixel_width']}x{q['pixel_height']} {q['frame_rate']}FPS" for q in QUALITIES.values() if q["flag"] ] ) ), ), option( "-r", "--resolution", callback=validate_resolution, default=None, help='Resolution in "W,H" for when 16:9 aspect ratio isn\'t possible.', ), option( "--fps", "--frame_rate", "frame_rate", type=float, default=None, help="Render at this frame rate.", ), option( "--renderer", type=Choice( [renderer_type.value for renderer_type in RendererType], case_sensitive=False, ), help="Select a renderer for your Scene.", default="cairo", ), option( "-g", "--save_pngs", is_flag=True, default=None, help="Save each frame as png (Deprecated).", ), option( "-i", "--save_as_gif", default=None, is_flag=True, help="Save as a gif (Deprecated).", ), option( "--save_sections", default=None, is_flag=True, help="Save section videos in addition to movie file.", ), option( "-t", "--transparent", is_flag=True, help="Render scenes with alpha channel.", ), option( "--use_projection_fill_shaders", is_flag=True, help="Use shaders for OpenGLVMobject fill which are compatible with transformation matrices.", default=None, ), option( "--use_projection_stroke_shaders", is_flag=True, help="Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.", default=None, ), ) ================================================ FILE: manim/constants.py ================================================ """Constant definitions.""" from __future__ import annotations from enum import Enum from typing import TypedDict import numpy as np from cloup import Context from PIL.Image import Resampling from manim.typing import Vector3D __all__ = [ "SCENE_NOT_FOUND_MESSAGE", "CHOOSE_NUMBER_MESSAGE", "INVALID_NUMBER_MESSAGE", "NO_SCENE_MESSAGE", "NORMAL", "ITALIC", "OBLIQUE", "BOLD", "THIN", "ULTRALIGHT", "LIGHT", "SEMILIGHT", "BOOK", "MEDIUM", "SEMIBOLD", "ULTRABOLD", "HEAVY", "ULTRAHEAVY", "RESAMPLING_ALGORITHMS", "ORIGIN", "UP", "DOWN", "RIGHT", "LEFT", "IN", "OUT", "X_AXIS", "Y_AXIS", "Z_AXIS", "UL", "UR", "DL", "DR", "START_X", "START_Y", "DEFAULT_DOT_RADIUS", "DEFAULT_SMALL_DOT_RADIUS", "DEFAULT_DASH_LENGTH", "DEFAULT_ARROW_TIP_LENGTH", "SMALL_BUFF", "MED_SMALL_BUFF", "MED_LARGE_BUFF", "LARGE_BUFF", "DEFAULT_MOBJECT_TO_EDGE_BUFFER", "DEFAULT_MOBJECT_TO_MOBJECT_BUFFER", "DEFAULT_POINTWISE_FUNCTION_RUN_TIME", "DEFAULT_WAIT_TIME", "DEFAULT_POINT_DENSITY_2D", "DEFAULT_POINT_DENSITY_1D", "DEFAULT_STROKE_WIDTH", "DEFAULT_FONT_SIZE", "SCALE_FACTOR_PER_FONT_POINT", "PI", "TAU", "DEGREES", "QUALITIES", "DEFAULT_QUALITY", "EPILOG", "CONTEXT_SETTINGS", "SHIFT_VALUE", "CTRL_VALUE", "RendererType", "LineJointType", "CapStyleType", ] # Messages SCENE_NOT_FOUND_MESSAGE = """ {} is not in the script """ CHOOSE_NUMBER_MESSAGE = """ Choose number corresponding to desired scene/arguments. (Use comma separated list for multiple entries or use "*" to select all scenes.) Choice(s): """ INVALID_NUMBER_MESSAGE = "Invalid scene numbers have been specified. Aborting." NO_SCENE_MESSAGE = """ There are no scenes inside that module """ # Pango stuff NORMAL = "NORMAL" ITALIC = "ITALIC" OBLIQUE = "OBLIQUE" BOLD = "BOLD" # Only for Pango from below THIN = "THIN" ULTRALIGHT = "ULTRALIGHT" LIGHT = "LIGHT" SEMILIGHT = "SEMILIGHT" BOOK = "BOOK" MEDIUM = "MEDIUM" SEMIBOLD = "SEMIBOLD" ULTRABOLD = "ULTRABOLD" HEAVY = "HEAVY" ULTRAHEAVY = "ULTRAHEAVY" RESAMPLING_ALGORITHMS = { "nearest": Resampling.NEAREST, "none": Resampling.NEAREST, "bilinear": Resampling.BILINEAR, "linear": Resampling.BILINEAR, "bicubic": Resampling.BICUBIC, "cubic": Resampling.BICUBIC, } # Geometry: directions ORIGIN: Vector3D = np.array((0.0, 0.0, 0.0)) """The center of the coordinate system.""" UP: Vector3D = np.array((0.0, 1.0, 0.0)) """One unit step in the positive Y direction.""" DOWN: Vector3D = np.array((0.0, -1.0, 0.0)) """One unit step in the negative Y direction.""" RIGHT: Vector3D = np.array((1.0, 0.0, 0.0)) """One unit step in the positive X direction.""" LEFT: Vector3D = np.array((-1.0, 0.0, 0.0)) """One unit step in the negative X direction.""" IN: Vector3D = np.array((0.0, 0.0, -1.0)) """One unit step in the negative Z direction.""" OUT: Vector3D = np.array((0.0, 0.0, 1.0)) """One unit step in the positive Z direction.""" # Geometry: axes X_AXIS: Vector3D = np.array((1.0, 0.0, 0.0)) Y_AXIS: Vector3D = np.array((0.0, 1.0, 0.0)) Z_AXIS: Vector3D = np.array((0.0, 0.0, 1.0)) # Geometry: useful abbreviations for diagonals UL: Vector3D = UP + LEFT """One step up plus one step left.""" UR: Vector3D = UP + RIGHT """One step up plus one step right.""" DL: Vector3D = DOWN + LEFT """One step down plus one step left.""" DR: Vector3D = DOWN + RIGHT """One step down plus one step right.""" # Geometry START_X = 30 START_Y = 20 DEFAULT_DOT_RADIUS = 0.08 DEFAULT_SMALL_DOT_RADIUS = 0.04 DEFAULT_DASH_LENGTH = 0.05 DEFAULT_ARROW_TIP_LENGTH = 0.35 # Default buffers (padding) SMALL_BUFF = 0.1 MED_SMALL_BUFF = 0.25 MED_LARGE_BUFF = 0.5 LARGE_BUFF = 1 DEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_LARGE_BUFF DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF # Times in seconds DEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0 DEFAULT_WAIT_TIME = 1.0 # Misc DEFAULT_POINT_DENSITY_2D = 25 DEFAULT_POINT_DENSITY_1D = 10 DEFAULT_STROKE_WIDTH = 4 DEFAULT_FONT_SIZE = 48 SCALE_FACTOR_PER_FONT_POINT = 1 / 960 # Mathematical constants PI = np.pi """The ratio of the circumference of a circle to its diameter.""" TAU = 2 * PI """The ratio of the circumference of a circle to its radius.""" DEGREES = TAU / 360 """The exchange rate between radians and degrees.""" class QualityDict(TypedDict): flag: str | None pixel_height: int pixel_width: int frame_rate: int # Video qualities QUALITIES: dict[str, QualityDict] = { "fourk_quality": { "flag": "k", "pixel_height": 2160, "pixel_width": 3840, "frame_rate": 60, }, "production_quality": { "flag": "p", "pixel_height": 1440, "pixel_width": 2560, "frame_rate": 60, }, "high_quality": { "flag": "h", "pixel_height": 1080, "pixel_width": 1920, "frame_rate": 60, }, "medium_quality": { "flag": "m", "pixel_height": 720, "pixel_width": 1280, "frame_rate": 30, }, "low_quality": { "flag": "l", "pixel_height": 480, "pixel_width": 854, "frame_rate": 15, }, "example_quality": { "flag": None, "pixel_height": 480, "pixel_width": 854, "frame_rate": 30, }, } DEFAULT_QUALITY = "high_quality" EPILOG = "Made with <3 by Manim Community developers." SHIFT_VALUE = 65505 CTRL_VALUE = 65507 CONTEXT_SETTINGS = Context.settings( align_option_groups=True, align_sections=True, show_constraints=True, ) class RendererType(Enum): """An enumeration of all renderer types that can be assigned to the ``config.renderer`` attribute. Manim's configuration allows assigning string values to the renderer setting, the values are then replaced by the corresponding enum object. In other words, you can run:: config.renderer = "opengl" and checking the renderer afterwards reveals that the attribute has assumed the value:: """ CAIRO = "cairo" #: A renderer based on the cairo backend. OPENGL = "opengl" #: An OpenGL-based renderer. class LineJointType(Enum): """Collection of available line joint types. See the example below for a visual illustration of the different joint types. Examples -------- .. manim:: LineJointVariants :save_last_frame: class LineJointVariants(Scene): def construct(self): mob = VMobject(stroke_width=20, color=GREEN).set_points_as_corners([ np.array([-2, 0, 0]), np.array([0, 0, 0]), np.array([-2, 1, 0]), ]) lines = VGroup(*[mob.copy() for _ in range(len(LineJointType))]) for line, joint_type in zip(lines, LineJointType): line.joint_type = joint_type lines.arrange(RIGHT, buff=1) self.add(lines) for line in lines: label = Text(line.joint_type.name).next_to(line, DOWN) self.add(label) """ AUTO = 0 ROUND = 1 BEVEL = 2 MITER = 3 class CapStyleType(Enum): """Collection of available cap styles. See the example below for a visual illustration of the different cap styles. Examples -------- .. manim:: CapStyleVariants :save_last_frame: class CapStyleVariants(Scene): def construct(self): arcs = VGroup(*[ Arc( radius=1, start_angle=0, angle=TAU / 4, stroke_width=20, color=GREEN, cap_style=cap_style, ) for cap_style in CapStyleType ]) arcs.arrange(RIGHT, buff=1) self.add(arcs) for arc in arcs: label = Text(arc.cap_style.name, font_size=24).next_to(arc, DOWN) self.add(label) """ AUTO = 0 ROUND = 1 BUTT = 2 SQUARE = 3 ================================================ FILE: manim/data_structures.py ================================================ """Data classes and other necessary data structures for use in Manim.""" from __future__ import annotations from collections.abc import Iterable from dataclasses import dataclass from types import MethodType from typing import Any @dataclass class MethodWithArgs: """Object containing a :attr:`method` which is intended to be called later with the positional arguments :attr:`args` and the keyword arguments :attr:`kwargs`. Attributes ---------- method : MethodType A callable representing a method of some class. args : Iterable[Any] Positional arguments for :attr:`method`. kwargs : dict[str, Any] Keyword arguments for :attr:`method`. """ __slots__ = ["method", "args", "kwargs"] method: MethodType args: Iterable[Any] kwargs: dict[str, Any] ================================================ FILE: manim/mobject/__init__.py ================================================ ================================================ FILE: manim/mobject/frame.py ================================================ """Special rectangles.""" from __future__ import annotations __all__ = [ "ScreenRectangle", "FullScreenRectangle", ] from typing import Any from manim.mobject.geometry.polygram import Rectangle from .. import config class ScreenRectangle(Rectangle): def __init__( self, aspect_ratio: float = 16.0 / 9.0, height: float = 4, **kwargs: Any ) -> None: super().__init__(width=aspect_ratio * height, height=height, **kwargs) @property def aspect_ratio(self) -> float: """The aspect ratio. When set, the width is stretched to accommodate the new aspect ratio. """ return self.width / self.height @aspect_ratio.setter def aspect_ratio(self, value: float) -> None: self.stretch_to_fit_width(value * self.height) class FullScreenRectangle(ScreenRectangle): def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) self.height = config["frame_height"] ================================================ FILE: manim/mobject/geometry/__init__.py ================================================ """Various geometric Mobjects. Modules ======= .. autosummary:: :toctree: ../reference ~arc ~boolean_ops ~labeled ~line ~polygram ~shape_matchers ~tips """ ================================================ FILE: manim/mobject/geometry/arc.py ================================================ r"""Mobjects that are curved. Examples -------- .. manim:: UsefulAnnotations :save_last_frame: class UsefulAnnotations(Scene): def construct(self): m0 = Dot() m1 = AnnotationDot() m2 = LabeledDot("ii") m3 = LabeledDot(MathTex(r"\alpha").set_color(ORANGE)) m4 = CurvedArrow(2*LEFT, 2*RIGHT, radius= -5) m5 = CurvedArrow(2*LEFT, 2*RIGHT, radius= 8) m6 = CurvedDoubleArrow(ORIGIN, 2*RIGHT) self.add(m0, m1, m2, m3, m4, m5, m6) for i, mobj in enumerate(self.mobjects): mobj.shift(DOWN * (i-3)) """ from __future__ import annotations __all__ = [ "TipableVMobject", "Arc", "ArcBetweenPoints", "CurvedArrow", "CurvedDoubleArrow", "Circle", "Dot", "AnnotationDot", "LabeledDot", "Ellipse", "AnnularSector", "Sector", "Annulus", "CubicBezier", "ArcPolygon", "ArcPolygonFromArcs", "TangentialArc", ] import itertools import warnings from typing import TYPE_CHECKING, Any, Self, cast import numpy as np from manim.constants import * from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.color import BLACK, BLUE, RED, WHITE, ParsableManimColor from manim.utils.iterables import adjacent_pairs from manim.utils.space_ops import ( angle_between_vectors, angle_of_vector, cartesian_to_spherical, line_intersection, perpendicular_bisector, rotate_vector, ) if TYPE_CHECKING: from collections.abc import Iterable import manim.mobject.geometry.tips as tips from manim.mobject.geometry.line import Line from manim.mobject.mobject import Mobject from manim.mobject.text.tex_mobject import SingleStringMathTex, Tex from manim.mobject.text.text_mobject import Text from manim.typing import ( Point3D, Point3DLike, QuadraticSpline, Vector3DLike, ) class TipableVMobject(VMobject, metaclass=ConvertToOpenGL): """Meant for shared functionality between Arc and Line. Functionality can be classified broadly into these groups: * Adding, Creating, Modifying tips - add_tip calls create_tip, before pushing the new tip into the TipableVMobject's list of submobjects - stylistic and positional configuration * Checking for tips - Boolean checks for whether the TipableVMobject has a tip and a starting tip * Getters - Straightforward accessors, returning information pertaining to the TipableVMobject instance's tip(s), its length etc """ def __init__( self, tip_length: float = DEFAULT_ARROW_TIP_LENGTH, normal_vector: Vector3DLike = OUT, tip_style: dict | None = None, **kwargs: Any, ) -> None: self.tip_length: float = tip_length self.normal_vector = normal_vector self.tip_style: dict = tip_style if tip_style is not None else {} super().__init__(**kwargs) # Adding, Creating, Modifying tips def add_tip( self, tip: tips.ArrowTip | None = None, tip_shape: type[tips.ArrowTip] | None = None, tip_length: float | None = None, tip_width: float | None = None, at_start: bool = False, ) -> Self: """Adds a tip to the TipableVMobject instance, recognising that the endpoints might need to be switched if it's a 'starting tip' or not. """ if tip is None: tip = self.create_tip(tip_shape, tip_length, tip_width, at_start) else: self.position_tip(tip, at_start) self.reset_endpoints_based_on_tip(tip, at_start) self.assign_tip_attr(tip, at_start) self.add(tip) return self def create_tip( self, tip_shape: type[tips.ArrowTip] | None = None, tip_length: float | None = None, tip_width: float | None = None, at_start: bool = False, ) -> tips.ArrowTip: """Stylises the tip, positions it spatially, and returns the newly instantiated tip to the caller. """ tip = self.get_unpositioned_tip(tip_shape, tip_length, tip_width) self.position_tip(tip, at_start) return tip def get_unpositioned_tip( self, tip_shape: type[tips.ArrowTip] | None = None, tip_length: float | None = None, tip_width: float | None = None, ) -> tips.ArrowTip | tips.ArrowTriangleFilledTip: """Returns a tip that has been stylistically configured, but has not yet been given a position in space. """ from manim.mobject.geometry.tips import ArrowTriangleFilledTip style: dict[str, Any] = {} if tip_shape is None: tip_shape = ArrowTriangleFilledTip if tip_shape is ArrowTriangleFilledTip: if tip_width is None: tip_width = self.get_default_tip_length() style.update({"width": tip_width}) if tip_length is None: tip_length = self.get_default_tip_length() color = self.get_color() style.update({"fill_color": color, "stroke_color": color}) style.update(self.tip_style) tip = tip_shape(length=tip_length, **style) return tip def position_tip(self, tip: tips.ArrowTip, at_start: bool = False) -> tips.ArrowTip: # Last two control points, defining both # the end, and the tangency direction if at_start: anchor = self.get_start() handle = self.get_first_handle() else: handle = self.get_last_handle() anchor = self.get_end() angles = cartesian_to_spherical(handle - anchor) tip.rotate( angles[1] - PI - tip.tip_angle, ) # Rotates the tip along the azimuthal if not hasattr(self, "_init_positioning_axis"): axis = np.array( [ np.sin(angles[1]), -np.cos(angles[1]), 0, ] ) # Obtains the perpendicular of the tip tip.rotate( -angles[2] + PI / 2, axis=axis, ) # Rotates the tip along the vertical wrt the axis self._init_positioning_axis = axis tip.shift(anchor - tip.tip_point) return tip def reset_endpoints_based_on_tip(self, tip: tips.ArrowTip, at_start: bool) -> Self: if self.get_length() == 0: # Zero length, put_start_and_end_on wouldn't work return self if at_start: self.put_start_and_end_on(tip.base, self.get_end()) else: self.put_start_and_end_on(self.get_start(), tip.base) return self def assign_tip_attr(self, tip: tips.ArrowTip, at_start: bool) -> Self: if at_start: self.start_tip = tip else: self.tip = tip return self # Checking for tips def has_tip(self) -> bool: return hasattr(self, "tip") and self.tip in self def has_start_tip(self) -> bool: return hasattr(self, "start_tip") and self.start_tip in self # Getters def pop_tips(self) -> VGroup: start, end = self.get_start_and_end() result = self.get_group_class()() if self.has_tip(): result.add(self.tip) self.remove(self.tip) if self.has_start_tip(): result.add(self.start_tip) self.remove(self.start_tip) if result.submobjects: self.put_start_and_end_on(start, end) return result def get_tips(self) -> VGroup: """Returns a VGroup (collection of VMobjects) containing the TipableVMObject instance's tips. """ result = self.get_group_class()() if hasattr(self, "tip"): result.add(self.tip) if hasattr(self, "start_tip"): result.add(self.start_tip) return result def get_tip(self) -> VMobject: """Returns the TipableVMobject instance's (first) tip, otherwise throws an exception. """ tips = self.get_tips() if len(tips) == 0: raise Exception("tip not found") else: tip: VMobject = tips[0] return tip def get_default_tip_length(self) -> float: return self.tip_length def get_first_handle(self) -> Point3D: # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 first_handle: Point3D = self.points[1] return first_handle def get_last_handle(self) -> Point3D: # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 last_handle: Point3D = self.points[-2] return last_handle def get_end(self) -> Point3D: if self.has_tip(): return self.tip.get_start() else: return super().get_end() def get_start(self) -> Point3D: if self.has_start_tip(): return self.start_tip.get_start() else: return super().get_start() def get_length(self) -> float: start, end = self.get_start_and_end() return float(np.linalg.norm(start - end)) class Arc(TipableVMobject): """A circular arc. Examples -------- A simple arc of angle Pi. .. manim:: ArcExample :save_last_frame: class ArcExample(Scene): def construct(self): self.add(Arc(angle=PI)) """ def __init__( self, radius: float | None = 1.0, start_angle: float = 0, angle: float = TAU / 4, num_components: int = 9, arc_center: Point3DLike = ORIGIN, **kwargs: Any, ): if radius is None: # apparently None is passed by ArcBetweenPoints radius = 1.0 self.radius = radius self.num_components = num_components self.arc_center: Point3D = np.asarray(arc_center) self.start_angle = start_angle self.angle = angle self._failed_to_get_center: bool = False super().__init__(**kwargs) def generate_points(self) -> None: self._set_pre_positioned_points() self.scale(self.radius, about_point=ORIGIN) self.shift(self.arc_center) # Points are set a bit differently when rendering via OpenGL. # TODO: refactor Arc so that only one strategy for setting points # has to be used. def init_points(self) -> None: self.set_points( Arc._create_quadratic_bezier_points( angle=self.angle, start_angle=self.start_angle, n_components=self.num_components, ), ) self.scale(self.radius, about_point=ORIGIN) self.shift(self.arc_center) @staticmethod def _create_quadratic_bezier_points( angle: float, start_angle: float = 0, n_components: int = 8 ) -> QuadraticSpline: samples = np.array( [ [np.cos(a), np.sin(a), 0] for a in np.linspace( start_angle, start_angle + angle, 2 * n_components + 1, ) ], ) theta = angle / n_components samples[1::2] /= np.cos(theta / 2) points = np.zeros((3 * n_components, 3)) points[0::3] = samples[0:-1:2] points[1::3] = samples[1::2] points[2::3] = samples[2::2] return points def _set_pre_positioned_points(self) -> None: anchors = np.array( [ np.cos(a) * RIGHT + np.sin(a) * UP for a in np.linspace( self.start_angle, self.start_angle + self.angle, self.num_components, ) ], ) # Figure out which control points will give the # Appropriate tangent lines to the circle d_theta = self.angle / (self.num_components - 1.0) tangent_vectors = np.zeros(anchors.shape) # Rotate all 90 degrees, via (x, y) -> (-y, x) tangent_vectors[:, 1] = anchors[:, 0] tangent_vectors[:, 0] = -anchors[:, 1] # Use tangent vectors to deduce anchors factor = 4 / 3 * np.tan(d_theta / 4) handles1 = anchors[:-1] + factor * tangent_vectors[:-1] handles2 = anchors[1:] - factor * tangent_vectors[1:] self.set_anchors_and_handles(anchors[:-1], handles1, handles2, anchors[1:]) def get_arc_center(self, warning: bool = True) -> Point3D: """Looks at the normals to the first two anchors, and finds their intersection points """ # First two anchors and handles a1, h1, h2, a2 = self.points[:4] if np.all(a1 == a2): # For a1 and a2 to lie at the same point arc radius # must be zero. Thus arc_center will also lie at # that point. return np.copy(a1) # Tangent vectors t1 = h1 - a1 t2 = h2 - a2 # Normals n1 = rotate_vector(t1, TAU / 4) n2 = rotate_vector(t2, TAU / 4) try: return line_intersection(line1=(a1, a1 + n1), line2=(a2, a2 + n2)) except Exception: if warning: warnings.warn( "Can't find Arc center, using ORIGIN instead", stacklevel=1 ) self._failed_to_get_center = True return np.array(ORIGIN) def move_arc_center_to(self, point: Point3DLike) -> Self: self.shift(point - self.get_arc_center()) return self def stop_angle(self) -> float: return cast( float, angle_of_vector(self.points[-1] - self.get_arc_center()) % TAU, ) class ArcBetweenPoints(Arc): """Inherits from Arc and additionally takes 2 points between which the arc is spanned. Example ------- .. manim:: ArcBetweenPointsExample class ArcBetweenPointsExample(Scene): def construct(self): circle = Circle(radius=2, stroke_color=GREY) dot_1 = Dot(color=GREEN).move_to([2, 0, 0]).scale(0.5) dot_1_text = Tex("(2,0)").scale(0.5).next_to(dot_1, RIGHT).set_color(BLUE) dot_2 = Dot(color=GREEN).move_to([0, 2, 0]).scale(0.5) dot_2_text = Tex("(0,2)").scale(0.5).next_to(dot_2, UP).set_color(BLUE) arc= ArcBetweenPoints(start=2 * RIGHT, end=2 * UP, stroke_color=YELLOW) self.add(circle, dot_1, dot_2, dot_1_text, dot_2_text) self.play(Create(arc)) """ def __init__( self, start: Point3DLike, end: Point3DLike, angle: float = TAU / 4, radius: float | None = None, **kwargs: Any, ) -> None: if radius is not None: self.radius = radius if radius < 0: sign = -2 radius *= -1 else: sign = 2 halfdist = np.linalg.norm(np.array(start) - np.array(end)) / 2 if radius < halfdist: raise ValueError( """ArcBetweenPoints called with a radius that is smaller than half the distance between the points.""", ) arc_height = radius - np.sqrt(radius**2 - halfdist**2) angle = np.arccos((radius - arc_height) / radius) * sign super().__init__(radius=radius, angle=angle, **kwargs) if angle == 0: self.set_points_as_corners(np.array([LEFT, RIGHT])) self.put_start_and_end_on(start, end) if radius is None: center = self.get_arc_center(warning=False) if not self._failed_to_get_center: # np.linalg.norm returns floating[Any] which is not compatible with float self.radius = cast( float, np.linalg.norm(np.array(start) - np.array(center)) ) else: self.radius = np.inf class TangentialArc(ArcBetweenPoints): """ Construct an arc that is tangent to two intersecting lines. You can choose any of the 4 possible corner arcs via the `corner` tuple. corner = (s1, s2) where each si is ±1 to control direction along each line. Examples -------- .. manim:: TangentialArcExample :save_last_frame: class TangentialArcExample(Scene): def construct(self): line1 = DashedLine(start=3 * LEFT, end=3 * RIGHT) line1.rotate(angle=31 * DEGREES, about_point=ORIGIN) line2 = DashedLine(start=3 * UP, end=3 * DOWN) line2.rotate(angle=12 * DEGREES, about_point=ORIGIN) arc = TangentialArc(line1, line2, radius=2.25, corner=(1, 1), color=TEAL) self.add(arc, line1, line2) The following example shows all four possible corner configurations: .. manim:: TangentialArcCorners :save_last_frame: class TangentialArcCorners(Scene): def construct(self): # Create two intersecting lines line1 = DashedLine(start=3 * LEFT, end=3 * RIGHT, color=GREY) line2 = DashedLine(start=3 * UP, end=3 * DOWN, color=GREY) # All four corner configurations with different colors arc_pp = TangentialArc(line1, line2, radius=1.5, corner=(1, 1), color=RED) arc_pn = TangentialArc(line1, line2, radius=1.5, corner=(1, -1), color=GREEN) arc_np = TangentialArc(line1, line2, radius=1.5, corner=(-1, 1), color=BLUE) arc_nn = TangentialArc(line1, line2, radius=1.5, corner=(-1, -1), color=YELLOW) # Labels for each arc label_pp = Text("(1,1)", font_size=24, color=RED).next_to(arc_pp, UR, buff=0.1) label_pn = Text("(1,-1)", font_size=24, color=GREEN).next_to(arc_pn, DR, buff=0.1) label_np = Text("(-1,1)", font_size=24, color=BLUE).next_to(arc_np, UL, buff=0.1) label_nn = Text("(-1,-1)", font_size=24, color=YELLOW).next_to(arc_nn, DL, buff=0.1) self.add(line1, line2, arc_pp, arc_pn, arc_np, arc_nn) self.add(label_pp, label_pn, label_np, label_nn) """ def __init__( self, line1: Line, line2: Line, radius: float, corner: Any = (1, 1), **kwargs: Any, ): self.line1 = line1 self.line2 = line2 intersection_point = line_intersection( [line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()] ) s1, s2 = corner # Get unit vector for specified directions unit_vector1 = s1 * line1.get_unit_vector() unit_vector2 = s2 * line2.get_unit_vector() corner_angle = angle_between_vectors(unit_vector1, unit_vector2) tangent_point_distance = radius / np.tan(corner_angle / 2) # tangent points tangent_point1 = intersection_point + tangent_point_distance * unit_vector1 tangent_point2 = intersection_point + tangent_point_distance * unit_vector2 cross_product = ( unit_vector1[0] * unit_vector2[1] - unit_vector1[1] * unit_vector2[0] ) # Determine start and end points based on orientation if cross_product < 0: # Counterclockwise orientation - standard order start_point = tangent_point1 end_point = tangent_point2 else: # Clockwise orientation - reverse the points start_point = tangent_point2 end_point = tangent_point1 super().__init__(start=start_point, end=end_point, radius=radius, **kwargs) class CurvedArrow(ArcBetweenPoints): def __init__( self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any ) -> None: from manim.mobject.geometry.tips import ArrowTriangleFilledTip tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) super().__init__(start_point, end_point, **kwargs) self.add_tip(tip_shape=tip_shape) class CurvedDoubleArrow(CurvedArrow): def __init__( self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any ) -> None: if "tip_shape_end" in kwargs: kwargs["tip_shape"] = kwargs.pop("tip_shape_end") from manim.mobject.geometry.tips import ArrowTriangleFilledTip tip_shape_start = kwargs.pop("tip_shape_start", ArrowTriangleFilledTip) super().__init__(start_point, end_point, **kwargs) self.add_tip(at_start=True, tip_shape=tip_shape_start) class Circle(Arc): """A circle. Parameters ---------- color The color of the shape. kwargs Additional arguments to be passed to :class:`Arc` Examples -------- .. manim:: CircleExample :save_last_frame: class CircleExample(Scene): def construct(self): circle_1 = Circle(radius=1.0) circle_2 = Circle(radius=1.5, color=GREEN) circle_3 = Circle(radius=1.0, color=BLUE_B, fill_opacity=1) circle_group = Group(circle_1, circle_2, circle_3).arrange(buff=1) self.add(circle_group) """ def __init__( self, radius: float | None = None, color: ParsableManimColor = RED, **kwargs: Any, ) -> None: super().__init__( radius=radius, start_angle=0, angle=TAU, color=color, **kwargs, ) def surround( self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False, buffer_factor: float = 1.2, ) -> Self: """Modifies a circle so that it surrounds a given mobject. Parameters ---------- mobject The mobject that the circle will be surrounding. dim_to_match buffer_factor Scales the circle with respect to the mobject. A `buffer_factor` < 1 makes the circle smaller than the mobject. stretch Stretches the circle to fit more tightly around the mobject. Note: Does not work with :class:`Line` Examples -------- .. manim:: CircleSurround :save_last_frame: class CircleSurround(Scene): def construct(self): triangle1 = Triangle() circle1 = Circle().surround(triangle1) group1 = Group(triangle1,circle1) # treat the two mobjects as one line2 = Line() circle2 = Circle().surround(line2, buffer_factor=2.0) group2 = Group(line2,circle2) # buffer_factor < 1, so the circle is smaller than the square square3 = Square() circle3 = Circle().surround(square3, buffer_factor=0.5) group3 = Group(square3, circle3) 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 # Something goes wrong here when surrounding lines? # TODO: Figure out and fix self.replace(mobject, dim_to_match, stretch) self.width = np.sqrt(mobject.width**2 + mobject.height**2) return self.scale(buffer_factor) def point_at_angle(self, angle: float) -> Point3D: """Returns the position of a point on the circle. Parameters ---------- angle The angle of the point along the circle in radians. Returns ------- :class:`numpy.ndarray` The location of the point along the circle's circumference. Examples -------- .. manim:: PointAtAngleExample :save_last_frame: class PointAtAngleExample(Scene): def construct(self): circle = Circle(radius=2.0) p1 = circle.point_at_angle(PI/2) p2 = circle.point_at_angle(270*DEGREES) s1 = Square(side_length=0.25).move_to(p1) s2 = Square(side_length=0.25).move_to(p2) self.add(circle, s1, s2) """ proportion = angle / TAU proportion -= np.floor(proportion) return self.point_from_proportion(proportion) @staticmethod def from_three_points( p1: Point3DLike, p2: Point3DLike, p3: Point3DLike, **kwargs: Any ) -> Circle: """Returns a circle passing through the specified three points. Example ------- .. manim:: CircleFromPointsExample :save_last_frame: class CircleFromPointsExample(Scene): def construct(self): circle = Circle.from_three_points(LEFT, LEFT + UP, UP * 2, color=RED) dots = VGroup( Dot(LEFT), Dot(LEFT + UP), Dot(UP * 2), ) self.add(NumberPlane(), circle, dots) """ center = line_intersection( perpendicular_bisector([np.asarray(p1), np.asarray(p2)]), perpendicular_bisector([np.asarray(p2), np.asarray(p3)]), ) # np.linalg.norm returns floating[Any] which is not compatible with float radius = cast(float, np.linalg.norm(p1 - center)) return Circle(radius=radius, **kwargs).shift(center) class Dot(Circle): """A circle with a very small radius. Parameters ---------- point The location of the dot. radius The radius of the dot. stroke_width The thickness of the outline of the dot. fill_opacity The opacity of the dot's fill_colour color The color of the dot. kwargs Additional arguments to be passed to :class:`Circle` Examples -------- .. manim:: DotExample :save_last_frame: class DotExample(Scene): def construct(self): dot1 = Dot(point=LEFT, radius=0.08) dot2 = Dot(point=ORIGIN) dot3 = Dot(point=RIGHT) self.add(dot1,dot2,dot3) """ def __init__( self, point: Point3DLike = ORIGIN, radius: float = DEFAULT_DOT_RADIUS, stroke_width: float = 0, fill_opacity: float = 1.0, color: ParsableManimColor = WHITE, **kwargs: Any, ) -> None: super().__init__( arc_center=point, radius=radius, stroke_width=stroke_width, fill_opacity=fill_opacity, color=color, **kwargs, ) class AnnotationDot(Dot): """A dot with bigger radius and bold stroke to annotate scenes.""" def __init__( self, radius: float = DEFAULT_DOT_RADIUS * 1.3, stroke_width: float = 5, stroke_color: ParsableManimColor = WHITE, fill_color: ParsableManimColor = BLUE, **kwargs: Any, ) -> None: super().__init__( radius=radius, stroke_width=stroke_width, stroke_color=stroke_color, fill_color=fill_color, **kwargs, ) class LabeledDot(Dot): """A :class:`Dot` containing a label in its center. Parameters ---------- label The label of the :class:`Dot`. This is rendered as :class:`~.MathTex` by default (i.e., when passing a :class:`str`), but other classes representing rendered strings like :class:`~.Text` or :class:`~.Tex` can be passed as well. radius The radius of the :class:`Dot`. If provided, the ``buff`` is ignored. If ``None`` (the default), the radius is calculated based on the size of the ``label`` and the ``buff``. Examples -------- .. manim:: SeveralLabeledDots :save_last_frame: class SeveralLabeledDots(Scene): def construct(self): sq = Square(fill_color=RED, fill_opacity=1) self.add(sq) dot1 = LabeledDot(Tex("42", color=RED)) dot2 = LabeledDot(MathTex("a", color=GREEN)) dot3 = LabeledDot(Text("ii", color=BLUE)) dot4 = LabeledDot("3") dot1.next_to(sq, UL) dot2.next_to(sq, UR) dot3.next_to(sq, DL) dot4.next_to(sq, DR) self.add(dot1, dot2, dot3, dot4) """ def __init__( self, label: str | SingleStringMathTex | Text | Tex, radius: float | None = None, buff: float = SMALL_BUFF, **kwargs: Any, ) -> None: if isinstance(label, str): from manim import MathTex rendered_label: VMobject = MathTex(label, color=BLACK) else: rendered_label = label if radius is None: radius = buff + float( np.linalg.norm([rendered_label.width, rendered_label.height]) / 2 ) super().__init__(radius=radius, **kwargs) rendered_label.move_to(self.get_center()) self.add(rendered_label) class Ellipse(Circle): """A circular shape; oval, circle. Parameters ---------- width The horizontal width of the ellipse. height The vertical height of the ellipse. kwargs Additional arguments to be passed to :class:`Circle`. Examples -------- .. manim:: EllipseExample :save_last_frame: class EllipseExample(Scene): def construct(self): ellipse_1 = Ellipse(width=2.0, height=4.0, color=BLUE_B) ellipse_2 = Ellipse(width=4.0, height=1.0, color=BLUE_D) ellipse_group = Group(ellipse_1,ellipse_2).arrange(buff=1) self.add(ellipse_group) """ def __init__(self, width: float = 2, height: float = 1, **kwargs: Any) -> None: super().__init__(**kwargs) self.stretch_to_fit_width(width) self.stretch_to_fit_height(height) class AnnularSector(Arc): """A sector of an annulus. Parameters ---------- inner_radius The inside radius of the Annular Sector. outer_radius The outside radius of the Annular Sector. angle The clockwise angle of the Annular Sector. start_angle The starting clockwise angle of the Annular Sector. fill_opacity The opacity of the color filled in the Annular Sector. stroke_width The stroke width of the Annular Sector. color The color filled into the Annular Sector. Examples -------- .. manim:: AnnularSectorExample :save_last_frame: class AnnularSectorExample(Scene): def construct(self): # Changes background color to clearly visualize changes in fill_opacity. self.camera.background_color = WHITE # The default parameter start_angle is 0, so the AnnularSector starts from the +x-axis. s1 = AnnularSector(color=YELLOW).move_to(2 * UL) # Different inner_radius and outer_radius than the default. s2 = AnnularSector(inner_radius=1.5, outer_radius=2, angle=45 * DEGREES, color=RED).move_to(2 * UR) # fill_opacity is typically a number > 0 and <= 1. If fill_opacity=0, the AnnularSector is transparent. s3 = AnnularSector(inner_radius=1, outer_radius=1.5, angle=PI, fill_opacity=0.25, color=BLUE).move_to(2 * DL) # With a negative value for the angle, the AnnularSector is drawn clockwise from the start value. s4 = AnnularSector(inner_radius=1, outer_radius=1.5, angle=-3 * PI / 2, color=GREEN).move_to(2 * DR) self.add(s1, s2, s3, s4) """ def __init__( self, inner_radius: float = 1, outer_radius: float = 2, angle: float = TAU / 4, start_angle: float = 0, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, **kwargs: Any, ) -> None: self.inner_radius = inner_radius self.outer_radius = outer_radius super().__init__( start_angle=start_angle, angle=angle, fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs, ) def generate_points(self) -> None: inner_arc, outer_arc = ( Arc( start_angle=self.start_angle, angle=self.angle, radius=radius, arc_center=self.arc_center, ) for radius in (self.inner_radius, self.outer_radius) ) outer_arc.reverse_points() self.append_points(inner_arc.points) self.add_line_to(outer_arc.points[0]) self.append_points(outer_arc.points) self.add_line_to(inner_arc.points[0]) def init_points(self) -> None: self.generate_points() class Sector(AnnularSector): """A sector of a circle. Examples -------- .. manim:: ExampleSector :save_last_frame: class ExampleSector(Scene): def construct(self): sector = Sector(radius=2) sector2 = Sector(radius=2.5, angle=60*DEGREES).move_to([-3, 0, 0]) sector.set_color(RED) sector2.set_color(PINK) self.add(sector, sector2) """ def __init__(self, radius: float = 1, **kwargs: Any) -> None: super().__init__(inner_radius=0, outer_radius=radius, **kwargs) class Annulus(Circle): """Region between two concentric :class:`Circles <.Circle>`. Parameters ---------- inner_radius The radius of the inner :class:`Circle`. outer_radius The radius of the outer :class:`Circle`. kwargs Additional arguments to be passed to :class:`Annulus` Examples -------- .. manim:: AnnulusExample :save_last_frame: class AnnulusExample(Scene): def construct(self): annulus_1 = Annulus(inner_radius=0.5, outer_radius=1).shift(UP) annulus_2 = Annulus(inner_radius=0.3, outer_radius=0.6, color=RED).next_to(annulus_1, DOWN) self.add(annulus_1, annulus_2) """ def __init__( self, inner_radius: float = 1, outer_radius: float = 2, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, mark_paths_closed: bool = False, **kwargs: Any, ) -> None: self.mark_paths_closed = mark_paths_closed # is this even used? self.inner_radius = inner_radius self.outer_radius = outer_radius super().__init__( fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs ) def generate_points(self) -> None: self.radius = self.outer_radius outer_circle = Circle(radius=self.outer_radius) inner_circle = Circle(radius=self.inner_radius) inner_circle.reverse_points() self.append_points(outer_circle.points) self.append_points(inner_circle.points) self.shift(self.arc_center) def init_points(self) -> None: self.generate_points() class CubicBezier(VMobject, metaclass=ConvertToOpenGL): """A cubic Bézier curve. Example ------- .. manim:: BezierSplineExample :save_last_frame: class BezierSplineExample(Scene): def construct(self): p1 = np.array([-3, 1, 0]) p1b = p1 + [1, 0, 0] d1 = Dot(point=p1).set_color(BLUE) l1 = Line(p1, p1b) p2 = np.array([3, -1, 0]) p2b = p2 - [1, 0, 0] d2 = Dot(point=p2).set_color(RED) l2 = Line(p2, p2b) bezier = CubicBezier(p1b, p1b + 3 * RIGHT, p2b - 3 * RIGHT, p2b) self.add(l1, d1, l2, d2, bezier) """ def __init__( self, start_anchor: Point3DLike, start_handle: Point3DLike, end_handle: Point3DLike, end_anchor: Point3DLike, **kwargs: Any, ) -> None: super().__init__(**kwargs) self.add_cubic_bezier_curve(start_anchor, start_handle, end_handle, end_anchor) class ArcPolygon(VMobject, metaclass=ConvertToOpenGL): """A generalized polygon allowing for points to be connected with arcs. This version tries to stick close to the way :class:`Polygon` is used. Points can be passed to it directly which are used to generate the according arcs (using :class:`ArcBetweenPoints`). An angle or radius can be passed to it to use across all arcs, but to configure arcs individually an ``arc_config`` list has to be passed with the syntax explained below. Parameters ---------- vertices A list of vertices, start and end points for the arc segments. angle The angle used for constructing the arcs. If no other parameters are set, this angle is used to construct all arcs. radius The circle radius used to construct the arcs. If specified, overrides the specified ``angle``. arc_config When passing a ``dict``, its content will be passed as keyword arguments to :class:`~.ArcBetweenPoints`. Otherwise, a list of dictionaries containing values that are passed as keyword arguments for every individual arc can be passed. kwargs Further keyword arguments that are passed to the constructor of :class:`~.VMobject`. Attributes ---------- arcs : :class:`list` The arcs created from the input parameters:: >>> from manim import ArcPolygon >>> ap = ArcPolygon([0, 0, 0], [2, 0, 0], [0, 2, 0]) >>> ap.arcs [ArcBetweenPoints, ArcBetweenPoints, ArcBetweenPoints] .. tip:: Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``). .. note:: There is an alternative version (:class:`ArcPolygonFromArcs`) that is instantiated with pre-defined arcs. See Also -------- :class:`ArcPolygonFromArcs` Examples -------- .. manim:: SeveralArcPolygons class SeveralArcPolygons(Scene): def construct(self): a = [0, 0, 0] b = [2, 0, 0] c = [0, 2, 0] ap1 = ArcPolygon(a, b, c, radius=2) ap2 = ArcPolygon(a, b, c, angle=45*DEGREES) ap3 = ArcPolygon(a, b, c, arc_config={'radius': 1.7, 'color': RED}) ap4 = ArcPolygon(a, b, c, color=RED, fill_opacity=1, arc_config=[{'radius': 1.7, 'color': RED}, {'angle': 20*DEGREES, 'color': BLUE}, {'radius': 1}]) ap_group = VGroup(ap1, ap2, ap3, ap4).arrange() self.play(*[Create(ap) for ap in [ap1, ap2, ap3, ap4]]) self.wait() For further examples see :class:`ArcPolygonFromArcs`. """ def __init__( self, *vertices: Point3DLike, angle: float = PI / 4, radius: float | None = None, arc_config: list[dict] | None = None, **kwargs: Any, ) -> None: n = len(vertices) point_pairs = [(vertices[k], vertices[(k + 1) % n]) for k in range(n)] if not arc_config: if radius: all_arc_configs: Iterable[dict] = itertools.repeat( {"radius": radius}, len(point_pairs) ) else: all_arc_configs = itertools.repeat({"angle": angle}, len(point_pairs)) elif isinstance(arc_config, dict): all_arc_configs = itertools.repeat(arc_config, len(point_pairs)) else: assert len(arc_config) == n all_arc_configs = arc_config arcs = [ ArcBetweenPoints(*pair, **conf) for (pair, conf) in zip(point_pairs, all_arc_configs, strict=True) ] super().__init__(**kwargs) # Adding the arcs like this makes ArcPolygon double as a VGroup. # Also makes changes to the ArcPolygon, such as scaling, affect # the arcs, so that their new values are usable. self.add(*arcs) for arc in arcs: self.append_points(arc.points) # This enables the use of ArcPolygon.arcs as a convenience # because ArcPolygon[0] returns itself, not the first Arc. self.arcs = arcs class ArcPolygonFromArcs(VMobject, metaclass=ConvertToOpenGL): """A generalized polygon allowing for points to be connected with arcs. This version takes in pre-defined arcs to generate the arcpolygon and introduces little new syntax. However unlike :class:`Polygon` it can't be created with points directly. For proper appearance the passed arcs should connect seamlessly: ``[a,b][b,c][c,a]`` If there are any gaps between the arcs, those will be filled in with straight lines, which can be used deliberately for any straight sections. Arcs can also be passed as straight lines such as an arc initialized with ``angle=0``. Parameters ---------- arcs These are the arcs from which the arcpolygon is assembled. kwargs Keyword arguments that are passed to the constructor of :class:`~.VMobject`. Affects how the ArcPolygon itself is drawn, but doesn't affect passed arcs. Attributes ---------- arcs The arcs used to initialize the ArcPolygonFromArcs:: >>> from manim import ArcPolygonFromArcs, Arc, ArcBetweenPoints >>> ap = ArcPolygonFromArcs(Arc(), ArcBetweenPoints([1,0,0], [0,1,0]), Arc()) >>> ap.arcs [Arc, ArcBetweenPoints, Arc] .. tip:: Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``). .. note:: There is an alternative version (:class:`ArcPolygon`) that can be instantiated with points. .. seealso:: :class:`ArcPolygon` Examples -------- One example of an arcpolygon is the Reuleaux triangle. Instead of 3 straight lines connecting the outer points, a Reuleaux triangle has 3 arcs connecting those points, making a shape with constant width. Passed arcs are stored as submobjects in the arcpolygon. This means that the arcs are changed along with the arcpolygon, for example when it's shifted, and these arcs can be manipulated after the arcpolygon has been initialized. Also both the arcs contained in an :class:`~.ArcPolygonFromArcs`, as well as the arcpolygon itself are drawn, which affects draw time in :class:`~.Create` for example. In most cases the arcs themselves don't need to be drawn, in which case they can be passed as invisible. .. manim:: ArcPolygonExample class ArcPolygonExample(Scene): def construct(self): arc_conf = {"stroke_width": 0} poly_conf = {"stroke_width": 10, "stroke_color": BLUE, "fill_opacity": 1, "color": PURPLE} a = [-1, 0, 0] b = [1, 0, 0] c = [0, np.sqrt(3), 0] arc0 = ArcBetweenPoints(a, b, radius=2, **arc_conf) arc1 = ArcBetweenPoints(b, c, radius=2, **arc_conf) arc2 = ArcBetweenPoints(c, a, radius=2, **arc_conf) reuleaux_tri = ArcPolygonFromArcs(arc0, arc1, arc2, **poly_conf) self.play(FadeIn(reuleaux_tri)) self.wait(2) The arcpolygon itself can also be hidden so that instead only the contained arcs are drawn. This can be used to easily debug arcs or to highlight them. .. manim:: ArcPolygonExample2 class ArcPolygonExample2(Scene): def construct(self): arc_conf = {"stroke_width": 3, "stroke_color": BLUE, "fill_opacity": 0.5, "color": GREEN} poly_conf = {"color": None} a = [-1, 0, 0] b = [1, 0, 0] c = [0, np.sqrt(3), 0] arc0 = ArcBetweenPoints(a, b, radius=2, **arc_conf) arc1 = ArcBetweenPoints(b, c, radius=2, **arc_conf) arc2 = ArcBetweenPoints(c, a, radius=2, stroke_color=RED) reuleaux_tri = ArcPolygonFromArcs(arc0, arc1, arc2, **poly_conf) self.play(FadeIn(reuleaux_tri)) self.wait(2) """ def __init__(self, *arcs: Arc | ArcBetweenPoints, **kwargs: Any) -> None: if not all(isinstance(m, (Arc, ArcBetweenPoints)) for m in arcs): raise ValueError( "All ArcPolygon submobjects must be of type Arc/ArcBetweenPoints", ) super().__init__(**kwargs) # Adding the arcs like this makes ArcPolygonFromArcs double as a VGroup. # Also makes changes to the ArcPolygonFromArcs, such as scaling, affect # the arcs, so that their new values are usable. self.add(*arcs) # This enables the use of ArcPolygonFromArcs.arcs as a convenience # because ArcPolygonFromArcs[0] returns itself, not the first Arc. self.arcs = [*arcs] from .line import Line for arc1, arc2 in adjacent_pairs(arcs): self.append_points(arc1.points) line = Line(arc1.get_end(), arc2.get_start()) len_ratio = line.get_length() / arc1.get_arc_length() if np.isnan(len_ratio) or np.isinf(len_ratio): continue line.insert_n_curves(int(arc1.get_num_curves() * len_ratio)) self.append_points(line.points) ================================================ FILE: manim/mobject/geometry/boolean_ops.py ================================================ """Boolean operations for two-dimensional mobjects.""" from __future__ import annotations from typing import TYPE_CHECKING, Any import numpy as np from pathops import Path as SkiaPath from pathops import PathVerb, difference, intersection, union, xor from manim import config from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VMobject if TYPE_CHECKING: from manim.typing import Point2DLike_Array, Point3D_Array, Point3DLike_Array from ...constants import RendererType __all__ = ["Union", "Intersection", "Difference", "Exclusion"] class _BooleanOps(VMobject, metaclass=ConvertToOpenGL): """This class contains some helper functions which helps to convert to and from skia objects and manim objects (:class:`~.VMobject`). """ def _convert_2d_to_3d_array( self, points: Point2DLike_Array | Point3DLike_Array, z_dim: float = 0.0, ) -> Point3D_Array: """Converts an iterable with coordinates in 2D to 3D by adding :attr:`z_dim` as the Z coordinate. Parameters ---------- points An iterable of points. z_dim Default value for the Z coordinate. Returns ------- Point3D_Array A list of the points converted to 3D. Example ------- >>> a = _BooleanOps() >>> p = [(1, 2), (3, 4)] >>> a._convert_2d_to_3d_array(p) array([[1., 2., 0.], [3., 4., 0.]]) """ list_of_points = list(points) for i, point in enumerate(list_of_points): if len(point) == 2: list_of_points[i] = np.append(point, z_dim) return np.asarray(list_of_points) def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: """Converts a :class:`~.VMobject` to SkiaPath. This method only works for cairo renderer because it treats the points as Cubic beizer curves. Parameters ---------- vmobject: The :class:`~.VMobject` to convert from. Returns ------- SkiaPath The converted path. """ path = SkiaPath() if np.all(np.isfinite(vmobject.points)): points = vmobject.points else: points = np.zeros((1, 3)) # point invalid? if len(points) == 0: # what? No points so return empty path return path # In OpenGL it's quadratic beizer curves while on Cairo it's cubic... if config.renderer == RendererType.OPENGL: subpaths = vmobject.get_subpaths_from_points(points) for subpath in subpaths: quads = vmobject.get_bezier_tuples_from_points(subpath) start = subpath[0] path.moveTo(*start[:2]) for _p0, p1, p2 in quads: path.quadTo(*p1[:2], *p2[:2]) if vmobject.consider_points_equals(subpath[0], subpath[-1]): path.close() elif config.renderer == RendererType.CAIRO: subpaths = vmobject.gen_subpaths_from_points_2d(points) # type: ignore[assignment] for subpath in subpaths: quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath) start = subpath[0] path.moveTo(*start[:2]) for _p0, p1, p2, p3 in quads: path.cubicTo(*p1[:2], *p2[:2], *p3[:2]) if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): path.close() return path def _convert_skia_path_to_vmobject(self, path: SkiaPath) -> VMobject: """Converts SkiaPath back to VMobject. Parameters ---------- path: The SkiaPath to convert. Returns ------- VMobject: The converted VMobject. """ vmobject = self current_path_start = np.array([0, 0, 0]) for path_verb, points in path: if path_verb == PathVerb.MOVE: parts = self._convert_2d_to_3d_array(points) for part in parts: current_path_start = part vmobject.start_new_path(part) # vmobject.move_to(*part) elif path_verb == PathVerb.CUBIC: n1, n2, n3 = self._convert_2d_to_3d_array(points) vmobject.add_cubic_bezier_curve_to(n1, n2, n3) elif path_verb == PathVerb.LINE: parts = self._convert_2d_to_3d_array(points) vmobject.add_line_to(parts[0]) elif path_verb == PathVerb.CLOSE: vmobject.add_line_to(current_path_start) elif path_verb == PathVerb.QUAD: n1, n2 = self._convert_2d_to_3d_array(points) vmobject.add_quadratic_bezier_curve_to(n1, n2) else: raise Exception(f"Unsupported: {path_verb}") return vmobject class Union(_BooleanOps): """Union of two or more :class:`~.VMobject` s. This returns the common region of the :class:`~VMobject` s. Parameters ---------- vmobjects The :class:`~.VMobject` s to find the union of. Raises ------ ValueError If less than 2 :class:`~.VMobject` s are passed. Example ------- .. manim:: UnionExample :save_last_frame: class UnionExample(Scene): def construct(self): sq = Square(color=RED, fill_opacity=1) sq.move_to([-2, 0, 0]) cr = Circle(color=BLUE, fill_opacity=1) cr.move_to([-1.3, 0.7, 0]) un = Union(sq, cr, color=GREEN, fill_opacity=1) un.move_to([1.5, 0.3, 0]) self.add(sq, cr, un) """ def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None: if len(vmobjects) < 2: raise ValueError("At least 2 mobjects needed for Union.") super().__init__(**kwargs) paths = [ self._convert_vmobject_to_skia_path(vmobject) for vmobject in vmobjects ] outpen = SkiaPath() union(paths, outpen.getPen()) self._convert_skia_path_to_vmobject(outpen) class Difference(_BooleanOps): """Subtracts one :class:`~.VMobject` from another one. Parameters ---------- subject The 1st :class:`~.VMobject`. clip The 2nd :class:`~.VMobject` Example ------- .. manim:: DifferenceExample :save_last_frame: class DifferenceExample(Scene): def construct(self): sq = Square(color=RED, fill_opacity=1) sq.move_to([-2, 0, 0]) cr = Circle(color=BLUE, fill_opacity=1) cr.move_to([-1.3, 0.7, 0]) un = Difference(sq, cr, color=GREEN, fill_opacity=1) un.move_to([1.5, 0, 0]) self.add(sq, cr, un) """ def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None: super().__init__(**kwargs) outpen = SkiaPath() difference( [self._convert_vmobject_to_skia_path(subject)], [self._convert_vmobject_to_skia_path(clip)], outpen.getPen(), ) self._convert_skia_path_to_vmobject(outpen) class Intersection(_BooleanOps): """Find the intersection of two :class:`~.VMobject` s. This keeps the parts covered by both :class:`~.VMobject` s. Parameters ---------- vmobjects The :class:`~.VMobject` to find the intersection. Raises ------ ValueError If less the 2 :class:`~.VMobject` are passed. Example ------- .. manim:: IntersectionExample :save_last_frame: class IntersectionExample(Scene): def construct(self): sq = Square(color=RED, fill_opacity=1) sq.move_to([-2, 0, 0]) cr = Circle(color=BLUE, fill_opacity=1) cr.move_to([-1.3, 0.7, 0]) un = Intersection(sq, cr, color=GREEN, fill_opacity=1) un.move_to([1.5, 0, 0]) self.add(sq, cr, un) """ def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None: if len(vmobjects) < 2: raise ValueError("At least 2 mobjects needed for Intersection.") super().__init__(**kwargs) outpen = SkiaPath() intersection( [self._convert_vmobject_to_skia_path(vmobjects[0])], [self._convert_vmobject_to_skia_path(vmobjects[1])], outpen.getPen(), ) new_outpen = outpen for _i in range(2, len(vmobjects)): new_outpen = SkiaPath() intersection( [outpen], [self._convert_vmobject_to_skia_path(vmobjects[_i])], new_outpen.getPen(), ) outpen = new_outpen self._convert_skia_path_to_vmobject(outpen) class Exclusion(_BooleanOps): """Find the XOR between two :class:`~.VMobject`. This creates a new :class:`~.VMobject` consisting of the region covered by exactly one of them. Parameters ---------- subject The 1st :class:`~.VMobject`. clip The 2nd :class:`~.VMobject` Example ------- .. manim:: IntersectionExample :save_last_frame: class IntersectionExample(Scene): def construct(self): sq = Square(color=RED, fill_opacity=1) sq.move_to([-2, 0, 0]) cr = Circle(color=BLUE, fill_opacity=1) cr.move_to([-1.3, 0.7, 0]) un = Exclusion(sq, cr, color=GREEN, fill_opacity=1) un.move_to([1.5, 0.4, 0]) self.add(sq, cr, un) """ def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None: super().__init__(**kwargs) outpen = SkiaPath() xor( [self._convert_vmobject_to_skia_path(subject)], [self._convert_vmobject_to_skia_path(clip)], outpen.getPen(), ) self._convert_skia_path_to_vmobject(outpen) ================================================ FILE: manim/mobject/geometry/labeled.py ================================================ r"""Mobjects that inherit from lines and contain a label along the length.""" from __future__ import annotations __all__ = ["Label", "LabeledLine", "LabeledArrow", "LabeledPolygram"] from typing import TYPE_CHECKING, Any import numpy as np from manim.constants import * from manim.mobject.geometry.line import Arrow, Line from manim.mobject.geometry.polygram import Polygram from manim.mobject.geometry.shape_matchers import ( BackgroundRectangle, SurroundingRectangle, ) from manim.mobject.text.tex_mobject import MathTex, Tex from manim.mobject.text.text_mobject import Text from manim.mobject.types.vectorized_mobject import VGroup from manim.utils.color import WHITE from manim.utils.polylabel import polylabel if TYPE_CHECKING: from manim.typing import Point3DLike_Array class Label(VGroup): """A Label consisting of text surrounded by a frame. Parameters ---------- label Label that will be displayed. label_config A dictionary containing the configuration for the label. This is only applied if ``label`` is of type ``str``. box_config A dictionary containing the configuration for the background box. frame_config A dictionary containing the configuration for the frame. Examples -------- .. manim:: LabelExample :save_last_frame: :quality: high class LabelExample(Scene): def construct(self): label = Label( label=Text('Label Text', font='sans-serif'), box_config = { "color" : BLUE, "fill_opacity" : 0.75 } ) label.scale(3) self.add(label) """ def __init__( self, label: str | Tex | MathTex | Text, label_config: dict[str, Any] | None = None, box_config: dict[str, Any] | None = None, frame_config: dict[str, Any] | None = None, **kwargs: Any, ) -> None: super().__init__(**kwargs) # Setup Defaults default_label_config: dict[str, Any] = { "color": WHITE, "font_size": DEFAULT_FONT_SIZE, } default_box_config: dict[str, Any] = { "color": None, "buff": 0.05, "fill_opacity": 1, "stroke_width": 0.5, } default_frame_config: dict[str, Any] = { "color": WHITE, "buff": 0.05, "stroke_width": 0.5, } # Merge Defaults label_config = default_label_config | (label_config or {}) box_config = default_box_config | (box_config or {}) frame_config = default_frame_config | (frame_config or {}) # Determine the type of label and instantiate the appropriate object self.rendered_label: MathTex | Tex | Text if isinstance(label, str): self.rendered_label = MathTex(label, **label_config) elif isinstance(label, (MathTex, Tex, Text)): self.rendered_label = label else: raise TypeError("Unsupported label type. Must be MathTex, Tex, or Text.") # Add a background box self.background_rect = BackgroundRectangle(self.rendered_label, **box_config) # Add a frame around the label self.frame = SurroundingRectangle(self.rendered_label, **frame_config) # Add components to the VGroup self.add(self.background_rect, self.rendered_label, self.frame) class LabeledLine(Line): """Constructs a line containing a label box somewhere along its length. Parameters ---------- label Label that will be displayed on the line. label_position 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. label_config A dictionary containing the configuration for the label. This is only applied if ``label`` is of type ``str``. box_config A dictionary containing the configuration for the background box. frame_config A dictionary containing the configuration for the frame. .. seealso:: :class:`LabeledArrow` Examples -------- .. manim:: LabeledLineExample :save_last_frame: :quality: high class LabeledLineExample(Scene): def construct(self): line = LabeledLine( label = '0.5', label_position = 0.8, label_config = { "font_size" : 20 }, start=LEFT+DOWN, end=RIGHT+UP) line.set_length(line.get_length() * 2) self.add(line) """ def __init__( self, label: str | Tex | MathTex | Text, label_position: float = 0.5, label_config: dict[str, Any] | None = None, box_config: dict[str, Any] | None = None, frame_config: dict[str, Any] | None = None, *args: Any, **kwargs: Any, ) -> None: super().__init__(*args, **kwargs) # Create Label self.label = Label( label=label, label_config=label_config, box_config=box_config, frame_config=frame_config, ) # Compute Label Position line_start, line_end = self.get_start_and_end() new_vec = (line_end - line_start) * label_position label_coords = line_start + new_vec self.label.move_to(label_coords) self.add(self.label) class LabeledArrow(LabeledLine, Arrow): """Constructs an arrow containing a label box somewhere along its length. This class inherits its label properties from `LabeledLine`, so the main parameters controlling it are the same. Parameters ---------- label Label that will be displayed on the Arrow. label_position 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. label_config A dictionary containing the configuration for the label. This is only applied if ``label`` is of type ``str``. box_config A dictionary containing the configuration for the background box. frame_config A dictionary containing the configuration for the frame. .. seealso:: :class:`LabeledLine` Examples -------- .. manim:: LabeledArrowExample :save_last_frame: :quality: high class LabeledArrowExample(Scene): def construct(self): l_arrow = LabeledArrow("0.5", start=LEFT*3, end=RIGHT*3 + UP*2, label_position=0.5) self.add(l_arrow) """ def __init__( self, *args: Any, **kwargs: Any, ) -> None: super().__init__(*args, **kwargs) class LabeledPolygram(Polygram): """Constructs a polygram containing a label box at its pole of inaccessibility. Parameters ---------- vertex_groups Vertices passed to the :class:`~.Polygram` constructor. label Label that will be displayed on the Polygram. precision The precision used by the PolyLabel algorithm. label_config A dictionary containing the configuration for the label. This is only applied if ``label`` is of type ``str``. box_config A dictionary containing the configuration for the background box. frame_config A dictionary containing the configuration for the frame. .. note:: The PolyLabel Algorithm expects each vertex group to form a closed ring. If the input is open, :class:`LabeledPolygram` will attempt to close it. This may cause the polygon to intersect itself leading to unexpected results. .. tip:: Make sure the precision corresponds to the scale of your inputs! 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. Examples -------- .. manim:: LabeledPolygramExample :save_last_frame: :quality: high class LabeledPolygramExample(Scene): def construct(self): # Define Rings ring1 = [ [-3.8, -2.4, 0], [-2.4, -2.5, 0], [-1.3, -1.6, 0], [-0.2, -1.7, 0], [1.7, -2.5, 0], [2.9, -2.6, 0], [3.5, -1.5, 0], [4.9, -1.4, 0], [4.5, 0.2, 0], [4.7, 1.6, 0], [3.5, 2.4, 0], [1.1, 2.5, 0], [-0.1, 0.9, 0], [-1.2, 0.5, 0], [-1.6, 0.7, 0], [-1.4, 1.9, 0], [-2.6, 2.6, 0], [-4.4, 1.2, 0], [-4.9, -0.8, 0], [-3.8, -2.4, 0] ] ring2 = [ [0.2, -1.2, 0], [0.9, -1.2, 0], [1.4, -2.0, 0], [2.1, -1.6, 0], [2.2, -0.5, 0], [1.4, 0.0, 0], [0.4, -0.2, 0], [0.2, -1.2, 0] ] ring3 = [[-2.7, 1.4, 0], [-2.3, 1.7, 0], [-2.8, 1.9, 0], [-2.7, 1.4, 0]] # Create Polygons (for reference) p1 = Polygon(*ring1, fill_opacity=0.75) p2 = Polygon(*ring2, fill_color=BLACK, fill_opacity=1) p3 = Polygon(*ring3, fill_color=BLACK, fill_opacity=1) # Create Labeled Polygram polygram = LabeledPolygram( *[ring1, ring2, ring3], label=Text('Pole', font='sans-serif'), precision=0.01, ) # Display Circle (for reference) circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole) self.add(p1, p2, p3) self.add(polygram) self.add(circle) .. manim:: LabeledCountryExample :save_last_frame: :quality: high import requests import json class LabeledCountryExample(Scene): def construct(self): # Fetch JSON data and process arcs data = requests.get('https://cdn.jsdelivr.net/npm/us-atlas@3/nation-10m.json').json() arcs, transform = data['arcs'], data['transform'] sarcs = [np.cumsum(arc, axis=0) * transform['scale'] + transform['translate'] for arc in arcs] ssarcs = sorted(sarcs, key=len, reverse=True)[:1] # Compute Bounding Box points = np.concatenate(ssarcs) mins, maxs = np.min(points, axis=0), np.max(points, axis=0) # Build Axes ax = Axes( x_range=[mins[0], maxs[0], maxs[0] - mins[0]], x_length=10, y_range=[mins[1], maxs[1], maxs[1] - mins[1]], y_length=7, tips=False ) # Adjust Coordinates array = [[ax.c2p(*point) for point in sarc] for sarc in ssarcs] # Add Polygram polygram = LabeledPolygram( *array, label=Text('USA', font='sans-serif'), precision=0.01, fill_color=BLUE, stroke_width=0, fill_opacity=0.75 ) # Display Circle (for reference) circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole) self.add(ax) self.add(polygram) self.add(circle) """ def __init__( self, *vertex_groups: Point3DLike_Array, label: str | Tex | MathTex | Text, precision: float = 0.01, label_config: dict[str, Any] | None = None, box_config: dict[str, Any] | None = None, frame_config: dict[str, Any] | None = None, **kwargs: Any, ) -> None: # Initialize the Polygram with the vertex groups super().__init__(*vertex_groups, **kwargs) # Create Label self.label = Label( label=label, label_config=label_config, box_config=box_config, frame_config=frame_config, ) # Close Vertex Groups rings = [ group if np.array_equal(group[0], group[-1]) else list(group) + [group[0]] for group in vertex_groups ] # Compute the Pole of Inaccessibility cell = polylabel(rings, precision=precision) self.pole, self.radius = np.pad(cell.c, (0, 1), "constant"), cell.d # Position the label at the pole self.label.move_to(self.pole) self.add(self.label) ================================================ FILE: manim/mobject/geometry/line.py ================================================ r"""Mobjects that are lines or variations of them.""" from __future__ import annotations __all__ = [ "Line", "DashedLine", "TangentLine", "Elbow", "Arrow", "Vector", "DoubleArrow", "Angle", "RightAngle", ] from typing import TYPE_CHECKING, Any, Literal, cast import numpy as np from manim import config from manim.constants import * from manim.mobject.geometry.arc import Arc, ArcBetweenPoints, Dot, TipableVMobject from manim.mobject.geometry.tips import ArrowTip, ArrowTriangleFilledTip from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.types.vectorized_mobject import DashedVMobject, VGroup, VMobject from manim.utils.color import WHITE from manim.utils.space_ops import angle_of_vector, line_intersection, normalize if TYPE_CHECKING: from typing import Self, TypeAlias from manim.typing import Point3D, Point3DLike, Vector2DLike, Vector3D, Vector3DLike from manim.utils.color import ParsableManimColor from ..matrix import Matrix # Avoid circular import AngleQuadrant: TypeAlias = tuple[Literal[-1, 1], Literal[-1, 1]] r"""A tuple of 2 integers which can be either +1 or -1, allowing to select one of the 4 quadrants of the Cartesian plane. Let :math:`L_1,\ L_2` be two lines defined by start points :math:`S_1,\ S_2` and end points :math:`E_1,\ E_2`. We define the "positive direction" of :math:`L_1` as the direction from :math:`S_1` to :math:`E_1`, and its "negative direction" as the opposite one. We do the same with :math:`L_2`. If :math:`L_1` and :math:`L_2` intersect, they divide the plane into 4 quadrants. To pick one quadrant, choose the integers in this tuple in the following way: - If the 1st integer is +1, select one of the 2 quadrants towards the positive direction of :math:`L_1`, i.e. closest to `E_1`. Otherwise, if the 1st integer is -1, select one of the 2 quadrants towards the negative direction of :math:`L_1`, i.e. closest to `S_1`. - Similarly, the sign of the 2nd integer picks the positive or negative direction of :math:`L_2` and, thus, selects one of the 2 quadrants which are closest to :math:`E_2` or :math:`S_2` respectively. """ class Line(TipableVMobject): """A straight or curved line segment between two points or mobjects. Parameters ---------- start The starting point or Mobject of the line. end The ending point or Mobject of the line. buff The distance to shorten the line from both ends. path_arc If nonzero, the line will be curved into an arc with this angle (in radians). kwargs Additional arguments to be passed to :class:`TipableVMobject` Examples -------- .. manim:: LineExample :save_last_frame: class LineExample(Scene): def construct(self): line1 = Line(LEFT*2, RIGHT*2) line2 = Line(LEFT*2, RIGHT*2, buff=0.5) line3 = Line(LEFT*2, RIGHT*2, path_arc=PI/2) grp = VGroup(line1,line2,line3).arrange(DOWN, buff=2) self.add(grp) """ def __init__( self, start: Point3DLike | Mobject = LEFT, end: Point3DLike | Mobject = RIGHT, buff: float = 0, path_arc: float = 0, **kwargs: Any, ) -> None: self.dim = 3 self.buff = buff self.path_arc = path_arc self._set_start_and_end_attrs(start, end) super().__init__(**kwargs) def generate_points(self) -> None: self.set_points_by_ends( start=self.start, end=self.end, buff=self.buff, path_arc=self.path_arc, ) def set_points_by_ends( self, start: Point3DLike | Mobject, end: Point3DLike | Mobject, buff: float = 0, path_arc: float = 0, ) -> None: """Sets the points of the line based on its start and end points. Unlike :meth:`put_start_and_end_on`, this method respects `self.buff` and Mobject bounding boxes. Parameters ---------- start The start point or Mobject of the line. end The end point or Mobject of the line. buff The empty space between the start and end of the line, by default 0. path_arc The angle of a circle spanned by this arc, by default 0 which is a straight line. """ self._set_start_and_end_attrs(start, end) if path_arc: arc = ArcBetweenPoints(self.start, self.end, angle=self.path_arc) self.set_points(arc.points) else: self.set_points_as_corners(np.asarray([self.start, self.end])) self._account_for_buff(buff) def init_points(self) -> None: self.generate_points() def _account_for_buff(self, buff: float) -> None: if buff <= 0: return length = self.get_length() if self.path_arc == 0 else self.get_arc_length() if length < 2 * buff: return buff_proportion = buff / length self.pointwise_become_partial(self, buff_proportion, 1 - buff_proportion) def _set_start_and_end_attrs( self, start: Point3DLike | Mobject, end: Point3DLike | Mobject ) -> None: # If either start or end are Mobjects, this # gives their centers rough_start = self._pointify(start) rough_end = self._pointify(end) vect = normalize(rough_end - rough_start) # Now that we know the direction between them, # we can find the appropriate boundary point from # start and end, if they're mobjects self.start = self._pointify(start, vect) self.end = self._pointify(end, -vect) def _pointify( self, mob_or_point: Mobject | Point3DLike, direction: Vector3DLike | None = None, ) -> Point3D: """Transforms a mobject into its corresponding point. Does nothing if a point is passed. ``direction`` determines the location of the point along its bounding box in that direction. Parameters ---------- mob_or_point The mobject or point. direction The direction. """ if isinstance(mob_or_point, (Mobject, OpenGLMobject)): mob = mob_or_point if direction is None: return mob.get_center() else: return mob.get_boundary_point(direction) return np.array(mob_or_point) def set_path_arc(self, new_value: float) -> None: self.path_arc = new_value self.init_points() def put_start_and_end_on( self, start: Point3DLike, end: Point3DLike, ) -> Self: """Sets starts and end coordinates of a line. Examples -------- .. manim:: LineExample class LineExample(Scene): def construct(self): d = VGroup() for i in range(0,10): d.add(Dot()) d.arrange_in_grid(buff=1) self.add(d) l= Line(d[0], d[1]) self.add(l) self.wait() l.put_start_and_end_on(d[1].get_center(), d[2].get_center()) self.wait() l.put_start_and_end_on(d[4].get_center(), d[7].get_center()) self.wait() """ curr_start, curr_end = self.get_start_and_end() if np.all(curr_start == curr_end): # TODO, any problems with resetting # these attrs? self.start = np.asarray(start) self.end = np.asarray(end) self.generate_points() return super().put_start_and_end_on(start, end) def get_vector(self) -> Vector3D: return self.get_end() - self.get_start() def get_unit_vector(self) -> Vector3D: return normalize(self.get_vector()) def get_angle(self) -> float: return angle_of_vector(self.get_vector()) def get_projection(self, point: Point3DLike) -> Point3D: """Returns the projection of a point onto a line. Parameters ---------- point The point to which the line is projected. """ start = self.get_start() end = self.get_end() unit_vect = normalize(end - start) return start + float(np.dot(point - start, unit_vect)) * unit_vect def get_slope(self) -> float: return float(np.tan(self.get_angle())) def set_angle(self, angle: float, about_point: Point3DLike | None = None) -> Self: if about_point is None: about_point = self.get_start() self.rotate( angle - self.get_angle(), about_point=about_point, ) return self def set_length(self, length: float) -> Self: scale_factor: float = length / self.get_length() return self.scale(scale_factor) class DashedLine(Line): """A dashed :class:`Line`. Parameters ---------- args Arguments to be passed to :class:`Line` dash_length The length of each individual dash of the line. dashed_ratio The ratio of dash space to empty space. Range of 0-1. kwargs Additional arguments to be passed to :class:`Line` .. seealso:: :class:`~.DashedVMobject` Examples -------- .. manim:: DashedLineExample :save_last_frame: class DashedLineExample(Scene): def construct(self): # dash_length increased dashed_1 = DashedLine(config.left_side, config.right_side, dash_length=2.0).shift(UP*2) # normal dashed_2 = DashedLine(config.left_side, config.right_side) # dashed_ratio decreased dashed_3 = DashedLine(config.left_side, config.right_side, dashed_ratio=0.1).shift(DOWN*2) self.add(dashed_1, dashed_2, dashed_3) """ def __init__( self, *args: Any, dash_length: float = DEFAULT_DASH_LENGTH, dashed_ratio: float = 0.5, **kwargs: Any, ) -> None: self.dash_length = dash_length self.dashed_ratio = dashed_ratio super().__init__(*args, **kwargs) dashes = DashedVMobject( self, num_dashes=self._calculate_num_dashes(), dashed_ratio=dashed_ratio, ) self.clear_points() self.add(*dashes) def _calculate_num_dashes(self) -> int: """Returns the number of dashes in the dashed line. Examples -------- :: >>> DashedLine()._calculate_num_dashes() 20 """ # Minimum number of dashes has to be 2 return max( 2, int(np.ceil((self.get_length() / self.dash_length) * self.dashed_ratio)), ) def get_start(self) -> Point3D: """Returns the start point of the line. Examples -------- :: >>> DashedLine().get_start() array([-1., 0., 0.]) """ if len(self.submobjects) > 0: return self.submobjects[0].get_start() else: return super().get_start() def get_end(self) -> Point3D: """Returns the end point of the line. Examples -------- :: >>> DashedLine().get_end() array([1., 0., 0.]) """ if len(self.submobjects) > 0: return self.submobjects[-1].get_end() else: return super().get_end() def get_first_handle(self) -> Point3D: """Returns the point of the first handle. Examples -------- :: >>> DashedLine().get_first_handle() array([-0.98333333, 0. , 0. ]) """ # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 first_handle: Point3D = self.submobjects[0].points[1] return first_handle def get_last_handle(self) -> Point3D: """Returns the point of the last handle. Examples -------- :: >>> DashedLine().get_last_handle() array([0.98333333, 0. , 0. ]) """ # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 last_handle: Point3D = self.submobjects[-1].points[2] return last_handle class TangentLine(Line): """Constructs a line tangent to a :class:`~.VMobject` at a specific point. Parameters ---------- vmob The VMobject on which the tangent line is drawn. alpha How far along the shape that the line will be constructed. range: 0-1. length Length of the tangent line. d_alpha The ``dx`` value kwargs Additional arguments to be passed to :class:`Line` .. seealso:: :meth:`~.VMobject.point_from_proportion` Examples -------- .. manim:: TangentLineExample :save_last_frame: class TangentLineExample(Scene): def construct(self): circle = Circle(radius=2) line_1 = TangentLine(circle, alpha=0.0, length=4, color=BLUE_D) # right line_2 = TangentLine(circle, alpha=0.4, length=4, color=GREEN) # top left self.add(circle, line_1, line_2) """ def __init__( self, vmob: VMobject, alpha: float, length: float = 1, d_alpha: float = 1e-6, **kwargs: Any, ) -> None: self.length = length self.d_alpha = d_alpha da = self.d_alpha a1 = np.clip(alpha - da, 0, 1) a2 = np.clip(alpha + da, 0, 1) super().__init__( vmob.point_from_proportion(a1), vmob.point_from_proportion(a2), **kwargs ) self.scale(self.length / self.get_length()) class Elbow(VMobject, metaclass=ConvertToOpenGL): """Two lines that create a right angle about each other: L-shape. Parameters ---------- width The length of the elbow's sides. angle The rotation of the elbow. kwargs Additional arguments to be passed to :class:`~.VMobject` .. seealso:: :class:`RightAngle` Examples -------- .. manim:: ElbowExample :save_last_frame: class ElbowExample(Scene): def construct(self): elbow_1 = Elbow() elbow_2 = Elbow(width=2.0) elbow_3 = Elbow(width=2.0, angle=5*PI/4) elbow_group = Group(elbow_1, elbow_2, elbow_3).arrange(buff=1) self.add(elbow_group) """ def __init__(self, width: float = 0.2, angle: float = 0, **kwargs: Any) -> None: self.angle = angle super().__init__(**kwargs) self.set_points_as_corners(np.array([UP, UP + RIGHT, RIGHT])) self.scale_to_fit_width(width, about_point=ORIGIN) self.rotate(self.angle, about_point=ORIGIN) class Arrow(Line): """An arrow. Parameters ---------- args Arguments to be passed to :class:`Line`. stroke_width The thickness of the arrow. Influenced by :attr:`max_stroke_width_to_length_ratio`. buff The distance of the arrow from its start and end points. max_tip_length_to_length_ratio :attr:`tip_length` scales with the length of the arrow. Increasing this ratio raises the max value of :attr:`tip_length`. max_stroke_width_to_length_ratio :attr:`stroke_width` scales with the length of the arrow. Increasing this ratio ratios the max value of :attr:`stroke_width`. kwargs Additional arguments to be passed to :class:`Line`. .. seealso:: :class:`ArrowTip` :class:`CurvedArrow` Examples -------- .. manim:: ArrowExample :save_last_frame: from manim.mobject.geometry.tips import ArrowSquareTip class ArrowExample(Scene): def construct(self): arrow_1 = Arrow(start=RIGHT, end=LEFT, color=GOLD) arrow_2 = Arrow(start=RIGHT, end=LEFT, color=GOLD, tip_shape=ArrowSquareTip).shift(DOWN) g1 = Group(arrow_1, arrow_2) # the effect of buff square = Square(color=MAROON_A) arrow_3 = Arrow(start=LEFT, end=RIGHT) arrow_4 = Arrow(start=LEFT, end=RIGHT, buff=0).next_to(arrow_1, UP) g2 = Group(arrow_3, arrow_4, square) # a shorter arrow has a shorter tip and smaller stroke width arrow_5 = Arrow(start=ORIGIN, end=config.top).shift(LEFT * 4) arrow_6 = Arrow(start=config.top + DOWN, end=config.top).shift(LEFT * 3) g3 = Group(arrow_5, arrow_6) self.add(Group(g1, g2, g3).arrange(buff=2)) .. manim:: ArrowExample :save_last_frame: class ArrowExample(Scene): def construct(self): left_group = VGroup() # As buff increases, the size of the arrow decreases. for buff in np.arange(0, 2.2, 0.45): left_group += Arrow(buff=buff, start=2 * LEFT, end=2 * RIGHT) # Required to arrange arrows. left_group.arrange(DOWN) left_group.move_to(4 * LEFT) middle_group = VGroup() # As max_stroke_width_to_length_ratio gets bigger, # the width of stroke increases. for i in np.arange(0, 5, 0.5): middle_group += Arrow(max_stroke_width_to_length_ratio=i) middle_group.arrange(DOWN) UR_group = VGroup() # As max_tip_length_to_length_ratio increases, # the length of the tip increases. for i in np.arange(0, 0.3, 0.1): UR_group += Arrow(max_tip_length_to_length_ratio=i) UR_group.arrange(DOWN) UR_group.move_to(4 * RIGHT + 2 * UP) DR_group = VGroup() DR_group += Arrow(start=LEFT, end=RIGHT, color=BLUE, tip_shape=ArrowSquareTip) DR_group += Arrow(start=LEFT, end=RIGHT, color=BLUE, tip_shape=ArrowSquareFilledTip) DR_group += Arrow(start=LEFT, end=RIGHT, color=YELLOW, tip_shape=ArrowCircleTip) DR_group += Arrow(start=LEFT, end=RIGHT, color=YELLOW, tip_shape=ArrowCircleFilledTip) DR_group.arrange(DOWN) DR_group.move_to(4 * RIGHT + 2 * DOWN) self.add(left_group, middle_group, UR_group, DR_group) """ def __init__( self, *args: Any, stroke_width: float = 6, buff: float = MED_SMALL_BUFF, max_tip_length_to_length_ratio: float = 0.25, max_stroke_width_to_length_ratio: float = 5, **kwargs: Any, ) -> None: self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) # type: ignore[misc] # TODO, should this be affected when # Arrow.set_stroke is called? self.initial_stroke_width = self.stroke_width self.add_tip(tip_shape=tip_shape) self._set_stroke_width_from_length() def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: # type: ignore[override] r"""Scale an arrow, but keep stroke width and arrow tip size fixed. .. seealso:: :meth:`~.Mobject.scale` Examples -------- :: >>> arrow = Arrow(np.array([-1, -1, 0]), np.array([1, 1, 0]), buff=0) >>> scaled_arrow = arrow.scale(2) >>> np.round(scaled_arrow.get_start_and_end(), 8) + 0 array([[-2., -2., 0.], [ 2., 2., 0.]]) >>> arrow.tip.length == scaled_arrow.tip.length True Manually scaling the object using the default method :meth:`~.Mobject.scale` does not have the same properties:: >>> new_arrow = Arrow(np.array([-1, -1, 0]), np.array([1, 1, 0]), buff=0) >>> another_scaled_arrow = VMobject.scale(new_arrow, 2) >>> another_scaled_arrow.tip.length == arrow.tip.length False """ if self.get_length() == 0: return self if scale_tips: super().scale(factor, **kwargs) self._set_stroke_width_from_length() return self has_tip = self.has_tip() has_start_tip = self.has_start_tip() if has_tip or has_start_tip: old_tips = self.pop_tips() super().scale(factor, **kwargs) self._set_stroke_width_from_length() if has_tip: # error: Argument "tip" to "add_tip" of "TipableVMobject" has incompatible type "VMobject"; expected "ArrowTip | None" [arg-type] self.add_tip(tip=cast(ArrowTip, old_tips[0])) if has_start_tip: # error: Argument "tip" to "add_tip" of "TipableVMobject" has incompatible type "VMobject"; expected "ArrowTip | None" [arg-type] self.add_tip(tip=cast(ArrowTip, old_tips[1]), at_start=True) return self def get_normal_vector(self) -> Vector3D: """Returns the normal of a vector. Examples -------- :: >>> 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)) def reset_normal_vector(self) -> Self: """Resets the normal of a vector""" self.normal_vector = self.get_normal_vector() return self def get_default_tip_length(self) -> float: """Returns the default tip_length of the arrow. Examples -------- :: >>> 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()) def _set_stroke_width_from_length(self) -> Self: """Sets stroke width based on length.""" max_ratio = self.max_stroke_width_to_length_ratio if config.renderer == RendererType.OPENGL: # Mypy does not recognize that the self object in this case # is a OpenGLVMobject and that the set_stroke method is # defined here: # mobject/opengl/opengl_vectorized_mobject.py#L248 self.set_stroke( # type: ignore[call-arg] width=min(self.initial_stroke_width, max_ratio * self.get_length()), recurse=False, ) else: self.set_stroke( width=min(self.initial_stroke_width, max_ratio * self.get_length()), family=False, ) return self class Vector(Arrow): """A vector specialized for use in graphs. .. caution:: Do not confuse with the :class:`~.Vector2D`, :class:`~.Vector3D` or :class:`~.VectorND` type aliases, which are not Mobjects! Parameters ---------- direction The direction of the arrow. buff The distance of the vector from its endpoints. kwargs Additional arguments to be passed to :class:`Arrow` Examples -------- .. manim:: VectorExample :save_last_frame: class VectorExample(Scene): def construct(self): plane = NumberPlane() vector_1 = Vector([1,2]) vector_2 = Vector([-5,-2]) self.add(plane, vector_1, vector_2) """ def __init__( self, direction: Vector2DLike | Vector3DLike = RIGHT, buff: float = 0, **kwargs: Any, ) -> None: self.buff = buff if len(direction) == 2: direction = np.hstack([direction, 0]) super().__init__(ORIGIN, direction, buff=buff, **kwargs) def coordinate_label( self, integer_labels: bool = True, n_dim: int = 2, color: ParsableManimColor | None = None, **kwargs: Any, ) -> Matrix: """Creates a label based on the coordinates of the vector. Parameters ---------- integer_labels Whether or not to round the coordinates to integers. n_dim The number of dimensions of the vector. color Sets the color of label, optional. kwargs Additional arguments to be passed to :class:`~.Matrix`. Returns ------- :class:`~.Matrix` The label. Examples -------- .. manim:: VectorCoordinateLabel :save_last_frame: class VectorCoordinateLabel(Scene): def construct(self): plane = NumberPlane() vec_1 = Vector([1, 2]) vec_2 = Vector([-3, -2]) label_1 = vec_1.coordinate_label() label_2 = vec_2.coordinate_label(color=YELLOW) self.add(plane, vec_1, vec_2, label_1, label_2) """ # avoiding circular imports from ..matrix import Matrix vect = np.array(self.get_end()) if integer_labels: vect = np.round(vect).astype(int) vect = vect[:n_dim] vect = vect.reshape((n_dim, 1)) label = Matrix(vect, **kwargs) label.scale(LARGE_BUFF - 0.2) shift_dir = np.array(self.get_end()) if shift_dir[0] >= 0: # Pointing right shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * LEFT else: # Pointing left shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * RIGHT label.shift(shift_dir) if color is not None: label.set_color(color) return label class DoubleArrow(Arrow): """An arrow with tips on both ends. Parameters ---------- args Arguments to be passed to :class:`Arrow` kwargs Additional arguments to be passed to :class:`Arrow` .. seealso:: :class:`.~ArrowTip` :class:`.~CurvedDoubleArrow` Examples -------- .. manim:: DoubleArrowExample :save_last_frame: from manim.mobject.geometry.tips import ArrowCircleFilledTip class DoubleArrowExample(Scene): def construct(self): circle = Circle(radius=2.0) d_arrow = DoubleArrow(start=circle.get_left(), end=circle.get_right()) d_arrow_2 = DoubleArrow(tip_shape_end=ArrowCircleFilledTip, tip_shape_start=ArrowCircleFilledTip) group = Group(Group(circle, d_arrow), d_arrow_2).arrange(UP, buff=1) self.add(group) .. manim:: DoubleArrowExample2 :save_last_frame: class DoubleArrowExample2(Scene): def construct(self): box = Square() p1 = box.get_left() p2 = box.get_right() d1 = DoubleArrow(p1, p2, buff=0) d2 = DoubleArrow(p1, p2, buff=0, tip_length=0.2, color=YELLOW) d3 = DoubleArrow(p1, p2, buff=0, tip_length=0.4, color=BLUE) Group(d1, d2, d3).arrange(DOWN) self.add(box, d1, d2, d3) """ def __init__(self, *args: Any, **kwargs: Any) -> None: if "tip_shape_end" in kwargs: kwargs["tip_shape"] = kwargs.pop("tip_shape_end") tip_shape_start = kwargs.pop("tip_shape_start", ArrowTriangleFilledTip) super().__init__(*args, **kwargs) self.add_tip(at_start=True, tip_shape=tip_shape_start) class Angle(VMobject, metaclass=ConvertToOpenGL): """A circular arc or elbow-type mobject representing an angle of two lines. Parameters ---------- line1 : The first line. line2 : The second line. radius : The radius of the :class:`Arc`. quadrant A sequence of two :class:`int` numbers determining which of the 4 quadrants should be used. The first value indicates whether to anchor the arc on the first line closer to the end point (1) or start point (-1), and the second value functions similarly for the end (1) or start (-1) of the second line. Possibilities: (1,1), (-1,1), (1,-1), (-1,-1). other_angle : Toggles between the two possible angles defined by two points and an arc center. If set to False (default), the arc will always go counterclockwise from the point on line1 until the point on line2 is reached. If set to True, the angle will go clockwise from line1 to line2. dot Allows for a :class:`Dot` in the arc. Mainly used as an convention to indicate a right angle. The dot can be customized in the next three parameters. dot_radius The radius of the :class:`Dot`. If not specified otherwise, this radius will be 1/10 of the arc radius. dot_distance Relative distance from the center to the arc: 0 puts the dot in the center and 1 on the arc itself. dot_color The color of the :class:`Dot`. elbow Produces an elbow-type mobject indicating a right angle, see :class:`RightAngle` for more information and a shorthand. **kwargs Further keyword arguments that are passed to the constructor of :class:`Arc` or :class:`Elbow`. Examples -------- The first example shows some right angles with a dot in the middle while the second example shows all 8 possible angles defined by two lines. .. manim:: RightArcAngleExample :save_last_frame: class RightArcAngleExample(Scene): def construct(self): line1 = Line( LEFT, RIGHT ) line2 = Line( DOWN, UP ) rightarcangles = [ Angle(line1, line2, dot=True), Angle(line1, line2, radius=0.4, quadrant=(1,-1), dot=True, other_angle=True), Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, dot=True, dot_color=YELLOW, dot_radius=0.04, other_angle=True), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, dot=True, dot_color=GREEN, dot_radius=0.08), ] plots = VGroup() for angle in rightarcangles: plot=VGroup(line1.copy(),line2.copy(), angle) plots.add(plot) plots.arrange(buff=1.5) self.add(plots) .. manim:: AngleExample :save_last_frame: class AngleExample(Scene): def construct(self): line1 = Line( LEFT + (1/3) * UP, RIGHT + (1/3) * DOWN ) line2 = Line( DOWN + (1/3) * RIGHT, UP + (1/3) * LEFT ) angles = [ Angle(line1, line2), Angle(line1, line2, radius=0.4, quadrant=(1,-1), other_angle=True), Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, other_angle=True), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED), Angle(line1, line2, other_angle=True), Angle(line1, line2, radius=0.4, quadrant=(1,-1)), Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True), ] plots = VGroup() for angle in angles: plot=VGroup(line1.copy(),line2.copy(), angle) plots.add(VGroup(plot,SurroundingRectangle(plot, buff=0.3))) plots.arrange_in_grid(rows=2,buff=1) self.add(plots) .. manim:: FilledAngle :save_last_frame: class FilledAngle(Scene): def construct(self): l1 = Line(ORIGIN, 2 * UP + RIGHT).set_color(GREEN) l2 = ( Line(ORIGIN, 2 * UP + RIGHT) .set_color(GREEN) .rotate(-20 * DEGREES, about_point=ORIGIN) ) norm = l1.get_length() a1 = Angle(l1, l2, other_angle=True, radius=norm - 0.5).set_color(GREEN) a2 = Angle(l1, l2, other_angle=True, radius=norm).set_color(GREEN) q1 = a1.points # save all coordinates of points of angle a1 q2 = a2.reverse_direction().points # save all coordinates of points of angle a1 (in reversed direction) pnts = np.concatenate([q1, q2, q1[0].reshape(1, 3)]) # adds points and ensures that path starts and ends at same point mfill = VMobject().set_color(ORANGE) mfill.set_points_as_corners(pnts).set_fill(GREEN, opacity=1) self.add(l1, l2) self.add(mfill) """ def __init__( self, line1: Line, line2: Line, radius: float | None = None, quadrant: AngleQuadrant = (1, 1), other_angle: bool = False, dot: bool = False, dot_radius: float | None = None, dot_distance: float = 0.55, dot_color: ParsableManimColor = WHITE, elbow: bool = False, **kwargs: Any, ) -> None: super().__init__(**kwargs) self.lines = (line1, line2) self.quadrant = quadrant self.dot_distance = dot_distance self.elbow = elbow inter = line_intersection( [line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()], ) if radius is None: if quadrant[0] == 1: dist_1 = np.linalg.norm(line1.get_end() - inter) else: dist_1 = np.linalg.norm(line1.get_start() - inter) if quadrant[1] == 1: dist_2 = np.linalg.norm(line2.get_end() - inter) else: dist_2 = np.linalg.norm(line2.get_start() - inter) if np.minimum(dist_1, dist_2) < 0.6: radius = (2 / 3) * np.minimum(dist_1, dist_2) else: radius = 0.4 else: self.radius = radius anchor_angle_1 = inter + quadrant[0] * radius * line1.get_unit_vector() anchor_angle_2 = inter + quadrant[1] * radius * line2.get_unit_vector() if elbow: anchor_middle = ( inter + quadrant[0] * radius * line1.get_unit_vector() + quadrant[1] * radius * line2.get_unit_vector() ) angle_mobject: VMobject = Elbow(**kwargs) angle_mobject.set_points_as_corners( np.array([anchor_angle_1, anchor_middle, anchor_angle_2]), ) else: angle_1 = angle_of_vector(anchor_angle_1 - inter) angle_2 = angle_of_vector(anchor_angle_2 - inter) if not other_angle: start_angle = angle_1 if angle_2 > angle_1: angle_fin = angle_2 - angle_1 else: angle_fin = 2 * np.pi - (angle_1 - angle_2) else: start_angle = angle_1 if angle_2 < angle_1: angle_fin = -angle_1 + angle_2 else: angle_fin = -2 * np.pi + (angle_2 - angle_1) self.angle_value = angle_fin angle_mobject = Arc( radius=radius, angle=self.angle_value, start_angle=start_angle, arc_center=inter, **kwargs, ) if dot: if dot_radius is None: dot_radius = radius / 10 else: self.dot_radius = dot_radius right_dot = Dot(ORIGIN, radius=dot_radius, color=dot_color) dot_anchor = ( inter + (angle_mobject.get_center() - inter) / np.linalg.norm(angle_mobject.get_center() - inter) * radius * dot_distance ) right_dot.move_to(dot_anchor) self.add(right_dot) self.set_points(angle_mobject.points) def get_lines(self) -> VGroup: """Get the lines forming an angle of the :class:`Angle` class. Returns ------- :class:`~.VGroup` A :class:`~.VGroup` containing the lines that form the angle of the :class:`Angle` class. Examples -------- :: >>> line_1, line_2 = Line(ORIGIN, RIGHT), Line(ORIGIN, UR) >>> angle = Angle(line_1, line_2) >>> angle.get_lines() VGroup(Line, Line) """ return VGroup(*self.lines) def get_value(self, degrees: bool = False) -> float: r"""Get the value of an angle of the :class:`Angle` class. Parameters ---------- degrees A boolean to decide the unit (deg/rad) in which the value of the angle is returned. Returns ------- :class:`float` The value in degrees/radians of an angle of the :class:`Angle` class. Examples -------- .. manim:: GetValueExample :save_last_frame: class GetValueExample(Scene): def construct(self): line1 = Line(LEFT+(1/3)*UP, RIGHT+(1/3)*DOWN) line2 = Line(DOWN+(1/3)*RIGHT, UP+(1/3)*LEFT) angle = Angle(line1, line2, radius=0.4) value = DecimalNumber(angle.get_value(degrees=True), unit=r"^{\circ}") value.next_to(angle, UR) self.add(line1, line2, angle, value) """ return self.angle_value / DEGREES if degrees else self.angle_value @staticmethod def from_three_points( A: Point3DLike, B: Point3DLike, C: Point3DLike, **kwargs: Any ) -> Angle: r"""The angle between the lines AB and BC. This constructs the angle :math:`\\angle ABC`. Parameters ---------- A The endpoint of the first angle leg B The vertex of the angle C The endpoint of the second angle leg **kwargs Further keyword arguments are passed to :class:`.Angle` Returns ------- The Angle calculated from the three points Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True), Examples -------- .. manim:: AngleFromThreePointsExample :save_last_frame: class AngleFromThreePointsExample(Scene): def construct(self): sample_angle = Angle.from_three_points(UP, ORIGIN, LEFT) red_angle = Angle.from_three_points(LEFT + UP, ORIGIN, RIGHT, radius=.8, quadrant=(-1,-1), color=RED, stroke_width=8, other_angle=True) self.add(red_angle, sample_angle) """ return Angle(Line(B, A), Line(B, C), **kwargs) class RightAngle(Angle): """An elbow-type mobject representing a right angle between two lines. Parameters ---------- line1 The first line. line2 The second line. length The length of the arms. **kwargs Further keyword arguments that are passed to the constructor of :class:`Angle`. Examples -------- .. manim:: RightAngleExample :save_last_frame: class RightAngleExample(Scene): def construct(self): line1 = Line( LEFT, RIGHT ) line2 = Line( DOWN, UP ) rightangles = [ RightAngle(line1, line2), RightAngle(line1, line2, length=0.4, quadrant=(1,-1)), RightAngle(line1, line2, length=0.5, quadrant=(-1,1), stroke_width=8), RightAngle(line1, line2, length=0.7, quadrant=(-1,-1), color=RED), ] plots = VGroup() for rightangle in rightangles: plot=VGroup(line1.copy(),line2.copy(), rightangle) plots.add(plot) plots.arrange(buff=1.5) self.add(plots) """ def __init__( self, line1: Line, line2: Line, length: float | None = None, **kwargs: Any, ) -> None: super().__init__(line1, line2, radius=length, elbow=True, **kwargs) ================================================ FILE: manim/mobject/geometry/polygram.py ================================================ r"""Mobjects that are simple geometric shapes.""" from __future__ import annotations __all__ = [ "Polygram", "Polygon", "RegularPolygram", "RegularPolygon", "Star", "Triangle", "Rectangle", "Square", "RoundedRectangle", "Cutout", "ConvexHull", ] from math import ceil from typing import TYPE_CHECKING, Any, Literal import numpy as np from manim.constants import * from manim.mobject.geometry.arc import ArcBetweenPoints from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.color import BLUE, WHITE, ParsableManimColor from manim.utils.iterables import adjacent_n_tuples, adjacent_pairs from manim.utils.qhull import QuickHull from manim.utils.space_ops import angle_between_vectors, normalize, regular_vertices if TYPE_CHECKING: from typing import Self import numpy.typing as npt from manim.typing import ( Point3D, Point3D_Array, Point3DLike, Point3DLike_Array, ) from manim.utils.color import ParsableManimColor class Polygram(VMobject, metaclass=ConvertToOpenGL): """A generalized :class:`Polygon`, allowing for disconnected sets of edges. Parameters ---------- vertex_groups The groups of vertices making up the :class:`Polygram`. The first vertex in each group is repeated to close the shape. Each point must be 3-dimensional: ``[x,y,z]`` color The color of the :class:`Polygram`. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: PolygramExample import numpy as np class PolygramExample(Scene): def construct(self): hexagram = Polygram( [[0, 2, 0], [-np.sqrt(3), -1, 0], [np.sqrt(3), -1, 0]], [[-np.sqrt(3), 1, 0], [0, -2, 0], [np.sqrt(3), 1, 0]], ) self.add(hexagram) dot = Dot() self.play(MoveAlongPath(dot, hexagram), run_time=5, rate_func=linear) self.remove(dot) self.wait() """ def __init__( self, *vertex_groups: Point3DLike_Array, color: ParsableManimColor = BLUE, **kwargs: Any, ): super().__init__(color=color, **kwargs) for vertices in vertex_groups: # The inferred type for *vertices is Any, but it should be # Point3D_Array first_vertex, *vertices = vertices first_vertex = np.array(first_vertex) self.start_new_path(first_vertex) self.add_points_as_corners( [*(np.array(vertex) for vertex in vertices), first_vertex], ) def get_vertices(self) -> Point3D_Array: """Gets the vertices of the :class:`Polygram`. Returns ------- :class:`numpy.ndarray` The vertices of the :class:`Polygram`. Examples -------- :: >>> sq = Square() >>> sq.get_vertices() array([[ 1., 1., 0.], [-1., 1., 0.], [-1., -1., 0.], [ 1., -1., 0.]]) """ return self.get_start_anchors() def get_vertex_groups(self) -> list[Point3D_Array]: """Gets the vertex groups of the :class:`Polygram`. Returns ------- list[Point3D_Array] The list of vertex groups of the :class:`Polygram`. Examples -------- :: >>> poly = Polygram([ORIGIN, RIGHT, UP, LEFT + UP], [LEFT, LEFT + UP, 2 * LEFT]) >>> groups = poly.get_vertex_groups() >>> len(groups) 2 >>> groups[0] array([[ 0., 0., 0.], [ 1., 0., 0.], [ 0., 1., 0.], [-1., 1., 0.]]) >>> groups[1] array([[-1., 0., 0.], [-1., 1., 0.], [-2., 0., 0.]]) """ vertex_groups = [] # TODO: If any of the original vertex groups contained the starting vertex N # times, then .get_vertex_groups() splits it into N vertex groups. group = [] for start, end in zip( self.get_start_anchors(), self.get_end_anchors(), strict=True ): group.append(start) if self.consider_points_equals(end, group[0]): vertex_groups.append(np.array(group)) group = [] return vertex_groups def round_corners( self, radius: float | list[float] = 0.5, evenly_distribute_anchors: bool = False, components_per_rounded_corner: int = 2, ) -> Self: """Rounds off the corners of the :class:`Polygram`. Parameters ---------- radius The curvature of the corners of the :class:`Polygram`. evenly_distribute_anchors Break long line segments into proportionally-sized segments. components_per_rounded_corner The number of points used to represent the rounded corner curve. .. seealso:: :class:`.~RoundedRectangle` .. note:: If `radius` is supplied as a single value, then the same radius will be applied to all corners. If `radius` is a list, then the individual values will be applied sequentially, with the first corner receiving `radius[0]`, the second corner receiving `radius[1]`, etc. The radius list will be repeated as necessary. The `components_per_rounded_corner` value is provided so that the fidelity of the rounded corner may be fine-tuned as needed. 2 is an appropriate value for most shapes, however a larger value may be need if the rounded corner is particularly large. 2 is the minimum number allowed, representing the start and end of the curve. 3 will result in a start, middle, and end point, meaning 2 curves will be generated. The option to `evenly_distribute_anchors` is provided so that the line segments (the part part of each line remaining after rounding off the corners) can be subdivided to a density similar to that of the average density of the rounded corners. This may be desirable in situations in which an even distribution of curves is desired for use in later transformation animations. Be aware, though, that enabling this option can result in an an object containing significantly more points than the original, especially when the rounded corner curves are small. Examples -------- .. manim:: PolygramRoundCorners :save_last_frame: class PolygramRoundCorners(Scene): def construct(self): star = Star(outer_radius=2) shapes = VGroup(star) shapes.add(star.copy().round_corners(radius=0.1)) shapes.add(star.copy().round_corners(radius=0.25)) shapes.arrange(RIGHT) self.add(shapes) """ if radius == 0: return self new_points: list[Point3D] = [] for vertex_group in self.get_vertex_groups(): arcs = [] # Repeat the radius list as necessary in order to provide a radius # for each vertex. if isinstance(radius, (int, float)): radius_list = [radius] * len(vertex_group) else: radius_list = radius * ceil(len(vertex_group) / len(radius)) for current_radius, (v1, v2, v3) in zip( radius_list, adjacent_n_tuples(vertex_group, 3), strict=True ): vect1 = v2 - v1 vect2 = v3 - v2 unit_vect1 = normalize(vect1) unit_vect2 = normalize(vect2) angle = angle_between_vectors(vect1, vect2) # Negative radius gives concave curves angle *= np.sign(current_radius) # Distance between vertex and start of the arc cut_off_length = current_radius * np.tan(angle / 2) # Determines counterclockwise vs. clockwise sign = np.sign(np.cross(vect1, vect2)[2]) arc = ArcBetweenPoints( v2 - unit_vect1 * cut_off_length, v2 + unit_vect2 * cut_off_length, angle=sign * angle, num_components=components_per_rounded_corner, ) arcs.append(arc) if evenly_distribute_anchors: # Determine the average length of each curve nonzero_length_arcs = [arc for arc in arcs if len(arc.points) > 4] if len(nonzero_length_arcs) > 0: total_arc_length = sum( [arc.get_arc_length() for arc in nonzero_length_arcs] ) num_curves = ( sum([len(arc.points) for arc in nonzero_length_arcs]) / 4 ) average_arc_length = total_arc_length / num_curves else: average_arc_length = 1.0 # To ensure that we loop through starting with last arcs = [arcs[-1], *arcs[:-1]] from manim.mobject.geometry.line import Line for arc1, arc2 in adjacent_pairs(arcs): new_points.extend(arc1.points) line = Line(arc1.get_end(), arc2.get_start()) # Make sure anchors are evenly distributed, if necessary if evenly_distribute_anchors: line.insert_n_curves(ceil(line.get_length() / average_arc_length)) new_points.extend(line.points) self.set_points(np.array(new_points)) return self class Polygon(Polygram): """A shape consisting of one closed loop of vertices. Parameters ---------- vertices The vertices of the :class:`Polygon`. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: PolygonExample :save_last_frame: class PolygonExample(Scene): def construct(self): isosceles = Polygon([-5, 1.5, 0], [-2, 1.5, 0], [-3.5, -2, 0]) position_list = [ [4, 1, 0], # middle right [4, -2.5, 0], # bottom right [0, -2.5, 0], # bottom left [0, 3, 0], # top left [2, 1, 0], # middle [4, 3, 0], # top right ] square_and_triangles = Polygon(*position_list, color=PURPLE_B) self.add(isosceles, square_and_triangles) """ def __init__(self, *vertices: Point3DLike, **kwargs: Any) -> None: super().__init__(vertices, **kwargs) class RegularPolygram(Polygram): """A :class:`Polygram` with regularly spaced vertices. Parameters ---------- num_vertices The number of vertices. density The density of the :class:`RegularPolygram`. Can be thought of as how many vertices to hop to draw a line between them. Every ``density``-th vertex is connected. radius The radius of the circle that the vertices are placed on. start_angle The angle the vertices start at; the rotation of the :class:`RegularPolygram`. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: RegularPolygramExample :save_last_frame: class RegularPolygramExample(Scene): def construct(self): pentagram = RegularPolygram(5, radius=2) self.add(pentagram) """ def __init__( self, num_vertices: int, *, density: int = 2, radius: float = 1, start_angle: float | None = None, **kwargs: Any, ) -> None: # Regular polygrams can be expressed by the number of their vertices # and their density. This relation can be expressed as its Schläfli # symbol: {num_vertices/density}. # # For instance, a pentagon can be expressed as {5/1} or just {5}. # A pentagram, however, can be expressed as {5/2}. # A hexagram *would* be expressed as {6/2}, except that 6 and 2 # are not coprime, and it can be simplified to 2{3}, which corresponds # to the fact that a hexagram is actually made up of 2 triangles. # # See https://en.wikipedia.org/wiki/Polygram_(geometry)#Generalized_regular_polygons # for more information. num_gons = np.gcd(num_vertices, density) num_vertices //= num_gons density //= num_gons # Utility function for generating the individual # polygon vertices. def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: reg_vertices, start_angle = regular_vertices( num_vertices, radius=radius, start_angle=start_angle, ) vertices = [] i = 0 while True: vertices.append(reg_vertices[i]) i += density i %= num_vertices if i == 0: break return vertices, start_angle first_group, self.start_angle = gen_polygon_vertices(start_angle) vertex_groups = [first_group] for i in range(1, num_gons): start_angle = self.start_angle + (i / num_gons) * TAU / num_vertices group, _ = gen_polygon_vertices(start_angle) vertex_groups.append(group) super().__init__(*vertex_groups, **kwargs) class RegularPolygon(RegularPolygram): """An n-sided regular :class:`Polygon`. Parameters ---------- n The number of sides of the :class:`RegularPolygon`. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: RegularPolygonExample :save_last_frame: class RegularPolygonExample(Scene): def construct(self): poly_1 = RegularPolygon(n=6) poly_2 = RegularPolygon(n=6, start_angle=30*DEGREES, color=GREEN) poly_3 = RegularPolygon(n=10, color=RED) poly_group = Group(poly_1, poly_2, poly_3).scale(1.5).arrange(buff=1) self.add(poly_group) """ def __init__(self, n: int = 6, **kwargs: Any) -> None: super().__init__(n, density=1, **kwargs) class Star(Polygon): """A regular polygram without the intersecting lines. Parameters ---------- n How many points on the :class:`Star`. outer_radius The radius of the circle that the outer vertices are placed on. inner_radius The radius of the circle that the inner vertices are placed on. If unspecified, the inner radius will be calculated such that the edges of the :class:`Star` perfectly follow the edges of its :class:`RegularPolygram` counterpart. density The density of the :class:`Star`. Only used if ``inner_radius`` is unspecified. See :class:`RegularPolygram` for more information. start_angle The angle the vertices start at; the rotation of the :class:`Star`. kwargs Forwardeds to the parent constructor. Raises ------ :exc:`ValueError` If ``inner_radius`` is unspecified and ``density`` is not in the range ``[1, n/2)``. Examples -------- .. manim:: StarExample class StarExample(Scene): def construct(self): pentagram = RegularPolygram(5, radius=2) star = Star(outer_radius=2, color=RED) self.add(pentagram) self.play(Create(star), run_time=3) self.play(FadeOut(star), run_time=2) .. manim:: DifferentDensitiesExample :save_last_frame: class DifferentDensitiesExample(Scene): def construct(self): density_2 = Star(7, outer_radius=2, density=2, color=RED) density_3 = Star(7, outer_radius=2, density=3, color=PURPLE) self.add(VGroup(density_2, density_3).arrange(RIGHT)) """ def __init__( self, n: int = 5, *, outer_radius: float = 1, inner_radius: float | None = None, density: int = 2, start_angle: float | None = TAU / 4, **kwargs: Any, ) -> None: inner_angle = TAU / (2 * n) if inner_radius is None: # See https://math.stackexchange.com/a/2136292 for an # overview of how to calculate the inner radius of a # perfect star. if density <= 0 or density >= n / 2: raise ValueError( f"Incompatible density {density} for number of points {n}", ) outer_angle = TAU * density / n inverse_x = 1 - np.tan(inner_angle) * ( (np.cos(outer_angle) - 1) / np.sin(outer_angle) ) inner_radius = outer_radius / (np.cos(inner_angle) * inverse_x) outer_vertices, self.start_angle = regular_vertices( n, radius=outer_radius, start_angle=start_angle, ) inner_vertices, _ = regular_vertices( n, radius=inner_radius, start_angle=self.start_angle + inner_angle, ) vertices: list[npt.NDArray] = [] for pair in zip(outer_vertices, inner_vertices, strict=True): vertices.extend(pair) super().__init__(*vertices, **kwargs) class Triangle(RegularPolygon): """An equilateral triangle. Parameters ---------- kwargs Additional arguments to be passed to :class:`RegularPolygon` Examples -------- .. manim:: TriangleExample :save_last_frame: class TriangleExample(Scene): def construct(self): triangle_1 = Triangle() triangle_2 = Triangle().scale(2).rotate(60*DEGREES) tri_group = Group(triangle_1, triangle_2).arrange(buff=1) self.add(tri_group) """ def __init__(self, **kwargs: Any) -> None: super().__init__(n=3, **kwargs) class Rectangle(Polygon): """A quadrilateral with two sets of parallel sides. Parameters ---------- color The color of the rectangle. height The vertical height of the rectangle. width The horizontal width of the rectangle. grid_xstep Space between vertical grid lines. grid_ystep Space between horizontal grid lines. mark_paths_closed No purpose. close_new_points No purpose. kwargs Additional arguments to be passed to :class:`Polygon` Examples ---------- .. manim:: RectangleExample :save_last_frame: class RectangleExample(Scene): def construct(self): rect1 = Rectangle(width=4.0, height=2.0, grid_xstep=1.0, grid_ystep=0.5) rect2 = Rectangle(width=1.0, height=4.0) rect3 = Rectangle(width=2.0, height=2.0, grid_xstep=1.0, grid_ystep=1.0) rect3.grid_lines.set_stroke(width=1) rects = Group(rect1, rect2, rect3).arrange(buff=1) self.add(rects) """ def __init__( self, color: ParsableManimColor = WHITE, height: float = 2.0, width: float = 4.0, grid_xstep: float | None = None, grid_ystep: float | None = None, mark_paths_closed: bool = True, close_new_points: bool = True, **kwargs: Any, ): super().__init__(UR, UL, DL, DR, color=color, **kwargs) self.stretch_to_fit_width(width) self.stretch_to_fit_height(height) v = self.get_vertices() self.grid_lines = VGroup() if grid_xstep or grid_ystep: from manim.mobject.geometry.line import Line v = self.get_vertices() if grid_xstep: grid_xstep = abs(grid_xstep) count = int(width / grid_xstep) grid = VGroup( *( Line( v[1] + i * grid_xstep * RIGHT, v[1] + i * grid_xstep * RIGHT + height * DOWN, color=color, ) for i in range(1, count) ) ) self.grid_lines.add(grid) if grid_ystep: grid_ystep = abs(grid_ystep) count = int(height / grid_ystep) grid = VGroup( *( Line( v[1] + i * grid_ystep * DOWN, v[1] + i * grid_ystep * DOWN + width * RIGHT, color=color, ) for i in range(1, count) ) ) self.grid_lines.add(grid) if self.grid_lines: self.add(self.grid_lines) class Square(Rectangle): """A rectangle with equal side lengths. Parameters ---------- side_length The length of the sides of the square. kwargs Additional arguments to be passed to :class:`Rectangle`. Examples -------- .. manim:: SquareExample :save_last_frame: class SquareExample(Scene): def construct(self): square_1 = Square(side_length=2.0).shift(DOWN) square_2 = Square(side_length=1.0).next_to(square_1, direction=UP) square_3 = Square(side_length=0.5).next_to(square_2, direction=UP) self.add(square_1, square_2, square_3) """ def __init__(self, side_length: float = 2.0, **kwargs: Any) -> None: super().__init__(height=side_length, width=side_length, **kwargs) @property def side_length(self) -> float: return float(np.linalg.norm(self.get_vertices()[0] - self.get_vertices()[1])) @side_length.setter def side_length(self, value: float) -> None: self.scale(value / self.side_length) class RoundedRectangle(Rectangle): """A rectangle with rounded corners. Parameters ---------- corner_radius The curvature of the corners of the rectangle. kwargs Additional arguments to be passed to :class:`Rectangle` Examples -------- .. manim:: RoundedRectangleExample :save_last_frame: class RoundedRectangleExample(Scene): def construct(self): rect_1 = RoundedRectangle(corner_radius=0.5) rect_2 = RoundedRectangle(corner_radius=1.5, height=4.0, width=4.0) rect_group = Group(rect_1, rect_2).arrange(buff=1) self.add(rect_group) """ def __init__(self, corner_radius: float | list[float] = 0.5, **kwargs: Any): super().__init__(**kwargs) self.corner_radius = corner_radius self.round_corners(self.corner_radius) class Cutout(VMobject, metaclass=ConvertToOpenGL): """A shape with smaller cutouts. Parameters ---------- main_shape The primary shape from which cutouts are made. mobjects The smaller shapes which are to be cut out of the ``main_shape``. kwargs Further keyword arguments that are passed to the constructor of :class:`~.VMobject`. .. warning:: Technically, this class behaves similar to a symmetric difference: if parts of the ``mobjects`` are not located within the ``main_shape``, these parts will be added to the resulting :class:`~.VMobject`. Examples -------- .. manim:: CutoutExample class CutoutExample(Scene): def construct(self): s1 = Square().scale(2.5) s2 = Triangle().shift(DOWN + RIGHT).scale(0.5) s3 = Square().shift(UP + RIGHT).scale(0.5) s4 = RegularPolygon(5).shift(DOWN + LEFT).scale(0.5) s5 = RegularPolygon(6).shift(UP + LEFT).scale(0.5) c = Cutout(s1, s2, s3, s4, s5, fill_opacity=1, color=BLUE, stroke_color=RED) self.play(Write(c), run_time=4) self.wait() """ def __init__( self, main_shape: VMobject, *mobjects: VMobject, **kwargs: Any ) -> None: super().__init__(**kwargs) self.append_points(main_shape.points) sub_direction: Literal["CCW", "CW"] = ( "CCW" if main_shape.get_direction() == "CW" else "CW" ) for mobject in mobjects: self.append_points(mobject.force_direction(sub_direction).points) class ConvexHull(Polygram): """Constructs a convex hull for a set of points in no particular order. Parameters ---------- points The points to consider. tolerance The tolerance used by quickhull. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: ConvexHullExample :save_last_frame: :quality: high class ConvexHullExample(Scene): def construct(self): points = [ [-2.35, -2.25, 0], [1.65, -2.25, 0], [2.65, -0.25, 0], [1.65, 1.75, 0], [-0.35, 2.75, 0], [-2.35, 0.75, 0], [-0.35, -1.25, 0], [0.65, -0.25, 0], [-1.35, 0.25, 0], [0.15, 0.75, 0] ] hull = ConvexHull(*points, color=BLUE) dots = VGroup(*[Dot(point) for point in points]) self.add(hull) self.add(dots) """ def __init__( self, *points: Point3DLike, tolerance: float = 1e-5, **kwargs: Any ) -> None: # Build Convex Hull array = np.array(points)[:, :2] hull = QuickHull(tolerance) hull.build(array) # Extract Vertices facets = set(hull.facets) - hull.removed facet = facets.pop() subfacets = list(facet.subfacets) while len(subfacets) <= len(facets): sf = subfacets[-1] (facet,) = hull.neighbors[sf] - {facet} (sf,) = facet.subfacets - {sf} subfacets.append(sf) # Setup Vertices as Point3D coordinates = np.vstack([sf.coordinates for sf in subfacets]) vertices = np.hstack((coordinates, np.zeros((len(coordinates), 1)))) # Call Polygram super().__init__(vertices, **kwargs) ================================================ FILE: manim/mobject/geometry/shape_matchers.py ================================================ """Mobjects used to mark and annotate other mobjects.""" from __future__ import annotations __all__ = ["SurroundingRectangle", "BackgroundRectangle", "Cross", "Underline"] from typing import Any, Self from manim import logger from manim._config import config from manim.constants import ( DOWN, LEFT, RIGHT, SMALL_BUFF, UP, ) from manim.mobject.geometry.line import Line from manim.mobject.geometry.polygram import RoundedRectangle from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.types.vectorized_mobject import VGroup from manim.utils.color import BLACK, PURE_YELLOW, RED, ParsableManimColor class SurroundingRectangle(RoundedRectangle): r"""A rectangle surrounding a :class:`~.Mobject` Examples -------- .. manim:: SurroundingRectExample :save_last_frame: class SurroundingRectExample(Scene): def construct(self): title = Title("A Quote from Newton") quote = Text( "If I have seen further than others, \n" "it is by standing upon the shoulders of giants.", color=BLUE, ).scale(0.75) box = SurroundingRectangle(quote, color=YELLOW, buff=MED_LARGE_BUFF) t2 = Tex(r"Hello World").scale(1.5) box2 = SurroundingRectangle(t2, corner_radius=0.2) mobjects = VGroup(VGroup(box, quote), VGroup(t2, box2)).arrange(DOWN) self.add(title, mobjects) """ def __init__( self, *mobjects: Mobject, color: ParsableManimColor = PURE_YELLOW, buff: float | tuple[float, float] = SMALL_BUFF, corner_radius: float = 0.0, **kwargs: Any, ) -> None: from manim.mobject.mobject import Group if not all(isinstance(mob, (Mobject, OpenGLMobject)) for mob in mobjects): raise TypeError( "Expected all inputs for parameter mobjects to be a Mobjects" ) if isinstance(buff, tuple): buff_x = buff[0] buff_y = buff[1] else: buff_x = buff_y = buff group = Group(*mobjects) super().__init__( color=color, width=group.width + 2 * buff_x, height=group.height + 2 * buff_y, corner_radius=corner_radius, **kwargs, ) self.buff = buff self.move_to(group) class BackgroundRectangle(SurroundingRectangle): """A background rectangle. Its default color is the background color of the scene. Examples -------- .. manim:: ExampleBackgroundRectangle :save_last_frame: class ExampleBackgroundRectangle(Scene): def construct(self): circle = Circle().shift(LEFT) circle.set_stroke(color=GREEN, width=20) triangle = Triangle().shift(2 * RIGHT) triangle.set_fill(PINK, opacity=0.5) backgroundRectangle1 = BackgroundRectangle(circle, color=WHITE, fill_opacity=0.15) backgroundRectangle2 = BackgroundRectangle(triangle, color=WHITE, fill_opacity=0.15) self.add(backgroundRectangle1) self.add(backgroundRectangle2) self.add(circle) self.add(triangle) self.play(Rotate(backgroundRectangle1, PI / 4)) self.play(Rotate(backgroundRectangle2, PI / 2)) """ def __init__( self, *mobjects: Mobject, color: ParsableManimColor | None = None, stroke_width: float = 0, stroke_opacity: float = 0, fill_opacity: float = 0.75, buff: float | tuple[float, float] = 0, **kwargs: Any, ) -> None: if color is None: color = config.background_color super().__init__( *mobjects, color=color, stroke_width=stroke_width, stroke_opacity=stroke_opacity, fill_opacity=fill_opacity, buff=buff, **kwargs, ) self.original_fill_opacity: float = self.fill_opacity def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self: self.set_fill(opacity=b * self.original_fill_opacity) return self def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # type: ignore[override] # Unchangeable style, except for fill_opacity # All other style arguments are ignored super().set_style( stroke_color=BLACK, stroke_width=0, fill_color=BLACK, fill_opacity=fill_opacity, ) if len(kwargs) > 0: logger.info( "Argument %s is ignored in BackgroundRectangle.set_style.", kwargs, ) return self class Cross(VGroup): """Creates a cross. Parameters ---------- mobject The mobject linked to this instance. It fits the mobject when specified. Defaults to None. stroke_color Specifies the color of the cross lines. Defaults to RED. stroke_width Specifies the width of the cross lines. Defaults to 6. scale_factor Scales the cross to the provided units. Defaults to 1. Examples -------- .. manim:: ExampleCross :save_last_frame: class ExampleCross(Scene): def construct(self): cross = Cross() self.add(cross) """ def __init__( self, mobject: Mobject | None = None, stroke_color: ParsableManimColor = RED, stroke_width: float = 6.0, scale_factor: float = 1.0, **kwargs: Any, ) -> None: super().__init__( Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT), **kwargs ) if mobject is not None: self.replace(mobject, stretch=True) self.scale(scale_factor) self.set_stroke(color=stroke_color, width=stroke_width) class Underline(Line): """Creates an underline. Examples -------- .. manim:: UnderLine :save_last_frame: class UnderLine(Scene): def construct(self): man = Tex("Manim") # Full Word ul = Underline(man) # Underlining the word self.add(man, ul) """ def __init__( self, mobject: Mobject, buff: float = SMALL_BUFF, **kwargs: Any ) -> None: super().__init__(LEFT, RIGHT, buff=buff, **kwargs) self.match_width(mobject) self.next_to(mobject, DOWN, buff=self.buff) ================================================ FILE: manim/mobject/geometry/tips.py ================================================ r"""A collection of tip mobjects for use with :class:`~.TipableVMobject`.""" from __future__ import annotations __all__ = [ "ArrowTip", "ArrowCircleFilledTip", "ArrowCircleTip", "ArrowSquareTip", "ArrowSquareFilledTip", "ArrowTriangleTip", "ArrowTriangleFilledTip", "StealthTip", ] from typing import TYPE_CHECKING, Any import numpy as np from manim.constants import * from manim.mobject.geometry.arc import Circle from manim.mobject.geometry.polygram import Square, Triangle from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VMobject from manim.utils.space_ops import angle_of_vector if TYPE_CHECKING: from manim.typing import Point3D, Vector3D class ArrowTip(VMobject, metaclass=ConvertToOpenGL): r"""Base class for arrow tips. .. seealso:: :class:`ArrowTriangleTip` :class:`ArrowTriangleFilledTip` :class:`ArrowCircleTip` :class:`ArrowCircleFilledTip` :class:`ArrowSquareTip` :class:`ArrowSquareFilledTip` :class:`StealthTip` Examples -------- Cannot be used directly, only intended for inheritance:: >>> tip = ArrowTip() Traceback (most recent call last): ... NotImplementedError: Has to be implemented in inheriting subclasses. Instead, use one of the pre-defined ones, or make a custom one like this: .. manim:: CustomTipExample >>> from manim import RegularPolygon, Arrow >>> class MyCustomArrowTip(ArrowTip, RegularPolygon): ... def __init__(self, length=0.35, **kwargs): ... RegularPolygon.__init__(self, n=5, **kwargs) ... self.width = length ... self.stretch_to_fit_height(length) >>> arr = Arrow( ... np.array([-2, -2, 0]), np.array([2, 2, 0]), tip_shape=MyCustomArrowTip ... ) >>> isinstance(arr.tip, RegularPolygon) True >>> from manim import Scene, Create >>> class CustomTipExample(Scene): ... def construct(self): ... self.play(Create(arr)) Using a class inherited from :class:`ArrowTip` to get a non-filled tip is a shorthand to manually specifying the arrow tip style as follows:: >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 1, 0]), ... tip_style={'fill_opacity': 0, 'stroke_width': 3}) The following example illustrates the usage of all of the predefined arrow tips. .. manim:: ArrowTipsShowcase :save_last_frame: class ArrowTipsShowcase(Scene): def construct(self): tip_names = [ 'Default (YELLOW)', 'ArrowTriangleTip', 'Default', 'ArrowSquareTip', 'ArrowSquareFilledTip', 'ArrowCircleTip', 'ArrowCircleFilledTip', 'StealthTip' ] big_arrows = [ Arrow(start=[-4, 3.5, 0], end=[2, 3.5, 0], color=YELLOW), Arrow(start=[-4, 2.5, 0], end=[2, 2.5, 0], tip_shape=ArrowTriangleTip), Arrow(start=[-4, 1.5, 0], end=[2, 1.5, 0]), Arrow(start=[-4, 0.5, 0], end=[2, 0.5, 0], tip_shape=ArrowSquareTip), Arrow([-4, -0.5, 0], [2, -0.5, 0], tip_shape=ArrowSquareFilledTip), Arrow([-4, -1.5, 0], [2, -1.5, 0], tip_shape=ArrowCircleTip), Arrow([-4, -2.5, 0], [2, -2.5, 0], tip_shape=ArrowCircleFilledTip), Arrow([-4, -3.5, 0], [2, -3.5, 0], tip_shape=StealthTip) ] small_arrows = ( arrow.copy().scale(0.5, scale_tips=True).next_to(arrow, RIGHT) for arrow in big_arrows ) labels = ( Text(tip_names[i], font='monospace', font_size=20, color=BLUE).next_to(big_arrows[i], LEFT) for i in range(len(big_arrows)) ) self.add(*big_arrows, *small_arrows, *labels) """ def __init__(self, *args: Any, **kwargs: Any) -> None: raise NotImplementedError("Has to be implemented in inheriting subclasses.") @property def base(self) -> Point3D: r"""The base point of the arrow tip. This is the point connecting to the arrow line. Examples -------- :: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 0, 0]), buff=0) >>> arrow.tip.base.round(2) + 0. # add 0. to avoid negative 0 in output array([1.65, 0. , 0. ]) """ return self.point_from_proportion(0.5) @property def tip_point(self) -> Point3D: r"""The tip point of the arrow tip. Examples -------- :: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 0, 0]), buff=0) >>> arrow.tip.tip_point.round(2) + 0. array([2., 0., 0.]) """ # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 tip_point: Point3D = self.points[0] return tip_point @property def vector(self) -> Vector3D: r"""The vector pointing from the base point to the tip point. Examples -------- :: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 2, 0]), buff=0) >>> arrow.tip.vector.round(2) + 0. array([0.25, 0.25, 0. ]) """ return self.tip_point - self.base @property def tip_angle(self) -> float: r"""The angle of the arrow tip. Examples -------- :: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 1, 0]), buff=0) >>> bool(round(arrow.tip.tip_angle, 5) == round(PI/4, 5)) True """ return angle_of_vector(self.vector) @property def length(self) -> float: r"""The length of the arrow tip. Examples -------- :: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 2, 0])) >>> round(arrow.tip.length, 3) 0.35 """ return float(np.linalg.norm(self.vector)) class StealthTip(ArrowTip): r"""'Stealth' fighter / kite arrow shape. Naming is inspired by the corresponding `TikZ arrow shape `__. """ def __init__( self, fill_opacity: float = 1, stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH / 2, start_angle: float = PI, **kwargs: Any, ): self.start_angle = start_angle VMobject.__init__( self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs ) self.set_points_as_corners( np.array( [ [2, 0, 0], # tip [-1.2, 1.6, 0], [0, 0, 0], # base [-1.2, -1.6, 0], [2, 0, 0], # close path, back to tip ] ) ) self.scale(length / self.length) @property def length(self) -> float: """The length of the arrow tip. In this case, the length is computed as the height of the triangle encompassing the stealth tip (otherwise, the tip is scaled too large). """ return float(np.linalg.norm(self.vector) * 1.6) class ArrowTriangleTip(ArrowTip, Triangle): r"""Triangular arrow tip.""" def __init__( self, fill_opacity: float = 0, stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH, width: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, **kwargs: Any, ) -> None: Triangle.__init__( self, fill_opacity=fill_opacity, stroke_width=stroke_width, start_angle=start_angle, **kwargs, ) self.width = width self.stretch_to_fit_width(length) self.stretch_to_fit_height(width) class ArrowTriangleFilledTip(ArrowTriangleTip): r"""Triangular arrow tip with filled tip. This is the default arrow tip shape. """ def __init__( self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) class ArrowCircleTip(ArrowTip, Circle): r"""Circular arrow tip.""" def __init__( self, fill_opacity: float = 0, stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, **kwargs: Any, ) -> None: self.start_angle = start_angle Circle.__init__( self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs ) self.width = length self.stretch_to_fit_height(length) class ArrowCircleFilledTip(ArrowCircleTip): r"""Circular arrow tip with filled tip.""" def __init__( self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) class ArrowSquareTip(ArrowTip, Square): r"""Square arrow tip.""" def __init__( self, fill_opacity: float = 0, stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, **kwargs: Any, ) -> None: self.start_angle = start_angle Square.__init__( self, fill_opacity=fill_opacity, stroke_width=stroke_width, side_length=length, **kwargs, ) self.width = length self.stretch_to_fit_height(length) class ArrowSquareFilledTip(ArrowSquareTip): r"""Square arrow tip with filled tip.""" def __init__( self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) ================================================ FILE: manim/mobject/graph.py ================================================ """Mobjects used to represent mathematical graphs (think graph theory, not plotting).""" from __future__ import annotations __all__ = [ "Graph", "DiGraph", ] import itertools as it from collections.abc import Hashable, Iterable, Sequence from copy import copy from typing import TYPE_CHECKING, Any, Literal, Protocol, cast import networkx as nx import numpy as np if TYPE_CHECKING: from typing import TypeAlias from manim.scene.scene import Scene from manim.typing import Point3D, Point3DLike NxGraph: TypeAlias = nx.classes.graph.Graph | nx.classes.digraph.DiGraph from manim.animation.composition import AnimationGroup from manim.animation.creation import Create, Uncreate from manim.mobject.geometry.arc import Dot, LabeledDot from manim.mobject.geometry.line import Line from manim.mobject.mobject import Mobject, override_animate from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.text.tex_mobject import MathTex from manim.mobject.types.vectorized_mobject import VMobject from manim.utils.color import BLACK class LayoutFunction(Protocol): """A protocol for automatic layout functions that compute a layout for a graph to be used in :meth:`~.Graph.change_layout`. .. note:: The layout function must be a pure function, i.e., it must not modify the graph passed to it. Examples -------- Here is an example that arranges nodes in an n x m grid in sorted order. .. manim:: CustomLayoutExample :save_last_frame: class CustomLayoutExample(Scene): def construct(self): import numpy as np import networkx as nx # create custom layout def custom_layout( graph: nx.Graph, scale: float | tuple[float, float, float] = 2, n: int | None = None, *args: Any, **kwargs: Any, ): nodes = sorted(list(graph)) height = len(nodes) // n return { node: (scale * np.array([ (i % n) - (n-1)/2, -(i // n) + height/2, 0 ])) for i, node in enumerate(graph) } # draw graph n = 4 graph = Graph( [i for i in range(4 * 2 - 1)], [(0, 1), (0, 4), (1, 2), (1, 5), (2, 3), (2, 6), (4, 5), (5, 6)], labels=True, layout=custom_layout, layout_config={'n': n} ) self.add(graph) Several automatic layouts are provided by manim, and can be used by passing their name as the ``layout`` parameter to :meth:`~.Graph.change_layout`. Alternatively, a custom layout function can be passed to :meth:`~.Graph.change_layout` as the ``layout`` parameter. Such a function must adhere to the :class:`~.LayoutFunction` protocol. The :class:`~.LayoutFunction` s provided by manim are illustrated below: - Circular Layout: places the vertices on a circle .. manim:: CircularLayout :save_last_frame: class CircularLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="circular", labels=True ) self.add(graph) - Kamada Kawai Layout: tries to place the vertices such that the given distances between them are respected .. manim:: KamadaKawaiLayout :save_last_frame: class KamadaKawaiLayout(Scene): def construct(self): from collections import defaultdict distances: dict[int, dict[int, float]] = defaultdict(dict) # set desired distances distances[1][2] = 1 # distance between vertices 1 and 2 is 1 distances[2][3] = 1 # distance between vertices 2 and 3 is 1 distances[3][4] = 2 # etc distances[4][5] = 3 distances[5][6] = 5 distances[6][1] = 8 graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1)], layout="kamada_kawai", layout_config={"dist": distances}, layout_scale=4, labels=True ) self.add(graph) - Partite Layout: places vertices into distinct partitions .. manim:: PartiteLayout :save_last_frame: class PartiteLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="partite", layout_config={"partitions": [[1,2],[3,4],[5,6]]}, labels=True ) self.add(graph) - Planar Layout: places vertices such that edges do not cross .. manim:: PlanarLayout :save_last_frame: class PlanarLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="planar", layout_scale=4, labels=True ) self.add(graph) - Random Layout: randomly places vertices .. manim:: RandomLayout :save_last_frame: class RandomLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="random", labels=True ) self.add(graph) - Shell Layout: places vertices in concentric circles .. manim:: ShellLayout :save_last_frame: class ShellLayout(Scene): def construct(self): nlist = [[1, 2, 3], [4, 5, 6, 7, 8, 9]] graph = Graph( [1, 2, 3, 4, 5, 6, 7, 8, 9], [(1, 2), (2, 3), (3, 1), (4, 1), (4, 2), (5, 2), (6, 2), (6, 3), (7, 3), (8, 3), (8, 1), (9, 1)], layout="shell", layout_config={"nlist": nlist}, labels=True ) self.add(graph) - Spectral Layout: places vertices using the eigenvectors of the graph Laplacian (clusters nodes which are an approximation of the ratio cut) .. manim:: SpectralLayout :save_last_frame: class SpectralLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="spectral", labels=True ) self.add(graph) - Sprial Layout: places vertices in a spiraling pattern .. manim:: SpiralLayout :save_last_frame: class SpiralLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="spiral", labels=True ) self.add(graph) - Spring Layout: places nodes according to the Fruchterman-Reingold force-directed algorithm (attempts to minimize edge length while maximizing node separation) .. manim:: SpringLayout :save_last_frame: class SpringLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6], [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)], layout="spring", labels=True ) self.add(graph) - Tree Layout: places vertices into a tree with a root node and branches (can only be used with legal trees) .. manim:: TreeLayout :save_last_frame: class TreeLayout(Scene): def construct(self): graph = Graph( [1, 2, 3, 4, 5, 6, 7], [(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)], layout="tree", layout_config={"root_vertex": 1}, labels=True ) self.add(graph) """ def __call__( self, graph: NxGraph, scale: float | tuple[float, float, float] = 2, *args: Any, **kwargs: Any, ) -> dict[Hashable, Point3D]: """Given a graph and a scale, return a dictionary of coordinates. Parameters ---------- graph The underlying NetworkX graph to be laid out. DO NOT MODIFY. scale Either a single float value, or a tuple of three float values specifying the scale along each axis. Returns ------- dict[Hashable, Point3D] A dictionary mapping vertices to their positions. """ ... def _partite_layout( nx_graph: NxGraph, scale: float = 2, partitions: Sequence[Sequence[Hashable]] | None = None, **kwargs: Any, ) -> dict[Hashable, Point3D]: if partitions is None or len(partitions) == 0: raise ValueError( "The partite layout requires partitions parameter to contain the partition of the vertices", ) partition_count = len(partitions) for i in range(partition_count): for v in partitions[i]: if nx_graph.nodes[v] is None: raise ValueError( "The partition must contain arrays of vertices in the graph", ) nx_graph.nodes[v]["subset"] = i # Add missing vertices to their own side for v in nx_graph.nodes: if "subset" not in nx_graph.nodes[v]: nx_graph.nodes[v]["subset"] = partition_count return nx.layout.multipartite_layout(nx_graph, scale=scale, **kwargs) def _random_layout(nx_graph: NxGraph, scale: float = 2, **kwargs: Any): # the random layout places coordinates in [0, 1) # we need to rescale manually afterwards... auto_layout = nx.layout.random_layout(nx_graph, **kwargs) for k, v in auto_layout.items(): auto_layout[k] = 2 * scale * (v - np.array([0.5, 0.5])) return {k: np.append(v, [0]) for k, v in auto_layout.items()} def _tree_layout( T: NxGraph, root_vertex: Hashable | None = None, scale: float | tuple | None = 2, vertex_spacing: tuple | None = None, orientation: str = "down", ): if root_vertex is None: raise ValueError("The tree layout requires the root_vertex parameter") if not nx.is_tree(T): raise ValueError("The tree layout must be used with trees") children = {root_vertex: list(T.neighbors(root_vertex))} # The following code is SageMath's tree layout implementation, taken from # https://github.com/sagemath/sage/blob/cc60cfebc4576fed8b01f0fc487271bdee3cefed/src/sage/graphs/graph_plot.py#L1447 # Always make a copy of the children because they get eaten stack = [list(children[root_vertex]).copy()] stick = [root_vertex] parent = dict.fromkeys(children[root_vertex], root_vertex) pos = {} obstruction = [0.0] * len(T) o = -1 if orientation == "down" else 1 def slide(v, dx): """ Shift the vertex v and its descendants to the right by dx. Precondition: v and its descendents have already had their positions computed. """ level = [v] while level: nextlevel = [] for u in level: x, y = pos[u] x += dx obstruction[y] = max(x + 1, obstruction[y]) pos[u] = x, y nextlevel += children[u] level = nextlevel while stack: C = stack[-1] if not C: p = stick.pop() stack.pop() cp = children[p] y = o * len(stack) if not cp: x = obstruction[y] pos[p] = x, y else: x = sum(pos[c][0] for c in cp) / float(len(cp)) pos[p] = x, y ox = obstruction[y] if x < ox: slide(p, ox - x) x = ox obstruction[y] = x + 1 continue t = C.pop() pt = parent[t] ct = [u for u in list(T.neighbors(t)) if u != pt] for c in ct: parent[c] = t children[t] = copy(ct) stack.append(ct) stick.append(t) # the resulting layout is then rescaled again to fit on Manim's canvas x_min = min(pos.values(), key=lambda t: t[0])[0] x_max = max(pos.values(), key=lambda t: t[0])[0] y_min = min(pos.values(), key=lambda t: t[1])[1] y_max = max(pos.values(), key=lambda t: t[1])[1] center = np.array([x_min + x_max, y_min + y_max, 0]) / 2 height = y_max - y_min width = x_max - x_min if vertex_spacing is None: if isinstance(scale, (float, int)) and (width > 0 or height > 0): sf = 2 * scale / max(width, height) elif isinstance(scale, tuple): sw = 2 * scale[0] / width if scale[0] is not None and width > 0 else 1 sh = 2 * scale[1] / height if scale[1] is not None and height > 0 else 1 sf = np.array([sw, sh, 0]) else: sf = 1 else: sx, sy = vertex_spacing sf = np.array([sx, sy, 0]) return {v: (np.array([x, y, 0]) - center) * sf for v, (x, y) in pos.items()} LayoutName = Literal[ "circular", "kamada_kawai", "partite", "planar", "random", "shell", "spectral", "spiral", "spring", "tree", ] _layouts: dict[LayoutName, LayoutFunction] = { "circular": cast(LayoutFunction, nx.layout.circular_layout), "kamada_kawai": cast(LayoutFunction, nx.layout.kamada_kawai_layout), "partite": cast(LayoutFunction, _partite_layout), "planar": cast(LayoutFunction, nx.layout.planar_layout), "random": cast(LayoutFunction, _random_layout), "shell": cast(LayoutFunction, nx.layout.shell_layout), "spectral": cast(LayoutFunction, nx.layout.spectral_layout), "spiral": cast(LayoutFunction, nx.layout.spiral_layout), "spring": cast(LayoutFunction, nx.layout.spring_layout), "tree": cast(LayoutFunction, _tree_layout), } def _determine_graph_layout( nx_graph: nx.classes.graph.Graph | nx.classes.digraph.DiGraph, layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = "spring", layout_scale: float | tuple[float, float, float] = 2, layout_config: dict[str, Any] | None = None, ) -> dict[Hashable, Point3DLike]: if layout_config is None: layout_config = {} if isinstance(layout, dict): return layout elif layout in _layouts: auto_layout = _layouts[layout](nx_graph, scale=layout_scale, **layout_config) # NetworkX returns a dictionary of 3D points if the dimension # is specified to be 3. Otherwise, it returns a dictionary of # 2D points, so adjusting is required. if ( layout_config.get("dim") == 3 or auto_layout[next(auto_layout.__iter__())].shape[0] == 3 ): return auto_layout else: return {k: np.append(v, [0]) for k, v in auto_layout.items()} else: try: return cast(LayoutFunction, layout)( nx_graph, scale=layout_scale, **layout_config ) except TypeError as e: raise ValueError( f"The layout '{layout}' is neither a recognized layout, a layout function," "nor a vertex placement dictionary.", ) from e class GenericGraph(VMobject, metaclass=ConvertToOpenGL): """Abstract base class for graphs (that is, a collection of vertices connected with edges). Graphs can be instantiated by passing both a list of (distinct, hashable) vertex names, together with list of edges (as tuples of vertex names). See the examples for concrete implementations of this class for details. .. note:: This implementation uses updaters to make the edges move with the vertices. See also -------- :class:`.Graph` :class:`.DiGraph` Parameters ---------- vertices A list of vertices. Must be hashable elements. edges A list of edges, specified as tuples ``(u, v)`` where both ``u`` and ``v`` are vertices. labels Controls whether or not vertices are labeled. If ``False`` (the default), the vertices are not labeled; if ``True`` they are labeled using their names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively, custom labels can be specified by passing a dictionary whose keys are the vertices, and whose values are the corresponding vertex labels (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`). label_fill_color Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``. layout Either one of ``"spring"`` (the default), ``"circular"``, ``"kamada_kawai"``, ``"planar"``, ``"random"``, ``"shell"``, ``"spectral"``, ``"spiral"``, ``"tree"``, and ``"partite"`` for automatic vertex positioning primarily using ``networkx`` (see `their documentation `_ for more details), a dictionary specifying a coordinate (value) for each vertex (key) for manual positioning, or a .:class:`~.LayoutFunction` with a user-defined automatic layout. layout_config Only for automatic layouts. A dictionary whose entries are passed as keyword arguments to the named layout or automatic layout function specified via ``layout``. The ``tree`` layout also accepts a special parameter ``vertex_spacing`` passed as a keyword argument inside the ``layout_config`` dictionary. Passing a tuple ``(space_x, space_y)`` as this argument overrides the value of ``layout_scale`` and ensures that vertices are arranged in a way such that the centers of siblings in the same layer are at least ``space_x`` units apart horizontally, and neighboring layers are spaced ``space_y`` units vertically. layout_scale The scale of automatically generated layouts: the vertices will be arranged such that the coordinates are located within the interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)`` causing the first coordinate to be in the interval ``[-scale_x, scale_x]``, and the second in ``[-scale_y, scale_y]``. Default: 2. vertex_type The mobject class used for displaying vertices in the scene. vertex_config Either a dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``, or a dictionary whose keys are the vertices, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding vertex. vertex_mobjects A dictionary whose keys are the vertices, and whose values are mobjects to be used as vertices. Passing vertices here overrides all other configuration options for a vertex. edge_type The mobject class used for displaying edges in the scene. Must be a subclass of :class:`~.Line` for default updaters to work. edge_config Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edges, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding edge. """ def __init__( self, vertices: Sequence[Hashable], edges: Sequence[tuple[Hashable, Hashable]], labels: bool | dict = False, label_fill_color: str = BLACK, layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = "spring", layout_scale: float | tuple[float, float, float] = 2, layout_config: dict | None = None, vertex_type: type[Mobject] = Dot, vertex_config: dict | None = None, vertex_mobjects: dict | None = None, edge_type: type[Mobject] = Line, partitions: Sequence[Sequence[Hashable]] | None = None, root_vertex: Hashable | None = None, edge_config: dict | None = None, ) -> None: super().__init__() nx_graph = self._empty_networkx_graph() nx_graph.add_nodes_from(vertices) nx_graph.add_edges_from(edges) self._graph = nx_graph if isinstance(labels, dict): self._labels = labels elif isinstance(labels, bool): if labels: self._labels = {v: MathTex(v, color=label_fill_color) for v in vertices} else: self._labels = {} if self._labels and vertex_type is Dot: vertex_type = LabeledDot if vertex_mobjects is None: vertex_mobjects = {} # build vertex_config if vertex_config is None: vertex_config = {} default_vertex_config = {} if vertex_config: default_vertex_config = { k: v for k, v in vertex_config.items() if k not in vertices } self._vertex_config = { v: vertex_config.get(v, copy(default_vertex_config)) for v in vertices } self.default_vertex_config = default_vertex_config for v, label in self._labels.items(): self._vertex_config[v]["label"] = label self.vertices = {v: vertex_type(**self._vertex_config[v]) for v in vertices} self.vertices.update(vertex_mobjects) self.change_layout( layout=layout, layout_scale=layout_scale, layout_config=layout_config, partitions=partitions, root_vertex=root_vertex, ) # build edge_config if edge_config is None: edge_config = {} default_tip_config = {} default_edge_config = {} if edge_config: default_tip_config = edge_config.pop("tip_config", {}) default_edge_config = { k: v for k, v in edge_config.items() if not isinstance( k, tuple ) # everything that is not an edge is an option } self._edge_config = {} self._tip_config = {} for e in edges: if e in edge_config: self._tip_config[e] = edge_config[e].pop( "tip_config", copy(default_tip_config) ) self._edge_config[e] = edge_config[e] else: self._tip_config[e] = copy(default_tip_config) self._edge_config[e] = copy(default_edge_config) self.default_edge_config = default_edge_config self._populate_edge_dict(edges, edge_type) self.add(*self.vertices.values()) self.add(*self.edges.values()) self.add_updater(self.update_edges) @staticmethod def _empty_networkx_graph() -> nx.classes.graph.Graph: """Return an empty networkx graph for the given graph type.""" raise NotImplementedError("To be implemented in concrete subclasses") def _populate_edge_dict( self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject] ): """Helper method for populating the edges of the graph.""" raise NotImplementedError("To be implemented in concrete subclasses") def __getitem__(self: Graph, v: Hashable) -> Mobject: return self.vertices[v] def _create_vertex( self, vertex: Hashable, position: Point3DLike | None = None, label: bool = False, label_fill_color: str = BLACK, vertex_type: type[Mobject] = Dot, vertex_config: dict | None = None, vertex_mobject: dict | None = None, ) -> tuple[Hashable, Point3D, dict, Mobject]: np_position: Point3D = ( self.get_center() if position is None else np.asarray(position) ) if vertex_config is None: vertex_config = {} if vertex in self.vertices: raise ValueError( f"Vertex identifier '{vertex}' is already used for a vertex in this graph.", ) if label is True: label = MathTex(vertex, color=label_fill_color) elif vertex in self._labels: label = self._labels[vertex] elif not isinstance(label, (Mobject, OpenGLMobject)): label = None base_vertex_config = copy(self.default_vertex_config) base_vertex_config.update(vertex_config) vertex_config = base_vertex_config if label is not None: vertex_config["label"] = label if vertex_type is Dot: vertex_type = LabeledDot if vertex_mobject is None: vertex_mobject = vertex_type(**vertex_config) vertex_mobject.move_to(np_position) return (vertex, np_position, vertex_config, vertex_mobject) def _add_created_vertex( self, vertex: Hashable, position: Point3DLike, vertex_config: dict, vertex_mobject: Mobject, ) -> Mobject: if vertex in self.vertices: raise ValueError( f"Vertex identifier '{vertex}' is already used for a vertex in this graph.", ) self._graph.add_node(vertex) self._layout[vertex] = position if "label" in vertex_config: self._labels[vertex] = vertex_config["label"] self._vertex_config[vertex] = vertex_config self.vertices[vertex] = vertex_mobject self.vertices[vertex].move_to(position) self.add(self.vertices[vertex]) return self.vertices[vertex] def _add_vertex( self, vertex: Hashable, position: Point3DLike | None = None, label: bool = False, label_fill_color: str = BLACK, vertex_type: type[Mobject] = Dot, vertex_config: dict | None = None, vertex_mobject: dict | None = None, ) -> Mobject: """Add a vertex to the graph. Parameters ---------- vertex A hashable vertex identifier. position The coordinates where the new vertex should be added. If ``None``, the center of the graph is used. label Controls whether or not the vertex is labeled. If ``False`` (the default), the vertex is not labeled; if ``True`` it is labeled using its names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively, any :class:`~.Mobject` can be passed to be used as the label. label_fill_color Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``label``. vertex_type The mobject class used for displaying vertices in the scene. vertex_config A dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``. vertex_mobject The mobject to be used as the vertex. Overrides all other vertex customization options. """ return self._add_created_vertex( *self._create_vertex( vertex=vertex, position=position, label=label, label_fill_color=label_fill_color, vertex_type=vertex_type, vertex_config=vertex_config, vertex_mobject=vertex_mobject, ) ) def _create_vertices( self: Graph, *vertices: Hashable, positions: dict | None = None, labels: bool = False, label_fill_color: str = BLACK, vertex_type: type[Mobject] = Dot, vertex_config: dict | None = None, vertex_mobjects: dict | None = None, ) -> Iterable[tuple[Hashable, Point3D, dict, Mobject]]: if positions is None: positions = {} if vertex_mobjects is None: vertex_mobjects = {} graph_center = self.get_center() base_positions = dict.fromkeys(vertices, graph_center) base_positions.update(positions) positions = base_positions if isinstance(labels, bool): labels = dict.fromkeys(vertices, labels) else: assert isinstance(labels, dict) base_labels = dict.fromkeys(vertices, False) base_labels.update(labels) labels = base_labels if vertex_config is None: vertex_config = copy(self.default_vertex_config) assert isinstance(vertex_config, dict) base_vertex_config = copy(self.default_vertex_config) base_vertex_config.update( {key: val for key, val in vertex_config.items() if key not in vertices}, ) vertex_config = { v: (vertex_config[v] if v in vertex_config else copy(base_vertex_config)) for v in vertices } return [ self._create_vertex( v, position=positions[v], label=labels[v], label_fill_color=label_fill_color, vertex_type=vertex_type, vertex_config=vertex_config[v], vertex_mobject=vertex_mobjects.get(v), ) for v in vertices ] def add_vertices( self: Graph, *vertices: Hashable, positions: dict | None = None, labels: bool = False, label_fill_color: str = BLACK, vertex_type: type[Mobject] = Dot, vertex_config: dict | None = None, vertex_mobjects: dict | None = None, ): """Add a list of vertices to the graph. Parameters ---------- vertices Hashable vertex identifiers. positions A dictionary specifying the coordinates where the new vertices should be added. If ``None``, all vertices are created at the center of the graph. labels Controls whether or not the vertex is labeled. If ``False`` (the default), the vertex is not labeled; if ``True`` it is labeled using its names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively, any :class:`~.Mobject` can be passed to be used as the label. label_fill_color Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``. vertex_type The mobject class used for displaying vertices in the scene. vertex_config A dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``. vertex_mobjects A dictionary whose keys are the vertex identifiers, and whose values are mobjects that should be used as vertices. Overrides all other vertex customization options. """ return [ self._add_created_vertex(*v) for v in self._create_vertices( *vertices, positions=positions, labels=labels, label_fill_color=label_fill_color, vertex_type=vertex_type, vertex_config=vertex_config, vertex_mobjects=vertex_mobjects, ) ] @override_animate(add_vertices) def _add_vertices_animation(self, *args, anim_args=None, **kwargs): if anim_args is None: anim_args = {} animation = anim_args.pop("animation", Create) vertex_mobjects = self._create_vertices(*args, **kwargs) def on_finish(scene: Scene): for v in vertex_mobjects: scene.remove(v[-1]) self._add_created_vertex(*v) return AnimationGroup( *(animation(v[-1], **anim_args) for v in vertex_mobjects), group=self, _on_finish=on_finish, ) def _remove_vertex(self, vertex): """Remove a vertex (as well as all incident edges) from the graph. Parameters ---------- vertex The identifier of a vertex to be removed. Returns ------- Group A mobject containing all removed objects. """ if vertex not in self.vertices: raise ValueError( f"The graph does not contain a vertex with identifier '{vertex}'", ) self._graph.remove_node(vertex) self._layout.pop(vertex) if vertex in self._labels: self._labels.pop(vertex) self._vertex_config.pop(vertex) edge_tuples = [e for e in self.edges if vertex in e] for e in edge_tuples: self._edge_config.pop(e) to_remove = [self.edges.pop(e) for e in edge_tuples] to_remove.append(self.vertices.pop(vertex)) self.remove(*to_remove) return self.get_group_class()(*to_remove) def remove_vertices(self, *vertices): """Remove several vertices from the graph. Parameters ---------- vertices Vertices to be removed from the graph. Examples -------- :: >>> G = Graph([1, 2, 3], [(1, 2), (2, 3)]) >>> removed = G.remove_vertices(2, 3); removed VGroup(Line, Line, Dot, Dot) >>> G Undirected graph on 1 vertices and 0 edges """ mobjects = [] for v in vertices: mobjects.extend(self._remove_vertex(v).submobjects) return self.get_group_class()(*mobjects) @override_animate(remove_vertices) def _remove_vertices_animation(self, *vertices, anim_args=None): if anim_args is None: anim_args = {} animation = anim_args.pop("animation", Uncreate) mobjects = self.remove_vertices(*vertices) return AnimationGroup( *(animation(mobj, **anim_args) for mobj in mobjects), group=self ) def _add_edge( self, edge: tuple[Hashable, Hashable], edge_type: type[Mobject] = Line, edge_config: dict | None = None, ): """Add a new edge to the graph. Parameters ---------- edge The edge (as a tuple of vertex identifiers) to be added. If a non-existing vertex is passed, a new vertex with default settings will be created. Create new vertices yourself beforehand to customize them. edge_type The mobject class used for displaying edges in the scene. edge_config A dictionary containing keyword arguments to be passed to the class specified via ``edge_type``. Returns ------- Group A group containing all newly added vertices and edges. """ if edge_config is None: edge_config = self.default_edge_config.copy() added_mobjects = [self._add_vertex(v) for v in edge if v not in self.vertices] u, v = edge self._graph.add_edge(u, v) base_edge_config = self.default_edge_config.copy() base_edge_config.update(edge_config) edge_config = base_edge_config self._edge_config[(u, v)] = edge_config edge_mobject = edge_type( start=self[u].get_center(), end=self[v].get_center(), z_index=-1, **edge_config, ) self.edges[(u, v)] = edge_mobject self.add(edge_mobject) added_mobjects.append(edge_mobject) return self.get_group_class()(*added_mobjects) def add_edges( self, *edges: tuple[Hashable, Hashable], edge_type: type[Mobject] = Line, edge_config: dict | None = None, **kwargs, ): """Add new edges to the graph. Parameters ---------- edges Edges (as tuples of vertex identifiers) to be added. If a non-existing vertex is passed, a new vertex with default settings will be created. Create new vertices yourself beforehand to customize them. edge_type The mobject class used for displaying edges in the scene. edge_config A dictionary either containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edge tuples, and whose values are dictionaries containing keyword arguments to be passed for the construction of the corresponding edge. kwargs Any further keyword arguments are passed to :meth:`.add_vertices` which is used to create new vertices in the passed edges. Returns ------- Group A group containing all newly added vertices and edges. """ if edge_config is None: edge_config = {} non_edge_settings = {k: v for (k, v) in edge_config.items() if k not in edges} base_edge_config = self.default_edge_config.copy() base_edge_config.update(non_edge_settings) base_edge_config = {e: base_edge_config.copy() for e in edges} for e in edges: base_edge_config[e].update(edge_config.get(e, {})) edge_config = base_edge_config edge_vertices = set(it.chain(*edges)) new_vertices = [v for v in edge_vertices if v not in self.vertices] added_vertices = self.add_vertices(*new_vertices, **kwargs) added_mobjects = sum( ( self._add_edge( edge, edge_type=edge_type, edge_config=edge_config[edge], ).submobjects for edge in edges ), added_vertices, ) return self.get_group_class()(*added_mobjects) @override_animate(add_edges) def _add_edges_animation(self, *args, anim_args=None, **kwargs): if anim_args is None: anim_args = {} animation = anim_args.pop("animation", Create) mobjects = self.add_edges(*args, **kwargs) return AnimationGroup( *(animation(mobj, **anim_args) for mobj in mobjects), group=self ) def _remove_edge(self, edge: tuple[Hashable]): """Remove an edge from the graph. Parameters ---------- edge The edge (i.e., a tuple of vertex identifiers) to be removed from the graph. Returns ------- Mobject The removed edge. """ if edge not in self.edges: raise ValueError(f"The graph does not contain a edge '{edge}'") edge_mobject = self.edges.pop(edge) self._graph.remove_edge(*edge) self._edge_config.pop(edge, None) self.remove(edge_mobject) return edge_mobject def remove_edges(self, *edges: tuple[Hashable]): """Remove several edges from the graph. Parameters ---------- edges Edges to be removed from the graph. Returns ------- Group A group containing all removed edges. """ edge_mobjects = [self._remove_edge(edge) for edge in edges] return self.get_group_class()(*edge_mobjects) @override_animate(remove_edges) def _remove_edges_animation(self, *edges, anim_args=None): if anim_args is None: anim_args = {} animation = anim_args.pop("animation", Uncreate) mobjects = self.remove_edges(*edges) return AnimationGroup(*(animation(mobj, **anim_args) for mobj in mobjects)) @classmethod def from_networkx( cls, nxgraph: nx.classes.graph.Graph | nx.classes.digraph.DiGraph, **kwargs ): """Build a :class:`~.Graph` or :class:`~.DiGraph` from a given ``networkx`` graph. Parameters ---------- nxgraph A ``networkx`` graph or digraph. **kwargs Keywords to be passed to the constructor of :class:`~.Graph`. Examples -------- .. manim:: ImportNetworkxGraph import networkx as nx nxgraph = nx.erdos_renyi_graph(14, 0.5) class ImportNetworkxGraph(Scene): def construct(self): G = Graph.from_networkx(nxgraph, layout="spring", layout_scale=3.5) self.play(Create(G)) self.play(*[G[v].animate.move_to(5*RIGHT*np.cos(ind/7 * PI) + 3*UP*np.sin(ind/7 * PI)) for ind, v in enumerate(G.vertices)]) self.play(Uncreate(G)) """ return cls(list(nxgraph.nodes), list(nxgraph.edges), **kwargs) def change_layout( self, layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = "spring", layout_scale: float | tuple[float, float, float] = 2, layout_config: dict[str, Any] | None = None, partitions: list[list[Hashable]] | None = None, root_vertex: Hashable | None = None, ) -> Graph: """Change the layout of this graph. See the documentation of :class:`~.Graph` for details about the keyword arguments. Examples -------- .. manim:: ChangeGraphLayout class ChangeGraphLayout(Scene): def construct(self): G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5)], layout={1: [-2, 0, 0], 2: [-1, 0, 0], 3: [0, 0, 0], 4: [1, 0, 0], 5: [2, 0, 0]} ) self.play(Create(G)) self.play(G.animate.change_layout("circular")) self.wait() """ layout_config = {} if layout_config is None else layout_config if partitions is not None and "partitions" not in layout_config: layout_config["partitions"] = partitions if root_vertex is not None and "root_vertex" not in layout_config: layout_config["root_vertex"] = root_vertex self._layout = _determine_graph_layout( self._graph, layout=layout, layout_scale=layout_scale, layout_config=layout_config, ) for v in self.vertices: self[v].move_to(self._layout[v]) return self class Graph(GenericGraph): """An undirected graph (vertices connected with edges). The graph comes with an updater which makes the edges stick to the vertices when moved around. See :class:`.DiGraph` for a version with directed edges. See also -------- :class:`.GenericGraph` Parameters ---------- vertices A list of vertices. Must be hashable elements. edges A list of edges, specified as tuples ``(u, v)`` where both ``u`` and ``v`` are vertices. The vertex order is irrelevant. labels Controls whether or not vertices are labeled. If ``False`` (the default), the vertices are not labeled; if ``True`` they are labeled using their names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively, custom labels can be specified by passing a dictionary whose keys are the vertices, and whose values are the corresponding vertex labels (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`). label_fill_color Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``. layout Either one of ``"spring"`` (the default), ``"circular"``, ``"kamada_kawai"``, ``"planar"``, ``"random"``, ``"shell"``, ``"spectral"``, ``"spiral"``, ``"tree"``, and ``"partite"`` for automatic vertex positioning using ``networkx`` (see `their documentation `_ for more details), or a dictionary specifying a coordinate (value) for each vertex (key) for manual positioning. layout_config Only for automatically generated layouts. A dictionary whose entries are passed as keyword arguments to the automatic layout algorithm specified via ``layout`` of ``networkx``. The ``tree`` layout also accepts a special parameter ``vertex_spacing`` passed as a keyword argument inside the ``layout_config`` dictionary. Passing a tuple ``(space_x, space_y)`` as this argument overrides the value of ``layout_scale`` and ensures that vertices are arranged in a way such that the centers of siblings in the same layer are at least ``space_x`` units apart horizontally, and neighboring layers are spaced ``space_y`` units vertically. layout_scale The scale of automatically generated layouts: the vertices will be arranged such that the coordinates are located within the interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)`` causing the first coordinate to be in the interval ``[-scale_x, scale_x]``, and the second in ``[-scale_y, scale_y]``. Default: 2. vertex_type The mobject class used for displaying vertices in the scene. vertex_config Either a dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``, or a dictionary whose keys are the vertices, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding vertex. vertex_mobjects A dictionary whose keys are the vertices, and whose values are mobjects to be used as vertices. Passing vertices here overrides all other configuration options for a vertex. edge_type The mobject class used for displaying edges in the scene. edge_config Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edges, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding edge. Examples -------- First, we create a small graph and demonstrate that the edges move together with the vertices. .. manim:: MovingVertices class MovingVertices(Scene): def construct(self): vertices = [1, 2, 3, 4] edges = [(1, 2), (2, 3), (3, 4), (1, 3), (1, 4)] g = Graph(vertices, edges) self.play(Create(g)) self.wait() self.play(g[1].animate.move_to([1, 1, 0]), g[2].animate.move_to([-1, 1, 0]), g[3].animate.move_to([1, -1, 0]), g[4].animate.move_to([-1, -1, 0])) self.wait() There are several automatic positioning algorithms to choose from: .. manim:: GraphAutoPosition :save_last_frame: class GraphAutoPosition(Scene): def construct(self): vertices = [1, 2, 3, 4, 5, 6, 7, 8] edges = [(1, 7), (1, 8), (2, 3), (2, 4), (2, 5), (2, 8), (3, 4), (6, 1), (6, 2), (6, 3), (7, 2), (7, 4)] autolayouts = ["spring", "circular", "kamada_kawai", "planar", "random", "shell", "spectral", "spiral"] graphs = [Graph(vertices, edges, layout=lt).scale(0.5) for lt in autolayouts] r1 = VGroup(*graphs[:3]).arrange() r2 = VGroup(*graphs[3:6]).arrange() r3 = VGroup(*graphs[6:]).arrange() self.add(VGroup(r1, r2, r3).arrange(direction=DOWN)) Vertices can also be positioned manually: .. manim:: GraphManualPosition :save_last_frame: class GraphManualPosition(Scene): def construct(self): vertices = [1, 2, 3, 4] edges = [(1, 2), (2, 3), (3, 4), (4, 1)] lt = {1: [0, 0, 0], 2: [1, 1, 0], 3: [1, -1, 0], 4: [-1, 0, 0]} G = Graph(vertices, edges, layout=lt) self.add(G) The vertices in graphs can be labeled, and configurations for vertices and edges can be modified both by default and for specific vertices and edges. .. note:: In ``edge_config``, edges can be passed in both directions: if ``(u, v)`` is an edge in the graph, both ``(u, v)`` as well as ``(v, u)`` can be used as keys in the dictionary. .. manim:: LabeledModifiedGraph :save_last_frame: class LabeledModifiedGraph(Scene): def construct(self): vertices = [1, 2, 3, 4, 5, 6, 7, 8] edges = [(1, 7), (1, 8), (2, 3), (2, 4), (2, 5), (2, 8), (3, 4), (6, 1), (6, 2), (6, 3), (7, 2), (7, 4)] g = Graph(vertices, edges, layout="circular", layout_scale=3, labels=True, vertex_config={7: {"fill_color": RED}}, edge_config={(1, 7): {"stroke_color": RED}, (2, 7): {"stroke_color": RED}, (4, 7): {"stroke_color": RED}}) self.add(g) You can also lay out a partite graph on columns by specifying a list of the vertices on each side and choosing the partite layout. .. note:: All vertices in your graph which are not listed in any of the partitions are collected in their own partition and rendered in the rightmost column. .. manim:: PartiteGraph :save_last_frame: import networkx as nx class PartiteGraph(Scene): def construct(self): G = nx.Graph() G.add_nodes_from([0, 1, 2, 3]) G.add_edges_from([(0, 2), (0,3), (1, 2)]) graph = Graph(list(G.nodes), list(G.edges), layout="partite", partitions=[[0, 1]]) self.play(Create(graph)) The representation of a linear artificial neural network is facilitated by the use of the partite layout and defining partitions for each layer. .. manim:: LinearNN :save_last_frame: class LinearNN(Scene): def construct(self): edges = [] partitions = [] c = 0 layers = [2, 3, 3, 2] # the number of neurons in each layer for i in layers: partitions.append(list(range(c + 1, c + i + 1))) c += i for i, v in enumerate(layers[1:]): last = sum(layers[:i+1]) for j in range(v): for k in range(last - layers[i], last): edges.append((k + 1, j + last + 1)) vertices = np.arange(1, sum(layers) + 1) graph = Graph( vertices, edges, layout='partite', partitions=partitions, layout_scale=3, vertex_config={'radius': 0.20}, ) self.add(graph) The custom tree layout can be used to show the graph by distance from the root vertex. You must pass the root vertex of the tree. .. manim:: Tree import networkx as nx class Tree(Scene): def construct(self): G = nx.Graph() G.add_node("ROOT") for i in range(5): G.add_node("Child_%i" % i) G.add_node("Grandchild_%i" % i) G.add_node("Greatgrandchild_%i" % i) G.add_edge("ROOT", "Child_%i" % i) G.add_edge("Child_%i" % i, "Grandchild_%i" % i) G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i) self.play(Create( Graph(list(G.nodes), list(G.edges), layout="tree", root_vertex="ROOT"))) The following code sample illustrates the use of the ``vertex_spacing`` layout parameter specific to the ``"tree"`` layout. As mentioned above, setting ``vertex_spacing`` overrides the specified value for ``layout_scale``, and as such it is harder to control the size of the mobject. However, we can adjust the captured frame and zoom out by using a :class:`.MovingCameraScene`:: class LargeTreeGeneration(MovingCameraScene): DEPTH = 4 CHILDREN_PER_VERTEX = 3 LAYOUT_CONFIG = {"vertex_spacing": (0.5, 1)} VERTEX_CONF = {"radius": 0.25, "color": BLUE_B, "fill_opacity": 1} def expand_vertex(self, g, vertex_id: str, depth: int): new_vertices = [ f"{vertex_id}/{i}" for i in range(self.CHILDREN_PER_VERTEX) ] new_edges = [(vertex_id, child_id) for child_id in new_vertices] g.add_edges( *new_edges, vertex_config=self.VERTEX_CONF, positions={ k: g.vertices[vertex_id].get_center() + 0.1 * DOWN for k in new_vertices }, ) if depth < self.DEPTH: for child_id in new_vertices: self.expand_vertex(g, child_id, depth + 1) return g def construct(self): g = Graph(["ROOT"], [], vertex_config=self.VERTEX_CONF) g = self.expand_vertex(g, "ROOT", 1) self.add(g) self.play( g.animate.change_layout( "tree", root_vertex="ROOT", layout_config=self.LAYOUT_CONFIG, ) ) self.play(self.camera.auto_zoom(g, margin=1), run_time=0.5) """ @staticmethod def _empty_networkx_graph() -> nx.Graph: return nx.Graph() def _populate_edge_dict( self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject] ): self.edges = { (u, v): edge_type( start=self[u].get_center(), end=self[v].get_center(), z_index=-1, **self._edge_config[(u, v)], ) for (u, v) in edges } def update_edges(self, graph): for (u, v), edge in graph.edges.items(): # Undirected graph has a Line edge edge.set_points_by_ends( graph[u].get_center(), graph[v].get_center(), buff=self._edge_config.get("buff", 0), path_arc=self._edge_config.get("path_arc", 0), ) def __repr__(self: Graph) -> str: return f"Undirected graph on {len(self.vertices)} vertices and {len(self.edges)} edges" class DiGraph(GenericGraph): """A directed graph. .. note:: In contrast to undirected graphs, the order in which vertices in a given edge are specified is relevant here. See also -------- :class:`.GenericGraph` Parameters ---------- vertices A list of vertices. Must be hashable elements. edges A list of edges, specified as tuples ``(u, v)`` where both ``u`` and ``v`` are vertices. The edge is directed from ``u`` to ``v``. labels Controls whether or not vertices are labeled. If ``False`` (the default), the vertices are not labeled; if ``True`` they are labeled using their names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively, custom labels can be specified by passing a dictionary whose keys are the vertices, and whose values are the corresponding vertex labels (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`). label_fill_color Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``. layout Either one of ``"spring"`` (the default), ``"circular"``, ``"kamada_kawai"``, ``"planar"``, ``"random"``, ``"shell"``, ``"spectral"``, ``"spiral"``, ``"tree"``, and ``"partite"`` for automatic vertex positioning using ``networkx`` (see `their documentation `_ for more details), or a dictionary specifying a coordinate (value) for each vertex (key) for manual positioning. layout_config Only for automatically generated layouts. A dictionary whose entries are passed as keyword arguments to the automatic layout algorithm specified via ``layout`` of ``networkx``. The ``tree`` layout also accepts a special parameter ``vertex_spacing`` passed as a keyword argument inside the ``layout_config`` dictionary. Passing a tuple ``(space_x, space_y)`` as this argument overrides the value of ``layout_scale`` and ensures that vertices are arranged in a way such that the centers of siblings in the same layer are at least ``space_x`` units apart horizontally, and neighboring layers are spaced ``space_y`` units vertically. layout_scale The scale of automatically generated layouts: the vertices will be arranged such that the coordinates are located within the interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)`` causing the first coordinate to be in the interval ``[-scale_x, scale_x]``, and the second in ``[-scale_y, scale_y]``. Default: 2. vertex_type The mobject class used for displaying vertices in the scene. vertex_config Either a dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``, or a dictionary whose keys are the vertices, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding vertex. vertex_mobjects A dictionary whose keys are the vertices, and whose values are mobjects to be used as vertices. Passing vertices here overrides all other configuration options for a vertex. edge_type The mobject class used for displaying edges in the scene. edge_config Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edges, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding edge. You can further customize the tip by adding a ``tip_config`` dictionary for global styling, or by adding the dict to a specific ``edge_config``. Examples -------- .. manim:: MovingDiGraph class MovingDiGraph(Scene): def construct(self): vertices = [1, 2, 3, 4] edges = [(1, 2), (2, 3), (3, 4), (1, 3), (1, 4)] g = DiGraph(vertices, edges) self.add(g) self.play( g[1].animate.move_to([1, 1, 1]), g[2].animate.move_to([-1, 1, 2]), g[3].animate.move_to([1, -1, -1]), g[4].animate.move_to([-1, -1, 0]), ) self.wait() You can customize the edges and arrow tips globally or locally. .. manim:: CustomDiGraph class CustomDiGraph(Scene): def construct(self): vertices = [i for i in range(5)] edges = [ (0, 1), (1, 2), (3, 2), (3, 4), ] edge_config = { "stroke_width": 2, "tip_config": { "tip_shape": ArrowSquareTip, "tip_length": 0.15, }, (3, 4): { "color": RED, "tip_config": {"tip_length": 0.25, "tip_width": 0.25} }, } g = DiGraph( vertices, edges, labels=True, layout="circular", edge_config=edge_config, ).scale(1.4) self.play(Create(g)) self.wait() Since this implementation respects the labels boundary you can also use it for an undirected moving graph with labels. .. manim:: UndirectedMovingDiGraph class UndirectedMovingDiGraph(Scene): def construct(self): vertices = [i for i in range(5)] edges = [ (0, 1), (1, 2), (3, 2), (3, 4), ] edge_config = { "stroke_width": 2, "tip_config": {"tip_length": 0, "tip_width": 0}, (3, 4): {"color": RED}, } g = DiGraph( vertices, edges, labels=True, layout="circular", edge_config=edge_config, ).scale(1.4) self.play(Create(g)) self.wait() self.play( g[1].animate.move_to([1, 1, 1]), g[2].animate.move_to([-1, 1, 2]), g[3].animate.move_to([-1.5, -1.5, -1]), g[4].animate.move_to([1, -2, -1]), ) self.wait() """ @staticmethod def _empty_networkx_graph() -> nx.DiGraph: return nx.DiGraph() def _populate_edge_dict( self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject] ): self.edges = { (u, v): edge_type( start=self[u], end=self[v], z_index=-1, **self._edge_config[(u, v)], ) for (u, v) in edges } for (u, v), edge in self.edges.items(): edge.add_tip(**self._tip_config[(u, v)]) def update_edges(self, graph): """Updates the edges to stick at their corresponding vertices. Arrow tips need to be repositioned since otherwise they can be deformed. """ for (u, v), edge in graph.edges.items(): tip = edge.pop_tips()[0] # Passing the Mobject instead of the vertex makes the tip # stop on the bounding box of the vertex. edge.set_points_by_ends( graph[u], graph[v], buff=self._edge_config.get("buff", 0), path_arc=self._edge_config.get("path_arc", 0), ) edge.add_tip(tip) def __repr__(self: DiGraph) -> str: return f"Directed graph on {len(self.vertices)} vertices and {len(self.edges)} edges" ================================================ FILE: manim/mobject/graphing/__init__.py ================================================ """Coordinate systems and function graphing related mobjects. Modules ======= .. autosummary:: :toctree: ../reference ~coordinate_systems ~functions ~number_line ~probability ~scale """ ================================================ FILE: manim/mobject/graphing/coordinate_systems.py ================================================ """Mobjects that represent coordinate systems.""" from __future__ import annotations __all__ = [ "CoordinateSystem", "Axes", "ThreeDAxes", "NumberPlane", "PolarPlane", "ComplexPlane", ] import fractions as fr import numbers from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING, Any, Self, TypeVar, overload import numpy as np from manim import config from manim.constants import * from manim.mobject.geometry.arc import Circle, Dot from manim.mobject.geometry.line import Arrow, DashedLine, Line from manim.mobject.geometry.polygram import Polygon, Rectangle, RegularPolygon from manim.mobject.graphing.functions import ImplicitFunction, ParametricFunction from manim.mobject.graphing.number_line import NumberLine from manim.mobject.graphing.scale import LinearBase from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_surface import OpenGLSurface from manim.mobject.text.tex_mobject import MathTex from manim.mobject.three_d.three_dimensions import Surface from manim.mobject.types.vectorized_mobject import ( VDict, VectorizedPoint, VGroup, VMobject, ) from manim.utils.color import ( BLACK, BLUE, BLUE_D, GREEN, PURE_YELLOW, WHITE, ManimColor, ParsableManimColor, color_gradient, interpolate_color, invert_color, ) from manim.utils.config_ops import merge_dicts_recursively, update_dict_recursively from manim.utils.simple_functions import binary_search from manim.utils.space_ops import angle_of_vector if TYPE_CHECKING: from manim.mobject.mobject import Mobject from manim.typing import ( ManimFloat, Point2D, Point2DLike, Point3D, Point3DLike, Vector3D, Vector3DLike, ) LineType = TypeVar("LineType", bound=Line) class CoordinateSystem: r"""Abstract base class for Axes and NumberPlane. Examples -------- .. manim:: CoordSysExample :save_last_frame: class CoordSysExample(Scene): def construct(self): # the location of the ticks depends on the x_range and y_range. grid = Axes( x_range=[0, 1, 0.05], # step size determines num_decimal_places. y_range=[0, 1, 0.05], x_length=9, y_length=5.5, axis_config={ "numbers_to_include": np.arange(0, 1 + 0.1, 0.1), "font_size": 24, }, tips=False, ) # Labels for the x-axis and y-axis. y_label = grid.get_y_axis_label("y", edge=LEFT, direction=LEFT, buff=0.4) x_label = grid.get_x_axis_label("x") grid_labels = VGroup(x_label, y_label) graphs = VGroup() for n in np.arange(1, 20 + 0.5, 0.5): graphs += grid.plot(lambda x: x ** n, color=WHITE) graphs += grid.plot( lambda x: x ** (1 / n), color=WHITE, use_smoothing=False ) # Extra lines and labels for point (1,1) graphs += grid.get_horizontal_line(grid @ (1, 1, 0), color=BLUE) graphs += grid.get_vertical_line(grid @ (1, 1, 0), color=BLUE) graphs += Dot(point=grid @ (1, 1, 0), color=YELLOW) graphs += Tex("(1,1)").scale(0.75).next_to(grid @ (1, 1, 0)) title = Title( # spaces between braces to prevent SyntaxError r"Graphs of $y=x^{ {1}\over{n} }$ and $y=x^n (n=1,2,3,...,20)$", include_underline=False, font_size=40, ) self.add(title, graphs, grid, grid_labels) """ def __init__( self, x_range: Sequence[float] | None = None, y_range: Sequence[float] | None = None, x_length: float | None = None, y_length: float | None = None, dimension: int = 2, ): self.dimension = dimension default_step = 1 if x_range is None: x_range = [ round(-config["frame_x_radius"]), round(config["frame_x_radius"]), default_step, ] elif len(x_range) == 2: x_range = [*x_range, default_step] if y_range is None: y_range = [ round(-config["frame_y_radius"]), round(config["frame_y_radius"]), default_step, ] elif len(y_range) == 2: y_range = [*y_range, default_step] self.x_range = x_range self.y_range = y_range self.x_length = x_length self.y_length = y_length self.num_sampled_graph_points_per_tick = 10 self.x_axis: NumberLine def coords_to_point(self, *coords: ManimFloat) -> Point3D: # TODO: I think the method should be able to return more than just a single point. # E.g. see the implementation of it on line 2065. raise NotImplementedError() def point_to_coords(self, point: Point3DLike) -> list[ManimFloat]: raise NotImplementedError() def polar_to_point(self, radius: float, azimuth: float) -> Point2D: r"""Gets a point from polar coordinates. Parameters ---------- radius The coordinate radius (:math:`r`). azimuth The coordinate azimuth (:math:`\theta`). Returns ------- numpy.ndarray The point. Examples -------- .. manim:: PolarToPointExample :ref_classes: PolarPlane Vector :save_last_frame: class PolarToPointExample(Scene): def construct(self): polarplane_pi = PolarPlane(azimuth_units="PI radians", size=6) polartopoint_vector = Vector(polarplane_pi.polar_to_point(3, PI/4)) self.add(polarplane_pi) self.add(polartopoint_vector) """ return self.coords_to_point(radius * np.cos(azimuth), radius * np.sin(azimuth)) def point_to_polar(self, point: Point2DLike) -> Point2D: r"""Gets polar coordinates from a point. Parameters ---------- point The point. Returns ------- Point2D The coordinate radius (:math:`r`) and the coordinate azimuth (:math:`\theta`). """ x, y = self.point_to_coords(point) return np.sqrt(x**2 + y**2), np.arctan2(y, x) def c2p( self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray ) -> np.ndarray: """Abbreviation for :meth:`coords_to_point`""" return self.coords_to_point(*coords) def p2c(self, point: Point3DLike) -> list[ManimFloat]: """Abbreviation for :meth:`point_to_coords`""" return self.point_to_coords(point) def pr2pt(self, radius: float, azimuth: float) -> np.ndarray: """Abbreviation for :meth:`polar_to_point`""" return self.polar_to_point(radius, azimuth) def pt2pr(self, point: np.ndarray) -> Point2D: """Abbreviation for :meth:`point_to_polar`""" return self.point_to_polar(point) def get_axes(self) -> VGroup: raise NotImplementedError() def get_axis(self, index: int) -> NumberLine: val: NumberLine = self.get_axes()[index] return val def get_origin(self) -> Point3D: """Gets the origin of :class:`~.Axes`. Returns ------- np.ndarray The center point. """ return self.coords_to_point(0, 0) def get_x_axis(self) -> NumberLine: return self.get_axis(0) def get_y_axis(self) -> NumberLine: return self.get_axis(1) def get_z_axis(self) -> NumberLine: return self.get_axis(2) def get_x_unit_size(self) -> float: return self.get_x_axis().get_unit_size() def get_y_unit_size(self) -> float: return self.get_y_axis().get_unit_size() def get_x_axis_label( self, label: float | str | VMobject, edge: Vector3D = UR, direction: Vector3D = UR, buff: float = SMALL_BUFF, **kwargs: Any, ) -> Mobject: """Generate an x-axis label. Parameters ---------- label The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. edge The edge of the x-axis to which the label will be added, by default ``UR``. direction Allows for further positioning of the label from an edge, by default ``UR``. buff The distance of the label from the line. Returns ------- :class:`~.Mobject` The positioned label. Examples -------- .. manim:: GetXAxisLabelExample :save_last_frame: class GetXAxisLabelExample(Scene): def construct(self): ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5) x_label = ax.get_x_axis_label( Tex("$x$-values").scale(0.65), edge=DOWN, direction=DOWN, buff=0.5 ) self.add(ax, x_label) """ return self._get_axis_label( label, self.get_x_axis(), edge, direction, buff=buff, **kwargs ) def get_y_axis_label( self, label: float | str | VMobject, edge: Vector3D = UR, direction: Vector3D = UP * 0.5 + RIGHT, buff: float = SMALL_BUFF, **kwargs: Any, ) -> Mobject: """Generate a y-axis label. Parameters ---------- label The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. edge The edge of the y-axis to which the label will be added, by default ``UR``. direction Allows for further positioning of the label from an edge, by default ``UR`` buff The distance of the label from the line. Returns ------- :class:`~.Mobject` The positioned label. Examples -------- .. manim:: GetYAxisLabelExample :save_last_frame: class GetYAxisLabelExample(Scene): def construct(self): ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5) y_label = ax.get_y_axis_label( Tex("$y$-values").scale(0.65).rotate(90 * DEGREES), edge=LEFT, direction=LEFT, buff=0.3, ) self.add(ax, y_label) """ return self._get_axis_label( label, self.get_y_axis(), edge, direction, buff=buff, **kwargs ) def _get_axis_label( self, label: float | str | VMobject, axis: Mobject, edge: Vector3DLike, direction: Vector3DLike, buff: float = SMALL_BUFF, ) -> Mobject: """Gets the label for an axis. Parameters ---------- label The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. axis The axis to which the label will be added. edge The edge of the axes to which the label will be added. ``RIGHT`` adds to the right side of the axis direction Allows for further positioning of the label. buff The distance of the label from the line. Returns ------- :class:`~.Mobject` The positioned label along the given axis. """ label_mobject: Mobject = self.x_axis._create_label_tex(label) label_mobject.next_to( axis.get_edge_center(edge), direction=direction, buff=buff ) label_mobject.shift_onto_screen(buff=MED_SMALL_BUFF) return label_mobject def get_axis_labels(self) -> VGroup: raise NotImplementedError() def add_coordinates( self, *axes_numbers: Iterable[float] | None | dict[float, str | float | Mobject], **kwargs: Any, ) -> Self: """Adds labels to the axes. Use ``Axes.coordinate_labels`` to access the coordinates after creation. Parameters ---------- axes_numbers The numbers to be added to the axes. Use ``None`` to represent an axis with default labels. Examples -------- .. code-block:: python ax = ThreeDAxes() x_labels = range(-4, 5) z_labels = range(-4, 4, 2) ax.add_coordinates( x_labels, None, z_labels ) # default y labels, custom x & z labels ax.add_coordinates(x_labels) # only x labels You can also specifically control the position and value of the labels using a dict. .. code-block:: python ax = Axes(x_range=[0, 7]) x_pos = [x for x in range(1, 8)] # strings are automatically converted into a Tex mobject. x_vals = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", ] 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: axes_numbers = [None for _ in range(self.dimension)] for axis, values in zip(self.axes, axes_numbers, strict=False): if isinstance(values, dict): axis.add_labels(values, **kwargs) labels = axis.labels elif values is None and axis.scaling.custom_labels: tick_range = axis.get_tick_range() axis.add_labels( dict( zip( tick_range, axis.scaling.get_custom_labels(tick_range), strict=True, ) ) ) labels = axis.labels else: axis.add_numbers(values, **kwargs) labels = axis.numbers self.coordinate_labels.add(labels) return self # overload necessary until https://github.com/python/mypy/issues/3737 is supported @overload def get_line_from_axis_to_point( self, index: int, point: Point3DLike, line_config: dict | None = ..., color: ParsableManimColor | None = ..., stroke_width: float = ..., ) -> DashedLine: ... @overload def get_line_from_axis_to_point( self, index: int, point: Point3DLike, line_func: type[LineType], line_config: dict | None = ..., color: ParsableManimColor | None = ..., stroke_width: float = ..., ) -> LineType: ... def get_line_from_axis_to_point( # type: ignore[no-untyped-def] self, index, point, line_func=DashedLine, line_config=None, color=None, stroke_width=2, ): """Returns a straight line from a given axis to a point in the scene. Parameters ---------- index Specifies the axis from which to draw the line. `0 = x_axis`, `1 = y_axis` point The point to which the line will be drawn. line_func The function of the :class:`~.Line` mobject used to construct the line. line_config Optional arguments to passed to :attr:`line_func`. color The color of the line. stroke_width The stroke width of the line. Returns ------- :class:`~.Line` The line from an axis to a point. .. seealso:: :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: color = VMobject().color line_config["color"] = ManimColor.parse(color) line_config["stroke_width"] = stroke_width axis = self.get_axis(index) line = line_func(axis.get_projection(point), point, **line_config) return line def get_vertical_line(self, point: Point3DLike, **kwargs: Any) -> Line: """A vertical line from the x-axis to a given point in the scene. Parameters ---------- point The point to which the vertical line will be drawn. kwargs Additional parameters to be passed to :class:`get_line_from_axis_to_point`. Returns ------- :class:`Line` A vertical line from the x-axis to the point. Examples -------- .. manim:: GetVerticalLineExample :save_last_frame: class GetVerticalLineExample(Scene): def construct(self): ax = Axes().add_coordinates() point = ax.coords_to_point(-3.5, 2) dot = Dot(point) line = ax.get_vertical_line(point, line_config={"dashed_ratio": 0.85}) self.add(ax, line, dot) """ return self.get_line_from_axis_to_point(0, point, **kwargs) def get_horizontal_line(self, point: Point3DLike, **kwargs: Any) -> Line: """A horizontal line from the y-axis to a given point in the scene. Parameters ---------- point The point to which the horizontal line will be drawn. kwargs Additional parameters to be passed to :class:`get_line_from_axis_to_point`. Returns ------- :class:`Line` A horizontal line from the y-axis to the point. Examples -------- .. manim:: GetHorizontalLineExample :save_last_frame: class GetHorizontalLineExample(Scene): def construct(self): ax = Axes().add_coordinates() point = ax @ (-4, 1.5) dot = Dot(point) line = ax.get_horizontal_line(point, line_func=Line) self.add(ax, line, dot) """ return self.get_line_from_axis_to_point(1, point, **kwargs) def get_lines_to_point(self, point: Point3DLike, **kwargs: Any) -> VGroup: """Generate both horizontal and vertical lines from the axis to a point. Parameters ---------- point A point on the scene. kwargs Additional parameters to be passed to :meth:`get_line_from_axis_to_point` Returns ------- :class:`~.VGroup` A :class:`~.VGroup` of the horizontal and vertical lines. .. seealso:: :meth:`~.CoordinateSystem.get_vertical_line` :meth:`~.CoordinateSystem.get_horizontal_line` Examples -------- .. manim:: GetLinesToPointExample :save_last_frame: class GetLinesToPointExample(Scene): def construct(self): ax = Axes() circ = Circle(radius=0.5).move_to([-4, -1.5, 0]) lines_1 = ax.get_lines_to_point(circ.get_right(), color=GREEN_B) 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), ) # graphing def plot( self, function: Callable[[float], float], x_range: Sequence[float] | None = None, use_vectorized: bool = False, colorscale: Iterable[ParsableManimColor] | Iterable[ParsableManimColor, float] | None = None, colorscale_axis: int = 1, **kwargs: Any, ) -> ParametricFunction: """Generates a curve based on a function. Parameters ---------- function The function used to construct the :class:`~.ParametricFunction`. x_range The range of the curve along the axes. ``x_range = [x_min, x_max, x_step]``. use_vectorized Whether to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]`` colorscale Colors of the function. Optional parameter used when coloring a function by values. Passing a list of colors and a colorscale_axis will color the function by y-value. Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots where the color transitions. colorscale_axis Defines the axis on which the colorscale is applied (0 = x, 1 = y), default is y-axis (1). kwargs Additional parameters to be passed to :class:`~.ParametricFunction`. Returns ------- :class:`~.ParametricFunction` The plotted curve. .. warning:: This method may not produce accurate graphs since Manim currently relies on interpolation between evenly-spaced samples of the curve, instead of intelligent plotting. See the example below for some solutions to this problem. Examples -------- .. manim:: PlotExample :save_last_frame: class PlotExample(Scene): def construct(self): # construct the axes ax_1 = Axes( x_range=[0.001, 6], y_range=[-8, 2], x_length=5, y_length=3, tips=False, ) ax_2 = ax_1.copy() ax_3 = ax_1.copy() # position the axes ax_1.to_corner(UL) ax_2.to_corner(UR) ax_3.to_edge(DOWN) axes = VGroup(ax_1, ax_2, ax_3) # create the logarithmic curves def log_func(x): return np.log(x) # a curve without adjustments; poor interpolation. curve_1 = ax_1.plot(log_func, color=PURE_RED) # disabling interpolation makes the graph look choppy as not enough # inputs are available curve_2 = ax_2.plot(log_func, use_smoothing=False, color=ORANGE) # taking more inputs of the curve by specifying a step for the # x_range yields expected results, but increases rendering time. curve_3 = ax_3.plot( log_func, x_range=(0.001, 6, 0.001), color=PURE_GREEN ) curves = VGroup(curve_1, curve_2, curve_3) 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 if x_range is None or len(x_range) < 3: # if t_range has a defined step size, increase the number of sample points per tick t_range[2] /= self.num_sampled_graph_points_per_tick # For axes, the third coordinate of x_range indicates # tick frequency. But for functions, it indicates a # sample frequency graph = ParametricFunction( lambda t: self.coords_to_point(t, function(t)), t_range=t_range, scaling=self.x_axis.scaling, use_vectorized=use_vectorized, **kwargs, ) graph.underlying_function = function if colorscale: if type(colorscale[0]) in (list, tuple): new_colors, pivots = [ [i for i, j in colorscale], [j for i, j in colorscale], ] else: new_colors = colorscale ranges = [self.x_range, self.y_range] pivot_min = ranges[colorscale_axis][0] pivot_max = ranges[colorscale_axis][1] pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1) pivots = np.arange( start=pivot_min, stop=pivot_max + pivot_frequency, step=pivot_frequency, ) resolution = 0.01 if len(x_range) == 2 else x_range[2] sample_points = np.arange(x_range[0], x_range[1] + resolution, resolution) color_list = [] for samp_x in sample_points: axis_value = (samp_x, function(samp_x))[colorscale_axis] if axis_value <= pivots[0]: color_list.append(new_colors[0]) elif axis_value >= pivots[-1]: color_list.append(new_colors[-1]) else: for i, pivot in enumerate(pivots): if pivot > axis_value: color_index = (axis_value - pivots[i - 1]) / ( pivots[i] - pivots[i - 1] ) color_index = min(color_index, 1) mob_color = interpolate_color( new_colors[i - 1], new_colors[i], color_index, ) color_list.append(mob_color) break if config.renderer == RendererType.OPENGL: graph.set_color(color_list) else: graph.set_stroke(color_list) graph.set_sheen_direction(RIGHT) return graph def plot_implicit_curve( self, func: Callable[[float, float], float], min_depth: int = 5, max_quads: int = 1500, **kwargs: Any, ) -> ImplicitFunction: """Creates the curves of an implicit function. Parameters ---------- func The function to graph, in the form of f(x, y) = 0. min_depth The minimum depth of the function to calculate. max_quads The maximum number of quads to use. kwargs Additional parameters to pass into :class:`ImplicitFunction`. Examples -------- .. manim:: ImplicitExample :save_last_frame: class ImplicitExample(Scene): def construct(self): ax = Axes() a = ax.plot_implicit_curve( lambda x, y: y * (x - y) ** 2 - 4 * x - 8, color=BLUE ) self.add(ax, a) """ x_scale = self.get_x_axis().scaling y_scale = self.get_y_axis().scaling graph = ImplicitFunction( func=(lambda x, y: func(x_scale.function(x), y_scale.function(y))), x_range=self.x_range[:2], y_range=self.y_range[:2], min_depth=min_depth, max_quads=max_quads, **kwargs, ) ( graph.stretch(self.get_x_unit_size(), 0, about_point=ORIGIN) .stretch(self.get_y_unit_size(), 1, about_point=ORIGIN) .shift(self.get_origin()) ) return graph def plot_parametric_curve( self, function: Callable[[float], np.ndarray], use_vectorized: bool = False, **kwargs: Any, ) -> ParametricFunction: """A parametric curve. Parameters ---------- function A parametric function mapping a number to a point in the coordinate system. use_vectorized Whether to pass in the generated t value array to the function. Only use this if your function supports it. kwargs Any further keyword arguments are passed to :class:`.ParametricFunction`. Example ------- .. manim:: ParametricCurveExample :save_last_frame: class ParametricCurveExample(Scene): def construct(self): ax = Axes() cardioid = ax.plot_parametric_curve( lambda t: np.array( [ np.exp(1) * np.cos(t) * (1 - np.cos(t)), np.exp(1) * np.sin(t) * (1 - np.cos(t)), 0, ] ), t_range=[0, 2 * PI], color="#0FF1CE", ) self.add(ax, cardioid) """ dim = self.dimension graph = ParametricFunction( lambda t: self.coords_to_point(*function(t)[:dim]), use_vectorized=use_vectorized, **kwargs, ) graph.underlying_function = function return graph def plot_polar_graph( self, r_func: Callable[[float], float], theta_range: Sequence[float] | None = None, **kwargs: Any, ) -> ParametricFunction: """A polar graph. Parameters ---------- r_func The function r of theta. theta_range The range of theta as ``theta_range = [theta_min, theta_max, theta_step]``. kwargs Additional parameters passed to :class:`~.ParametricFunction`. Examples -------- .. manim:: PolarGraphExample :ref_classes: PolarPlane :save_last_frame: class PolarGraphExample(Scene): def construct(self): plane = PolarPlane() r = lambda theta: 2 * np.sin(theta * 5) graph = plane.plot_polar_graph(r, [0, 2 * PI], color=ORANGE) self.add(plane, graph) """ theta_range = theta_range if theta_range is not None else [0, 2 * PI] graph = ParametricFunction( function=lambda th: self.pr2pt(r_func(th), th), t_range=theta_range, **kwargs, ) graph.underlying_function = r_func return graph def plot_surface( self, function: Callable[[float], float], u_range: Sequence[float] | None = None, v_range: Sequence[float] | None = None, colorscale: ( Sequence[ParsableManimColor] | Sequence[tuple[ParsableManimColor, float]] | None ) = None, colorscale_axis: int = 2, **kwargs: Any, ) -> Surface | OpenGLSurface: """Generates a surface based on a function. Parameters ---------- function The function used to construct the :class:`~.Surface`. u_range The range of the ``u`` variable: ``(u_min, u_max)``. v_range The range of the ``v`` variable: ``(v_min, v_max)``. colorscale Colors of the surface. Passing a list of colors will color the surface by z-value. Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots where the color transitions. colorscale_axis Defines the axis on which the colorscale is applied (0 = x, 1 = y, 2 = z), default is z-axis (2). kwargs Additional parameters to be passed to :class:`~.Surface`. Returns ------- :class:`~.Surface` The plotted surface. Examples -------- .. manim:: PlotSurfaceExample :save_last_frame: class PlotSurfaceExample(ThreeDScene): def construct(self): resolution_fa = 16 self.set_camera_orientation(phi=75 * DEGREES, theta=-60 * DEGREES) axes = ThreeDAxes(x_range=(-3, 3, 1), y_range=(-3, 3, 1), z_range=(-5, 5, 1)) def param_trig(u, v): x = u y = v z = 2 * np.sin(x) + 2 * np.cos(y) return z trig_plane = axes.plot_surface( param_trig, resolution=(resolution_fa, resolution_fa), u_range = (-3, 3), v_range = (-3, 3), colorscale = [BLUE, GREEN, YELLOW, ORANGE, RED], ) self.add(axes, trig_plane) """ if config.renderer == RendererType.CAIRO: surface = Surface( lambda u, v: self.c2p(u, v, function(u, v)), u_range=u_range, v_range=v_range, **kwargs, ) if colorscale: surface.set_fill_by_value( axes=self.copy(), colorscale=colorscale, axis=colorscale_axis, ) elif config.renderer == RendererType.OPENGL: surface = OpenGLSurface( lambda u, v: self.c2p(u, v, function(u, v)), u_range=u_range, v_range=v_range, axes=self.copy(), colorscale=colorscale, colorscale_axis=colorscale_axis, **kwargs, ) return surface def input_to_graph_point( self, x: float, graph: ParametricFunction | VMobject, ) -> Point3D: """Returns the coordinates of the point on a ``graph`` corresponding to an ``x`` value. Parameters ---------- x The x-value of a point on the ``graph``. graph The :class:`~.ParametricFunction` on which the point lies. Returns ------- :class:`np.ndarray` The coordinates of the point on the :attr:`graph` corresponding to the :attr:`x` value. Raises ------ :exc:`ValueError` When the target x is not in the range of the line graph. Examples -------- .. manim:: InputToGraphPointExample :save_last_frame: class InputToGraphPointExample(Scene): def construct(self): ax = Axes() curve = ax.plot(lambda x : np.cos(x)) # move a square to PI on the cosine curve. position = ax.input_to_graph_point(x=PI, graph=curve) sq = Square(side_length=1, color=YELLOW).move_to(position) self.add(ax, curve, sq) """ if hasattr(graph, "underlying_function"): return graph.function(x) else: alpha = binary_search( function=lambda a: self.point_to_coords(graph.point_from_proportion(a))[ 0 ], target=x, lower_bound=0, upper_bound=1, ) if alpha is not None: return graph.point_from_proportion(alpha) else: raise ValueError( f"x={x} not located in the range of the graph ([{self.p2c(graph.get_start())[0]}, {self.p2c(graph.get_end())[0]}])", ) def input_to_graph_coords( self, x: float, graph: ParametricFunction ) -> tuple[float, float]: """Returns a tuple of the axis relative coordinates of the point on the graph based on the x-value given. Examples -------- .. code-block:: pycon >>> from manim import Axes >>> ax = Axes() >>> parabola = ax.plot(lambda x: x**2) >>> ax.input_to_graph_coords(x=3, graph=parabola) (3, 9) """ return x, graph.underlying_function(x) def i2gc(self, x: float, graph: ParametricFunction) -> tuple[float, float]: """Alias for :meth:`input_to_graph_coords`.""" return self.input_to_graph_coords(x, graph) def i2gp(self, x: float, graph: ParametricFunction) -> np.ndarray: """Alias for :meth:`input_to_graph_point`.""" return self.input_to_graph_point(x, graph) def get_graph_label( self, graph: ParametricFunction, label: float | str | VMobject = "f(x)", x_val: float | None = None, direction: Sequence[float] = RIGHT, buff: float = MED_SMALL_BUFF, color: ParsableManimColor | None = None, dot: bool = False, dot_config: dict[str, Any] | None = None, ) -> Mobject: r"""Creates a properly positioned label for the passed graph, with an optional dot. Parameters ---------- graph The curve. label The label for the function's curve. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. x_val The x_value along the curve that positions the label. direction The cartesian position, relative to the curve that the label will be at --> ``LEFT``, ``RIGHT``. buff The distance between the curve and the label. color The color of the label. Defaults to the color of the curve. dot Whether to add a dot at the point on the graph. dot_config Additional parameters to be passed to :class:`~.Dot`. Returns ------- :class:`Mobject` The positioned label and :class:`~.Dot`, if applicable. Examples -------- .. manim:: GetGraphLabelExample :save_last_frame: class GetGraphLabelExample(Scene): def construct(self): ax = Axes() sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B) label = ax.get_graph_label( graph=sin, label= MathTex(r"\frac{\pi}{2}"), x_val=PI / 2, dot=True, direction=UR, ) self.add(ax, sin, label) """ if dot_config is None: dot_config = {} if color is None: color = graph.get_color() label_object: Mobject = self.x_axis._create_label_tex(label).set_color(color) if x_val is None: # Search from right to left for x in np.linspace(self.x_range[1], self.x_range[0], 100): point = self.input_to_graph_point(x, graph) if point[1] < config["frame_y_radius"]: break else: point = self.input_to_graph_point(x_val, graph) label_object.next_to(point, direction, buff=buff) label_object.shift_onto_screen() if dot: dot = Dot(point=point, **dot_config) label_object.add(dot) label_object.dot = dot return label_object # calculus def get_riemann_rectangles( self, graph: ParametricFunction, x_range: Sequence[float] | None = None, dx: float = 0.1, input_sample_type: str = "left", stroke_width: float = 1, stroke_color: ParsableManimColor = BLACK, fill_opacity: float = 1, color: Iterable[ParsableManimColor] | ParsableManimColor = (BLUE, GREEN), show_signed_area: bool = True, bounded_graph: ParametricFunction | None = None, blend: bool = False, width_scale_factor: float = 1.001, ) -> VGroup: """Generates a :class:`~.VGroup` of the Riemann Rectangles for a given curve. Parameters ---------- graph The graph whose area will be approximated by Riemann rectangles. x_range The minimum and maximum x-values of the rectangles. ``x_range = [x_min, x_max]``. dx The change in x-value that separates each rectangle. input_sample_type Can be any of ``"left"``, ``"right"`` or ``"center"``. Refers to where the sample point for the height of each Riemann Rectangle will be inside the segments of the partition. stroke_width The stroke_width of the border of the rectangles. stroke_color The color of the border of the rectangle. fill_opacity The opacity of the rectangles. color The colors of the rectangles. Creates a balanced gradient if multiple colors are passed. show_signed_area Indicates negative area when the curve dips below the x-axis by inverting its color. blend Sets the :attr:`stroke_color` to :attr:`fill_color`, blending the rectangles without clear separation. bounded_graph If a secondary graph is specified, encloses the area between the two curves. width_scale_factor The factor by which the width of the rectangles is scaled. Returns ------- :class:`~.VGroup` A :class:`~.VGroup` containing the Riemann Rectangles. Examples -------- .. manim:: GetRiemannRectanglesExample :save_last_frame: class GetRiemannRectanglesExample(Scene): def construct(self): ax = Axes(y_range=[-2, 10]) quadratic = ax.plot(lambda x: 0.5 * x ** 2 - 0.5) # the rectangles are constructed from their top right corner. # passing an iterable to `color` produces a gradient rects_right = ax.get_riemann_rectangles( quadratic, x_range=[-4, -3], dx=0.25, color=(TEAL, BLUE_B, DARK_BLUE), input_sample_type="right", ) # the colour of rectangles below the x-axis is inverted # due to show_signed_area rects_left = ax.get_riemann_rectangles( quadratic, x_range=[-1.5, 1.5], dx=0.15, color=YELLOW ) bounding_line = ax.plot( lambda x: 1.5 * x, color=BLUE_B, x_range=[3.3, 6] ) bounded_rects = ax.get_riemann_rectangles( bounding_line, bounded_graph=quadratic, dx=0.15, x_range=[4, 5], show_signed_area=False, color=(MAROON_A, RED_B, PURPLE_D), ) self.add( 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: x_range = [graph.t_min, graph.t_max] else: x_min = max(graph.t_min, bounded_graph.t_min) x_max = min(graph.t_max, bounded_graph.t_max) x_range = [x_min, x_max] x_range = [*x_range[:2], dx] rectangles = VGroup() x_range_array = np.arange(*x_range) if isinstance(color, (list, tuple)): color = [ManimColor(c) for c in color] else: color = [ManimColor(color)] colors = color_gradient(color, len(x_range_array)) for x, color in zip(x_range_array, colors, strict=True): if input_sample_type == "left": sample_input = x elif input_sample_type == "right": sample_input = x + dx elif input_sample_type == "center": sample_input = x + 0.5 * dx else: raise ValueError("Invalid input sample type") graph_point = self.input_to_graph_point(sample_input, graph) if bounded_graph is None: y_point = self._origin_shift(self.y_range) else: y_point = bounded_graph.underlying_function(x) points = VGroup( *list( map( VectorizedPoint, [ self.coords_to_point(x, y_point), self.coords_to_point(x + width_scale_factor * dx, y_point), graph_point, ], ), ) ) rect = Rectangle().replace(points, stretch=True) rectangles.add(rect) # checks if the rectangle is under the x-axis if self.p2c(graph_point)[1] < y_point and show_signed_area: color = invert_color(color) # blends rectangles smoothly if blend: stroke_color = color rect.set_style( fill_color=color, fill_opacity=fill_opacity, stroke_color=stroke_color, stroke_width=stroke_width, ) return rectangles def get_area( self, graph: ParametricFunction, x_range: tuple[float, float] | None = None, color: ParsableManimColor | Iterable[ParsableManimColor] = (BLUE, GREEN), opacity: float = 0.3, bounded_graph: ParametricFunction | None = None, **kwargs: Any, ) -> Polygon: """Returns a :class:`~.Polygon` representing the area under the graph passed. Parameters ---------- graph The graph/curve for which the area needs to be gotten. x_range The range of the minimum and maximum x-values of the area. ``x_range = [x_min, x_max]``. color The color of the area. Creates a gradient if a list of colors is provided. opacity The opacity of the area. bounded_graph If a secondary :attr:`graph` is specified, encloses the area between the two curves. kwargs Additional parameters passed to :class:`~.Polygon`. Returns ------- :class:`~.Polygon` The :class:`~.Polygon` representing the area. Raises ------ :exc:`ValueError` When x_ranges do not match (either area x_range, graph's x_range or bounded_graph's x_range). Examples -------- .. manim:: GetAreaExample :save_last_frame: class GetAreaExample(Scene): def construct(self): ax = Axes().add_coordinates() curve = ax.plot(lambda x: 2 * np.sin(x), color=DARK_BLUE) area = ax.get_area( curve, x_range=(PI / 2, 3 * PI / 2), color=(GREEN_B, GREEN_D), opacity=1, ) self.add(ax, curve, area) """ if x_range is None: a = graph.t_min b = graph.t_max else: a, b = x_range if bounded_graph is not None: if bounded_graph.t_min > b: raise ValueError( f"Ranges not matching: {bounded_graph.t_min} < {b}", ) if bounded_graph.t_max < a: raise ValueError( f"Ranges not matching: {bounded_graph.t_max} > {a}", ) a = max(a, bounded_graph.t_min) b = min(b, bounded_graph.t_max) if bounded_graph is None: points = ( [self.c2p(a), graph.function(a)] + [p for p in graph.points if a <= self.p2c(p)[0] <= b] + [graph.function(b), self.c2p(b)] ) else: graph_points, bounded_graph_points = ( [g.function(a)] + [p for p in g.points if a <= self.p2c(p)[0] <= b] + [g.function(b)] for g in (graph, bounded_graph) ) points = graph_points + bounded_graph_points[::-1] return Polygon(*points, **kwargs).set_opacity(opacity).set_color(color) def angle_of_tangent( self, x: float, graph: ParametricFunction, dx: float = 1e-8, ) -> float: """Returns the angle to the x-axis of the tangent to the plotted curve at a particular x-value. Parameters ---------- x The x-value at which the tangent must touch the curve. graph The :class:`~.ParametricFunction` for which to calculate the tangent. dx The change in `x` used to determine the angle of the tangent to the curve. Returns ------- :class:`float` The angle of the tangent to the curve. Examples -------- .. code-block:: python ax = Axes() curve = ax.plot(lambda x: x**2) 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) def slope_of_tangent( self, x: float, graph: ParametricFunction, **kwargs: Any ) -> float: """Returns the slope of the tangent to the plotted curve at a particular x-value. Parameters ---------- x The x-value at which the tangent must touch the curve. graph The :class:`~.ParametricFunction` for which to calculate the tangent. Returns ------- :class:`float` The slope of the tangent with the x axis. Examples -------- .. code-block:: python ax = Axes() curve = ax.plot(lambda x: x**2) ax.slope_of_tangent(x=-2, graph=curve) # -3.5000000259052038 """ val: float = np.tan(self.angle_of_tangent(x, graph, **kwargs)) return val def plot_derivative_graph( self, graph: ParametricFunction, color: ParsableManimColor = GREEN, **kwargs: Any, ) -> ParametricFunction: """Returns the curve of the derivative of the passed graph. Parameters ---------- graph The graph for which the derivative will be found. color The color of the derivative curve. kwargs Any valid keyword argument of :class:`~.ParametricFunction`. Returns ------- :class:`~.ParametricFunction` The curve of the derivative. Examples -------- .. manim:: DerivativeGraphExample :save_last_frame: class DerivativeGraphExample(Scene): def construct(self): ax = NumberPlane(y_range=[-1, 7], background_line_style={"stroke_opacity": 0.4}) curve_1 = ax.plot(lambda x: x ** 2, color=PURPLE_B) curve_2 = ax.plot_derivative_graph(curve_1) curves = VGroup(curve_1, curve_2) label_1 = ax.get_graph_label(curve_1, "x^2", x_val=-2, direction=DL) label_2 = ax.get_graph_label(curve_2, "2x", x_val=3, direction=RIGHT) labels = VGroup(label_1, label_2) self.add(ax, curves, labels) """ def deriv(x: float) -> float: return self.slope_of_tangent(x, graph) return self.plot(deriv, color=color, **kwargs) def plot_antiderivative_graph( self, graph: ParametricFunction, y_intercept: float = 0, samples: int = 50, use_vectorized: bool = False, **kwargs: Any, ) -> ParametricFunction: """Plots an antiderivative graph. Parameters ---------- graph The graph for which the antiderivative will be found. y_intercept The y-value at which the graph intercepts the y-axis. samples The number of points to take the area under the graph. use_vectorized Whether to use the vectorized version of the antiderivative. This means to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]`` kwargs Any valid keyword argument of :class:`~.ParametricFunction`. Returns ------- :class:`~.ParametricFunction` The curve of the antiderivative. .. note:: This graph is plotted from the values of area under the reference graph. The result might not be ideal if the reference graph contains uncalculatable areas from x=0. Examples -------- .. manim:: AntiderivativeExample :save_last_frame: class AntiderivativeExample(Scene): def construct(self): ax = Axes() graph1 = ax.plot( lambda x: (x ** 2 - 2) / 3, color=RED, ) graph2 = ax.plot_antiderivative_graph(graph1, color=BLUE) self.add(ax, graph1, graph2) """ def antideriv(x): x_vals = np.linspace(0, x, samples, axis=1 if use_vectorized else 0) f_vec = np.vectorize(graph.underlying_function) y_vals = f_vec(x_vals) return np.trapezoid(y_vals, x_vals) + y_intercept return self.plot(antideriv, use_vectorized=use_vectorized, **kwargs) def get_secant_slope_group( self, x: float, graph: ParametricFunction, dx: float | None = None, dx_line_color: ParsableManimColor = PURE_YELLOW, dy_line_color: ParsableManimColor | None = None, dx_label: float | str | None = None, dy_label: float | str | None = None, include_secant_line: bool = True, secant_line_color: ParsableManimColor = GREEN, secant_line_length: float = 10, ) -> VGroup: """Creates two lines representing `dx` and `df`, the labels for `dx` and `df`, and the secant to the curve at a particular x-value. Parameters ---------- x The x-value at which the secant intersects the graph for the first time. graph The curve for which the secant will be found. dx The change in `x` after which the secant exits. dx_line_color The color of the line that indicates the change in `x`. dy_line_color The color of the line that indicates the change in `y`. Defaults to the color of :attr:`graph`. dx_label The label for the `dx` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. dy_label The label for the `dy` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. include_secant_line Whether to include the secant line in the graph, or just the df/dx lines and labels. secant_line_color The color of the secant line. secant_line_length The length of the secant line. Returns ------- :class:`~.VGroup` A group containing the elements: `dx_line`, `df_line`, and if applicable also :attr:`dx_label`, :attr:`df_label`, `secant_line`. Examples -------- .. manim:: GetSecantSlopeGroupExample :save_last_frame: class GetSecantSlopeGroupExample(Scene): def construct(self): ax = Axes(y_range=[-1, 7]) graph = ax.plot(lambda x: 1 / 4 * x ** 2, color=BLUE) slopes = ax.get_secant_slope_group( x=2.0, graph=graph, dx=1.0, dx_label=Tex("dx = 1.0"), dy_label="dy", dx_line_color=GREEN_B, secant_line_length=4, secant_line_color=RED_D, ) self.add(ax, graph, slopes) """ group = VGroup() dx = dx or float(self.x_range[1] - self.x_range[0]) / 10 dy_line_color = dy_line_color or graph.get_color() p1 = self.input_to_graph_point(x, graph) p2 = self.input_to_graph_point(x + dx, graph) interim_point = p2[0] * RIGHT + p1[1] * UP group.dx_line = Line(p1, interim_point, color=dx_line_color) group.df_line = Line(interim_point, p2, color=dy_line_color) group.add(group.dx_line, group.df_line) labels = VGroup() if dx_label is not None: group.dx_label = self.x_axis._create_label_tex(dx_label) labels.add(group.dx_label) group.add(group.dx_label) if dy_label is not None: group.df_label = self.x_axis._create_label_tex(dy_label) labels.add(group.df_label) group.add(group.df_label) if len(labels) > 0: max_width = 0.8 * group.dx_line.width max_height = 0.8 * group.df_line.height if labels.width > max_width: labels.width = max_width if labels.height > max_height: labels.height = max_height if dx_label is not None: group.dx_label.next_to( group.dx_line, np.sign(dx) * DOWN, buff=group.dx_label.height / 2, ) group.dx_label.set_color(group.dx_line.get_color()) if dy_label is not None: group.df_label.next_to( group.df_line, np.sign(dx) * RIGHT, buff=group.df_label.height / 2, ) group.df_label.set_color(group.df_line.get_color()) if include_secant_line: group.secant_line = Line(p1, p2, color=secant_line_color) group.secant_line.scale( secant_line_length / group.secant_line.get_length(), ) group.add(group.secant_line) return group def get_vertical_lines_to_graph( self, graph: ParametricFunction, x_range: Sequence[float] | None = None, num_lines: int = 20, **kwargs: Any, ) -> VGroup: """Obtains multiple lines from the x-axis to the curve. Parameters ---------- graph The graph along which the lines are placed. x_range A list containing the lower and and upper bounds of the lines: ``x_range = [x_min, x_max]``. num_lines The number of evenly spaced lines. kwargs Additional arguments to be passed to :meth:`~.CoordinateSystem.get_vertical_line`. Returns ------- :class:`~.VGroup` The :class:`~.VGroup` of the evenly spaced lines. Examples -------- .. manim:: GetVerticalLinesToGraph :save_last_frame: class GetVerticalLinesToGraph(Scene): def construct(self): ax = Axes( x_range=[0, 8.0, 1], y_range=[-1, 1, 0.2], axis_config={"font_size": 24}, ).add_coordinates() curve = ax.plot(lambda x: np.sin(x) / np.e ** 2 * x) lines = ax.get_vertical_lines_to_graph( curve, x_range=[0, 4], num_lines=30, color=BLUE ) self.add(ax, curve, lines) """ x_range = x_range if x_range is not None else self.x_range return VGroup( *( self.get_vertical_line(self.i2gp(x, graph), **kwargs) for x in np.linspace(x_range[0], x_range[1], num_lines) ) ) def get_T_label( self, x_val: float, graph: ParametricFunction, label: float | str | Mobject | None = None, label_color: ParsableManimColor | None = None, triangle_size: float = MED_SMALL_BUFF, triangle_color: ParsableManimColor | None = WHITE, line_func: type[Line] = Line, line_color: ParsableManimColor = PURE_YELLOW, ) -> VGroup: """Creates a labelled triangle marker with a vertical line from the x-axis to a curve at a given x-value. Parameters ---------- x_val The position along the curve at which the label, line and triangle will be constructed. graph The :class:`~.ParametricFunction` for which to construct the label. label The label of the vertical line and triangle. label_color The color of the label. triangle_size The size of the triangle. triangle_color The color of the triangle. line_func The function used to construct the vertical line. line_color The color of the vertical line. Returns ------- :class:`~.VGroup` A :class:`~.VGroup` of the label, triangle and vertical line mobjects. Examples -------- .. manim:: TLabelExample :save_last_frame: class TLabelExample(Scene): def construct(self): # defines the axes and linear function axes = Axes(x_range=[-1, 10], y_range=[-1, 10], x_length=9, y_length=6) func = axes.plot(lambda x: x, color=BLUE) # creates the T_label 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, opacity=1, ) triangle.height = triangle_size triangle.move_to(self.coords_to_point(x_val, 0), UP) if label is not None: t_label = self.x_axis._create_label_tex(label, color=label_color) t_label.next_to(triangle, DOWN) T_label_group.add(t_label) v_line = self.get_vertical_line( self.i2gp(x_val, graph), color=line_color, line_func=line_func, ) T_label_group.add(triangle, v_line) return T_label_group def __matmul__(self, coord: Point3DLike | Mobject) -> Point3DLike: if isinstance(coord, Mobject): coord = coord.get_center() return self.coords_to_point(*coord) def __rmatmul__(self, point: Point3DLike) -> Point3DLike: return self.point_to_coords(point) @staticmethod def _origin_shift(axis_range: Sequence[float]) -> float: ... class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL): """Creates a set of axes. Parameters ---------- x_range The ``(x_min, x_max, x_step)`` values of the x-axis. y_range The ``(y_min, y_max, y_step)`` values of the y-axis. x_length The length of the x-axis. y_length The length of the y-axis. axis_config Arguments to be passed to :class:`~.NumberLine` that influences both axes. x_axis_config Arguments to be passed to :class:`~.NumberLine` that influence the x-axis. y_axis_config Arguments to be passed to :class:`~.NumberLine` that influence the y-axis. tips Whether or not to include the tips on both axes. kwargs Additional arguments to be passed to :class:`CoordinateSystem` and :class:`~.VGroup`. Examples -------- .. manim:: LogScalingExample :save_last_frame: class LogScalingExample(Scene): def construct(self): ax = Axes( x_range=[0, 10, 1], y_range=[-2, 6, 1], tips=False, axis_config={"include_numbers": True}, y_axis_config={"scaling": LogBase(custom_labels=True)}, ) # x_min must be > 0 because log is undefined at 0. graph = ax.plot(lambda x: x ** 2, x_range=[0.001, 10], use_smoothing=False) self.add(ax, graph) Styling arguments can be passed to the underlying :class:`.NumberLine` mobjects that represent the axes: .. manim:: AxesWithDifferentTips :save_last_frame: class AxesWithDifferentTips(Scene): def construct(self): ax = Axes(axis_config={'tip_shape': StealthTip}) self.add(ax) """ def __init__( self, x_range: Sequence[float] | None = None, y_range: Sequence[float] | None = None, x_length: float | None = round(config.frame_width) - 2, y_length: float | None = round(config.frame_height) - 2, axis_config: dict | None = None, x_axis_config: dict | None = None, y_axis_config: dict | None = None, tips: bool = True, **kwargs: Any, ): VGroup.__init__(self, **kwargs) CoordinateSystem.__init__(self, x_range, y_range, x_length, y_length) self.axis_config = { "include_tip": tips, "numbers_to_exclude": [0], } self.x_axis_config: dict[str, Any] = {} self.y_axis_config: dict[str, Any] = { "rotation": 90 * DEGREES, "label_direction": LEFT, } self._update_default_configs( (self.axis_config, self.x_axis_config, self.y_axis_config), (axis_config, x_axis_config, y_axis_config), ) self.x_axis_config = merge_dicts_recursively( self.axis_config, self.x_axis_config, ) self.y_axis_config = merge_dicts_recursively( self.axis_config, self.y_axis_config, ) # excluding the origin tick removes a tick at the 0-point of the axis # This is desired for LinearBase because the 0 point is always the x-axis # For non-LinearBase, the "0-point" does not have this quality, so it must be included. # i.e. with LogBase range [-2, 4]: # it would remove the "0" tick, which is actually 10^0, # not the lowest tick on the graph (which is 10^-2). if self.x_axis_config.get("scaling") is None or isinstance( self.x_axis_config.get("scaling"), LinearBase ): self.x_axis_config["exclude_origin_tick"] = True else: self.x_axis_config["exclude_origin_tick"] = False if self.y_axis_config.get("scaling") is None or isinstance( self.y_axis_config.get("scaling"), LinearBase ): self.y_axis_config["exclude_origin_tick"] = True else: self.y_axis_config["exclude_origin_tick"] = False self.x_axis = self._create_axis(self.x_range, self.x_axis_config, self.x_length) self.y_axis = self._create_axis(self.y_range, self.y_axis_config, self.y_length) # Add as a separate group in case various other # mobjects are added to self, as for example in # NumberPlane below self.axes = VGroup(self.x_axis, self.y_axis) self.add(*self.axes) # finds the middle-point on each axis lines_center_point = [ axis.scaling.function((axis.x_range[1] + axis.x_range[0]) / 2) for axis in self.axes ] self.shift(-self.coords_to_point(*lines_center_point)) @staticmethod def _update_default_configs( default_configs: tuple[dict[Any, Any]], passed_configs: tuple[dict[Any, Any]] ) -> None: """Takes in two tuples of dicts and return modifies the first such that values from ``passed_configs`` overwrite values in ``default_configs``. If a key does not exist in default_configs, it is added to the dict. This method is useful for having defaults in a class and being able to overwrite them with user-defined input. Parameters ---------- default_configs The dict that will be updated. passed_configs The dict that will be used to update. Examples -------- To create a tuple with one dictionary, add a comma after the element: .. code-block:: python self._update_default_configs( (dict_1,)( dict_2, ) ) """ for default_config, passed_config in zip( default_configs, passed_configs, strict=False ): if passed_config is not None: update_dict_recursively(default_config, passed_config) def _create_axis( self, range_terms: Sequence[float], axis_config: dict[str, Any], length: float, ) -> NumberLine: """Creates an axis and dynamically adjusts its position depending on where 0 is located on the line. Parameters ---------- range_terms The range of the the axis : ``(x_min, x_max, x_step)``. axis_config Additional parameters that are passed to :class:`~.NumberLine`. length The length of the axis. Returns ------- :class:`NumberLine` Returns a number line based on ``range_terms``. """ axis_config["length"] = length axis = NumberLine(range_terms, **axis_config) # without the call to _origin_shift, graph does not exist when min > 0 or max < 0 # shifts the axis so that 0 is centered axis.shift(-axis.number_to_point(self._origin_shift([axis.x_min, axis.x_max]))) return axis def coords_to_point( self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray ) -> np.ndarray: """Accepts coordinates from the axes and returns a point with respect to the scene. Equivalent to `ax @ (coord1)` Parameters ---------- coords The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``. Also accepts a list of coordinates ``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )`` ``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )`` A single coordinate can also be passed as a flat list or 1D array: ``ax.coords_to_point( [x, y, z] )`` Returns ------- np.ndarray A point with respect to the scene's coordinate system. The shape of the array will be similar to the shape of the input. Examples -------- .. code-block:: pycon >>> from manim import Axes >>> import numpy as np >>> ax = Axes() >>> np.around(ax.coords_to_point(1, 0, 0), 2) array([0.86, 0. , 0. ]) >>> np.around(ax @ (1, 0, 0), 2) array([0.86, 0. , 0. ]) >>> np.around(ax.coords_to_point([[0, 1], [1, 1], [1, 0]]), 2) array([[0. , 0.75, 0. ], [0.86, 0.75, 0. ], [0.86, 0. , 0. ]]) >>> np.around( ... ax.coords_to_point([0, 1, 1], [1, 1, 0]), 2 ... ) # Transposed version of the above array([[0. , 0.86, 0.86], [0.75, 0.75, 0. ], [0. , 0. , 0. ]]) >>> np.around(ax.coords_to_point([1, 0, 0]), 2) array([0.86, 0. , 0. ]) >>> np.around(ax.coords_to_point(np.array([1, 0])), 2) array([0.86, 0. , 0. ]) .. manim:: CoordsToPointExample :save_last_frame: class CoordsToPointExample(Scene): def construct(self): ax = Axes().add_coordinates() # a dot with respect to the axes dot_axes = Dot(ax.coords_to_point(2, 2), color=GREEN) lines = ax.get_lines_to_point(ax.c2p(2,2)) # a dot with respect to the scene # the default plane corresponds to the coordinates of the scene. plane = NumberPlane() dot_scene = Dot((2,2,0), color=RED) self.add(plane, dot_scene, ax, dot_axes, lines) """ coords = np.asarray(coords) origin = self.x_axis.number_to_point( self._origin_shift([self.x_axis.x_min, self.x_axis.x_max]), ) # Is coords in the format ([[x1 y1 z1] [x2 y2 z2] ...])? (True) # Or is coords in the format (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...])? (False) # The latter is preferred. are_coordinates_transposed = False # If coords is in the format ([[x1 y1 z1] [x2 y2 z2] ...]): if coords.ndim == 3: # Extract from original tuple: now coords looks like [[x y z]] or [[x1 y1 z1] [x2 y2 z2] ...]. coords = coords[0] # If there's a single coord (coords = [[x y z]]), extract it so that # coords = [x y z] and coords_to_point returns a single point. if coords.shape[0] == 1: coords = coords[0] # Else, if coords looks more like [[x1 y1 z1] [x2 y2 z2] ...], transform them (by # transposing) into the format [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]] for later processing. else: coords = coords.T are_coordinates_transposed = True # If coords is in the format ([x, y, z]) -- a single flat list/array passed as one argument: elif coords.ndim == 2 and coords.shape[0] == 1: # Extract the single list so [x, y, z] is treated like c2p(x, y, z). coords = coords[0] # Otherwise, coords already looked like (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]), # so no further processing is needed. # Now coords should either look like [x y z] or [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]], # so it can be iterated directly. Each element is either a float representing a single # coordinate, or a float ndarray of coordinates corresponding to a single axis. # Although "points" and "nums" are in plural, there might be a single point or number. points = self.x_axis.number_to_point(coords[0]) other_axes = self.axes.submobjects[1:] for axis, nums in zip(other_axes, coords[1:], strict=False): points += axis.number_to_point(nums) - origin # Return points as is, except if coords originally looked like # ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]), which is determined by the conditions below. In # that case, the current implementation requires that the results have to be transposed. if are_coordinates_transposed or points.ndim == 1: return points return points.T def point_to_coords(self, point: Sequence[float]) -> np.ndarray: """Accepts a point from the scene and returns its coordinates with respect to the axes. Parameters ---------- point The point, i.e. ``RIGHT`` or ``[0, 1, 0]``. Also accepts a list of points as ``[RIGHT, [0, 1, 0]]``. Returns ------- np.ndarray[float] The coordinates on the axes, i.e. ``[4.0, 7.0]``. Or a list of coordinates if `point` is a list of points. Examples -------- .. code-block:: pycon >>> from manim import Axes, RIGHT >>> import numpy as np >>> ax = Axes(x_range=[0, 10, 2]) >>> np.around(ax.point_to_coords(RIGHT), 2) array([5.83, 0. ]) >>> np.around(ax.point_to_coords([[0, 0, 1], [1, 0, 0]]), 2) array([[5. , 0. ], [5.83, 0. ]]) .. manim:: PointToCoordsExample :save_last_frame: class PointToCoordsExample(Scene): def construct(self): ax = Axes(x_range=[0, 10, 2]).add_coordinates() circ = Circle(radius=0.5).shift(UR * 2) # get the coordinates of the circle with respect to the axes coords = np.around(ax.point_to_coords(circ.get_right()), decimals=2) label = ( Matrix([[coords[0]], [coords[1]]]).scale(0.75).next_to(circ, RIGHT) ) self.add(ax, circ, label, Dot(circ.get_right())) """ point = np.asarray(point) result = np.asarray([axis.point_to_number(point) for axis in self.get_axes()]) if point.ndim == 2: return result.T return result def get_axes(self) -> VGroup: """Gets the axes. Returns ------- :class:`~.VGroup` A pair of axes. """ return self.axes def get_axis_labels( self, x_label: float | str | Mobject = "x", y_label: float | str | Mobject = "y", ) -> VGroup: """Defines labels for the x-axis and y-axis of the graph. For increased control over the position of the labels, use :meth:`~.CoordinateSystem.get_x_axis_label` and :meth:`~.CoordinateSystem.get_y_axis_label`. Parameters ---------- x_label The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. y_label The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. Returns ------- :class:`~.VGroup` A :class:`~.VGroup` of the labels for the x_axis and y_axis. .. seealso:: :meth:`~.CoordinateSystem.get_x_axis_label` :meth:`~.CoordinateSystem.get_y_axis_label` Examples -------- .. manim:: GetAxisLabelsExample :save_last_frame: class GetAxisLabelsExample(Scene): def construct(self): ax = Axes() labels = ax.get_axis_labels( Tex("x-axis").scale(0.7), Text("y-axis").scale(0.45) ) self.add(ax, labels) """ self.axis_labels = VGroup( self.get_x_axis_label(x_label), self.get_y_axis_label(y_label), ) return self.axis_labels def plot_line_graph( self, x_values: Iterable[float], y_values: Iterable[float], z_values: Iterable[float] | None = None, line_color: ParsableManimColor = PURE_YELLOW, add_vertex_dots: bool = True, vertex_dot_radius: float = DEFAULT_DOT_RADIUS, vertex_dot_style: dict[str, Any] | None = None, **kwargs: Any, ) -> VDict: """Draws a line graph. The graph connects the vertices formed from zipping ``x_values``, ``y_values`` and ``z_values``. Also adds :class:`Dots <.Dot>` at the vertices if ``add_vertex_dots`` is set to ``True``. Parameters ---------- x_values Iterable of values along the x-axis. y_values Iterable of values along the y-axis. z_values Iterable of values (zeros if z_values is None) along the z-axis. line_color Color for the line graph. add_vertex_dots Whether or not to add :class:`~.Dot` at each vertex. vertex_dot_radius Radius for the :class:`~.Dot` at each vertex. vertex_dot_style Style arguments to be passed into :class:`~.Dot` at each vertex. kwargs Additional arguments to be passed into :class:`~.VMobject`. Returns ------- :class:`~.VDict` A VDict containing both the line and dots (if specified). The line can be accessed with: ``line_graph["line_graph"]``. The dots can be accessed with: ``line_graph["vertex_dots"]``. Examples -------- .. manim:: LineGraphExample :save_last_frame: class LineGraphExample(Scene): def construct(self): plane = NumberPlane( x_range = (0, 7), y_range = (0, 5), x_length = 7, axis_config={"include_numbers": True}, ) plane.center() line_graph = plane.plot_line_graph( x_values = [0, 1.5, 2, 2.8, 4, 6.25], y_values = [1, 3, 2.25, 4, 2.5, 1.75], line_color=GOLD_E, vertex_dot_style=dict(stroke_width=3, fill_color=PURPLE), stroke_width = 4, ) self.add(plane, line_graph) """ x_values, y_values = map(np.array, (x_values, y_values)) if z_values is None: z_values = np.zeros(x_values.shape) line_graph = VDict() graph = VGroup(color=line_color, **kwargs) vertices = [ self.coords_to_point(x, y, z) for x, y, z in zip(x_values, y_values, z_values, strict=True) ] graph.set_points_as_corners(vertices) line_graph["line_graph"] = graph if add_vertex_dots: vertex_dot_style = vertex_dot_style or {} vertex_dots = VGroup( *( Dot(point=vertex, radius=vertex_dot_radius, **vertex_dot_style) for vertex in vertices ) ) line_graph["vertex_dots"] = vertex_dots return line_graph @staticmethod def _origin_shift(axis_range: Sequence[float]) -> float: """Determines how to shift graph mobjects to compensate when 0 is not on the axis. Parameters ---------- axis_range The range of the axis : ``(x_min, x_max, x_step)``. """ if axis_range[0] > 0: # min greater than 0 return axis_range[0] if axis_range[1] < 0: # max less than 0 return axis_range[1] else: return 0 class ThreeDAxes(Axes): """A 3-dimensional set of axes. Parameters ---------- x_range The ``[x_min, x_max, x_step]`` values of the x-axis. y_range The ``[y_min, y_max, y_step]`` values of the y-axis. z_range The ``[z_min, z_max, z_step]`` values of the z-axis. x_length The length of the x-axis. y_length The length of the y-axis. z_length The length of the z-axis. z_axis_config Arguments to be passed to :class:`~.NumberLine` that influence the z-axis. z_normal The direction of the normal. num_axis_pieces The number of pieces used to construct the axes. light_source The direction of the light source. depth Currently non-functional. gloss Currently non-functional. kwargs Additional arguments to be passed to :class:`Axes`. """ def __init__( self, x_range: Sequence[float] | None = (-6, 6, 1), y_range: Sequence[float] | None = (-5, 5, 1), z_range: Sequence[float] | None = (-4, 4, 1), x_length: float | None = config.frame_height + 2.5, y_length: float | None = config.frame_height + 2.5, z_length: float | None = config.frame_height - 1.5, z_axis_config: dict[str, Any] | None = None, z_normal: Vector3DLike = DOWN, num_axis_pieces: int = 20, light_source: Point3DLike = 9 * DOWN + 7 * LEFT + 10 * OUT, # opengl stuff (?) depth: Any = None, gloss: float = 0.5, **kwargs: dict[str, Any], ): super().__init__( x_range=x_range, x_length=x_length, y_range=y_range, y_length=y_length, **kwargs, ) self.z_range = z_range self.z_length = z_length self.z_axis_config: dict[str, Any] = {} self._update_default_configs((self.z_axis_config,), (z_axis_config,)) self.z_axis_config = merge_dicts_recursively( self.axis_config, self.z_axis_config, ) self.z_normal = z_normal self.num_axis_pieces = num_axis_pieces self.light_source = np.array(light_source) self.dimension = 3 if self.z_axis_config.get("scaling") is None or isinstance( self.z_axis_config.get("scaling"), LinearBase ): self.z_axis_config["exclude_origin_tick"] = True else: self.z_axis_config["exclude_origin_tick"] = False z_axis = self._create_axis(self.z_range, self.z_axis_config, self.z_length) # [ax.x_min, ax.x_max] used to account for LogBase() scaling # where ax.x_range[0] != ax.x_min z_origin = self._origin_shift([z_axis.x_min, z_axis.x_max]) z_axis.rotate_about_number(z_origin, -PI / 2, UP) z_axis.rotate_about_number(z_origin, angle_of_vector(self.z_normal)) z_axis.shift(-z_axis.number_to_point(z_origin)) z_axis.shift( self.x_axis.number_to_point( self._origin_shift([self.x_axis.x_min, self.x_axis.x_max]), ), ) self.axes.add(z_axis) self.add(z_axis) self.z_axis = z_axis if config.renderer == RendererType.CAIRO: self._add_3d_pieces() self._set_axis_shading() def _add_3d_pieces(self) -> None: for axis in self.axes: axis.pieces = VGroup(*axis.get_pieces(self.num_axis_pieces)) axis.add(axis.pieces) axis.set_stroke(width=0, family=False) axis.set_shade_in_3d(True) def _set_axis_shading(self) -> None: def make_func(axis): vect = self.light_source return lambda: ( axis.get_edge_center(-vect), axis.get_edge_center(vect), ) for axis in self: for submob in axis.family_members_with_points(): submob.get_gradient_start_and_end_points = make_func(axis) submob.get_unit_normal = lambda a: np.ones(3) submob.set_sheen(0.2) def get_y_axis_label( self, label: float | str | VMobject, edge: Vector3DLike = UR, direction: Vector3DLike = UR, buff: float = SMALL_BUFF, rotation: float = PI / 2, rotation_axis: Vector3DLike = OUT, **kwargs: dict[str, Any], ) -> Mobject: """Generate a y-axis label. Parameters ---------- label The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. edge The edge of the y-axis to which the label will be added, by default ``UR``. direction Allows for further positioning of the label from an edge, by default ``UR``. buff The distance of the label from the line, by default ``SMALL_BUFF``. rotation The angle at which to rotate the label, by default ``PI/2``. rotation_axis The axis about which to rotate the label, by default ``OUT``. Returns ------- :class:`~.Mobject` The positioned label. Examples -------- .. manim:: GetYAxisLabelExample :save_last_frame: class GetYAxisLabelExample(ThreeDScene): def construct(self): ax = ThreeDAxes() lab = ax.get_y_axis_label(Tex("$y$-label")) 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 ) positioned_label.rotate(rotation, axis=rotation_axis) return positioned_label def get_z_axis_label( self, label: float | str | VMobject, edge: Vector3DLike = OUT, direction: Vector3DLike = RIGHT, buff: float = SMALL_BUFF, rotation: float = PI / 2, rotation_axis: Vector3DLike = RIGHT, **kwargs: Any, ) -> Mobject: """Generate a z-axis label. Parameters ---------- label The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. edge The edge of the z-axis to which the label will be added, by default ``OUT``. direction Allows for further positioning of the label from an edge, by default ``RIGHT``. buff The distance of the label from the line, by default ``SMALL_BUFF``. rotation The angle at which to rotate the label, by default ``PI/2``. rotation_axis The axis about which to rotate the label, by default ``RIGHT``. Returns ------- :class:`~.Mobject` The positioned label. Examples -------- .. manim:: GetZAxisLabelExample :save_last_frame: class GetZAxisLabelExample(ThreeDScene): def construct(self): ax = ThreeDAxes() lab = ax.get_z_axis_label(Tex("$z$-label")) 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 ) positioned_label.rotate(rotation, axis=rotation_axis) return positioned_label def get_axis_labels( self, x_label: float | str | VMobject = "x", y_label: float | str | VMobject = "y", z_label: float | str | VMobject = "z", ) -> VGroup: """Defines labels for the x_axis and y_axis of the graph. For increased control over the position of the labels, use :meth:`~.CoordinateSystem.get_x_axis_label`, :meth:`~.ThreeDAxes.get_y_axis_label`, and :meth:`~.ThreeDAxes.get_z_axis_label`. Parameters ---------- x_label The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. y_label The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. z_label The label for the z_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs. Returns ------- :class:`~.VGroup` A :class:`~.VGroup` of the labels for the x_axis, y_axis, and z_axis. .. seealso:: :meth:`~.CoordinateSystem.get_x_axis_label` :meth:`~.ThreeDAxes.get_y_axis_label` :meth:`~.ThreeDAxes.get_z_axis_label` Examples -------- .. manim:: GetAxisLabelsExample :save_last_frame: class GetAxisLabelsExample(ThreeDScene): def construct(self): self.set_camera_orientation(phi=2*PI/5, theta=PI/5) axes = ThreeDAxes() labels = axes.get_axis_labels( Text("x-axis").scale(0.7), Text("y-axis").scale(0.45), Text("z-axis").scale(0.45) ) self.add(axes, labels) """ self.axis_labels = VGroup( self.get_x_axis_label(x_label), self.get_y_axis_label(y_label), self.get_z_axis_label(z_label), ) return self.axis_labels class NumberPlane(Axes): """Creates a cartesian plane with background lines. Parameters ---------- x_range The ``[x_min, x_max, x_step]`` values of the plane in the horizontal direction. y_range The ``[y_min, y_max, y_step]`` values of the plane in the vertical direction. x_length The width of the plane. y_length The height of the plane. background_line_style Arguments that influence the construction of the background lines of the plane. faded_line_style Similar to :attr:`background_line_style`, affects the construction of the scene's background lines. faded_line_ratio Determines the number of boxes within the background lines: :code:`2` = 4 boxes, :code:`3` = 9 boxes. make_smooth_after_applying_functions Currently non-functional. kwargs Additional arguments to be passed to :class:`Axes`. .. note:: If :attr:`x_length` or :attr:`y_length` are not defined, they are automatically calculated such that one unit on each axis is one Manim unit long. Examples -------- .. manim:: NumberPlaneExample :save_last_frame: class NumberPlaneExample(Scene): def construct(self): number_plane = NumberPlane( background_line_style={ "stroke_color": TEAL, "stroke_width": 4, "stroke_opacity": 0.6 } ) self.add(number_plane) .. manim:: NumberPlaneScaled :save_last_frame: class NumberPlaneScaled(Scene): def construct(self): number_plane = NumberPlane( x_range=(-4, 11, 1), y_range=(-3, 3, 1), x_length=5, y_length=2, ).move_to(LEFT*3) number_plane_scaled_y = NumberPlane( x_range=(-4, 11, 1), x_length=5, y_length=4, ).move_to(RIGHT*3) self.add(number_plane) self.add(number_plane_scaled_y) """ def __init__( self, x_range: Sequence[float] | None = ( -config["frame_x_radius"], config["frame_x_radius"], 1, ), y_range: Sequence[float] | None = ( -config["frame_y_radius"], config["frame_y_radius"], 1, ), x_length: float | None = None, y_length: float | None = None, background_line_style: dict[str, Any] | None = None, faded_line_style: dict[str, Any] | None = None, faded_line_ratio: int = 1, make_smooth_after_applying_functions: bool = True, **kwargs: dict[str, Any], ): # configs self.axis_config: dict[str, Any] = { "stroke_width": 2, "include_ticks": False, "include_tip": False, "line_to_number_buff": SMALL_BUFF, "label_direction": DR, "font_size": 24, } self.y_axis_config: dict[str, Any] = {"label_direction": DR} self.background_line_style: dict[str, Any] = { "stroke_color": BLUE_D, "stroke_width": 2, "stroke_opacity": 1, } self._update_default_configs( (self.axis_config, self.y_axis_config, self.background_line_style), ( kwargs.pop("axis_config", None), kwargs.pop("y_axis_config", None), background_line_style, ), ) # Defaults to a faded version of line_config self.faded_line_style = faded_line_style self.faded_line_ratio = faded_line_ratio self.make_smooth_after_applying_functions = make_smooth_after_applying_functions # init super().__init__( x_range=x_range, y_range=y_range, x_length=x_length, y_length=y_length, axis_config=self.axis_config, y_axis_config=self.y_axis_config, **kwargs, ) self._init_background_lines() def _init_background_lines(self) -> None: """Will init all the lines of NumberPlanes (faded or not)""" if self.faded_line_style is None: style = dict(self.background_line_style) # For anything numerical, like stroke_width # and stroke_opacity, chop it in half for key in style: if isinstance(style[key], numbers.Number): style[key] *= 0.5 self.faded_line_style = style self.background_lines, self.faded_lines = self._get_lines() self.background_lines.set_style( **self.background_line_style, ) self.faded_lines.set_style( **self.faded_line_style, ) self.add_to_back( self.faded_lines, self.background_lines, ) def _get_lines(self) -> tuple[VGroup, VGroup]: """Generate all the lines, faded and not faded. Two sets of lines are generated: one parallel to the X-axis, and parallel to the Y-axis. Returns ------- Tuple[:class:`~.VGroup`, :class:`~.VGroup`] The first (i.e the non faded lines) and second (i.e the faded lines) sets of lines, respectively. """ x_axis = self.get_x_axis() y_axis = self.get_y_axis() x_lines1, x_lines2 = self._get_lines_parallel_to_axis( x_axis, y_axis, self.y_axis.x_range[2], self.faded_line_ratio, ) y_lines1, y_lines2 = self._get_lines_parallel_to_axis( y_axis, x_axis, self.x_axis.x_range[2], self.faded_line_ratio, ) # TODO this was added so that we can run tests on NumberPlane # In the future these attributes will be tacked onto self.background_lines self.x_lines = x_lines1 self.y_lines = y_lines1 lines1 = VGroup(*x_lines1, *y_lines1) lines2 = VGroup(*x_lines2, *y_lines2) return lines1, lines2 def _get_lines_parallel_to_axis( self, axis_parallel_to: NumberLine, axis_perpendicular_to: NumberLine, freq: float, ratio_faded_lines: int, ) -> tuple[VGroup, VGroup]: """Generate a set of lines parallel to an axis. Parameters ---------- axis_parallel_to The axis with which the lines will be parallel. axis_perpendicular_to The axis with which the lines will be perpendicular. ratio_faded_lines The ratio between the space between faded lines and the space between non-faded lines. freq Frequency of non-faded lines (number of non-faded lines per graph unit). Returns ------- Tuple[:class:`~.VGroup`, :class:`~.VGroup`] 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 step = (1 / ratio_faded_lines) * freq lines1 = VGroup() lines2 = VGroup() unit_vector_axis_perp_to = axis_perpendicular_to.get_unit_vector() # need to unpack all three values x_min, x_max, _ = axis_perpendicular_to.x_range # account for different axis scalings (logarithmic), where # negative values do not exist and [-2 , 4] should output lines # similar to [0, 6] if axis_perpendicular_to.x_min > 0 and x_min < 0: x_min, x_max = (0, np.abs(x_min) + np.abs(x_max)) # min/max used in case range does not include 0. i.e. if (2,6): # the range becomes (0,4), not (0,6). ranges = ( [0], np.arange(step, min(x_max - x_min, x_max), step), np.arange(-step, max(x_min - x_max, x_min), -step), ) for inputs in ranges: for k, x in enumerate(inputs): new_line = line.copy() new_line.shift(unit_vector_axis_perp_to * x) if (k + 1) % ratio_faded_lines == 0: lines1.add(new_line) else: lines2.add(new_line) return lines1, lines2 def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow: kwargs["buff"] = 0 return Arrow( self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs ) def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self: for mob in self.family_members_with_points(): num_curves = mob.get_num_curves() if num_inserted_curves > num_curves: mob.insert_n_curves(num_inserted_curves - num_curves) return self class PolarPlane(Axes): r"""Creates a polar plane with background lines. Parameters ---------- azimuth_step The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default specified by ``azimuth_units``: - ``"PI radians"`` or ``"TAU radians"``: 20 - ``"degrees"``: 36 - ``"gradians"``: 40 - ``None``: 1 A non-integer value will result in a partial division at the end of the circle. size The diameter of the plane. radius_step The distance between faded radius lines. radius_max The maximum value of the radius. azimuth_units Specifies a default labelling system for the azimuth. Choices are: - ``"PI radians"``: Fractional labels in the interval :math:`\left[0, 2\pi\right]` with :math:`\pi` as a constant. - ``"TAU radians"``: Fractional labels in the interval :math:`\left[0, \tau\right]` (where :math:`\tau = 2\pi`) with :math:`\tau` as a constant. - ``"degrees"``: Decimal labels in the interval :math:`\left[0, 360\right]` with a degree (:math:`^{\circ}`) symbol. - ``"gradians"``: Decimal labels in the interval :math:`\left[0, 400\right]` with a superscript "g" (:math:`^{g}`). - ``None``: Decimal labels in the interval :math:`\left[0, 1\right]`. azimuth_compact_fraction If the ``azimuth_units`` choice has fractional labels, choose whether to combine the constant in a compact form :math:`\tfrac{xu}{y}` as opposed to :math:`\tfrac{x}{y}u`, where :math:`u` is the constant. azimuth_offset The angle offset of the azimuth, expressed in radians. azimuth_direction The direction of the azimuth. - ``"CW"``: Clockwise. - ``"CCW"``: Anti-clockwise. azimuth_label_buff The buffer for the azimuth labels. azimuth_label_font_size The font size of the azimuth labels. radius_config The axis config for the radius. Examples -------- .. manim:: PolarPlaneExample :ref_classes: PolarPlane :save_last_frame: class PolarPlaneExample(Scene): def construct(self): polarplane_pi = PolarPlane( azimuth_units="PI radians", size=6, azimuth_label_font_size=33.6, radius_config={"font_size": 33.6}, ).add_coordinates() self.add(polarplane_pi) """ def __init__( self, radius_max: float = config["frame_y_radius"], size: float | None = None, radius_step: float = 1, azimuth_step: float | None = None, azimuth_units: str = "PI radians", azimuth_compact_fraction: bool = True, azimuth_offset: float = 0, azimuth_direction: str = "CCW", azimuth_label_buff: float = SMALL_BUFF, azimuth_label_font_size: float = 24, radius_config: dict[str, Any] | None = None, background_line_style: dict[str, Any] | None = None, faded_line_style: dict[str, Any] | None = None, faded_line_ratio: int = 1, make_smooth_after_applying_functions: bool = True, **kwargs: Any, ): # error catching if azimuth_units in ["PI radians", "TAU radians", "degrees", "gradians", None]: self.azimuth_units = azimuth_units else: raise ValueError( "Invalid azimuth units. Expected one of: PI radians, TAU radians, degrees, gradians or None.", ) if azimuth_direction in ["CW", "CCW"]: self.azimuth_direction = azimuth_direction else: raise ValueError("Invalid azimuth units. Expected one of: CW, CCW.") # configs self.radius_config = { "stroke_width": 2, "include_ticks": False, "include_tip": False, "line_to_number_buff": SMALL_BUFF, "label_direction": DL, "font_size": 24, } self.background_line_style = { "stroke_color": BLUE_D, "stroke_width": 2, "stroke_opacity": 1, } self.azimuth_step = ( ( { "PI radians": 20, "TAU radians": 20, "degrees": 36, "gradians": 40, None: 1, }[azimuth_units] ) if azimuth_step is None else azimuth_step ) self._update_default_configs( (self.radius_config, self.background_line_style), (radius_config, background_line_style), ) # Defaults to a faded version of line_config self.faded_line_style = faded_line_style self.faded_line_ratio = faded_line_ratio self.make_smooth_after_applying_functions = make_smooth_after_applying_functions self.azimuth_offset = azimuth_offset self.azimuth_label_buff = azimuth_label_buff self.azimuth_label_font_size = azimuth_label_font_size self.azimuth_compact_fraction = azimuth_compact_fraction # init super().__init__( x_range=np.array((-radius_max, radius_max, radius_step)), y_range=np.array((-radius_max, radius_max, radius_step)), x_length=size, y_length=size, axis_config=self.radius_config, **kwargs, ) self._init_background_lines() def _init_background_lines(self) -> None: """Will init all the lines of NumberPlanes (faded or not)""" if self.faded_line_style is None: style = dict(self.background_line_style) # For anything numerical, like stroke_width # and stroke_opacity, chop it in half for key in style: if isinstance(style[key], numbers.Number): style[key] *= 0.5 self.faded_line_style = style self.background_lines, self.faded_lines = self._get_lines() self.background_lines.set_style( **self.background_line_style, ) self.faded_lines.set_style( **self.faded_line_style, ) self.add_to_back( self.faded_lines, self.background_lines, ) def _get_lines(self) -> tuple[VGroup, VGroup]: """Generate all the lines and circles, faded and not faded. Returns ------- Tuple[:class:`~.VGroup`, :class:`~.VGroup`] The first (i.e the non faded lines and circles) and second (i.e the faded lines and circles) sets of lines and circles, respectively. """ center = self.get_origin() ratio_faded_lines = self.faded_line_ratio offset = self.azimuth_offset if ratio_faded_lines == 0: # don't show faded lines ratio_faded_lines = 1 # i.e. set ratio to 1 rstep = (1 / ratio_faded_lines) * self.x_axis.x_range[2] astep = (1 / ratio_faded_lines) * (TAU * (1 / self.azimuth_step)) rlines1 = VGroup() rlines2 = VGroup() alines1 = VGroup() alines2 = VGroup() rinput = np.arange(0, self.x_axis.x_range[1] + rstep, rstep) ainput = np.arange(0, TAU, astep) unit_vector = self.x_axis.get_unit_vector()[0] for k, x in enumerate(rinput): new_circle = Circle(radius=x * unit_vector) if k % ratio_faded_lines == 0: alines1.add(new_circle) else: alines2.add(new_circle) line = Line(center, self.get_x_axis().get_end()) for k, x in enumerate(ainput): new_line = line.copy() new_line.rotate(x + offset, about_point=center) if k % ratio_faded_lines == 0: rlines1.add(new_line) else: rlines2.add(new_line) lines1 = VGroup(*rlines1, *alines1) lines2 = VGroup(*rlines2, *alines2) return lines1, lines2 def get_axes(self) -> VGroup: """Gets the axes. Returns ------- :class:`~.VGroup` A pair of axes. """ return self.axes def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow: kwargs["buff"] = 0 return Arrow( self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs ) def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self: for mob in self.family_members_with_points(): num_curves = mob.get_num_curves() if num_inserted_curves > num_curves: mob.insert_n_curves(num_inserted_curves - num_curves) return self def get_coordinate_labels( self, r_values: Iterable[float] | None = None, a_values: Iterable[float] | None = None, **kwargs: Any, ) -> VDict: """Gets labels for the coordinates Parameters ---------- r_values Iterable of values along the radius, by default None. a_values Iterable of values along the azimuth, by default None. Returns ------- VDict Labels for the radius and azimuth values. """ if r_values is None: r_values = [r for r in self.get_x_axis().get_tick_range() if r >= 0] if a_values is None: a_values = np.arange(0, 1, 1 / self.azimuth_step) r_mobs = self.get_x_axis().add_numbers(r_values) if self.azimuth_direction == "CCW": d = 1 elif self.azimuth_direction == "CW": d = -1 else: raise ValueError("Invalid azimuth direction. Expected one of: CW, CCW") a_points = [ { "label": i, "point": np.array( [ self.get_right()[0] * np.cos(d * (i * TAU) + self.azimuth_offset), self.get_right()[0] * np.sin(d * (i * TAU) + self.azimuth_offset), 0, ], ), } for i in a_values ] a_tex = [] if self.azimuth_units == "PI radians" or self.azimuth_units == "TAU radians": a_tex = [ self.get_radian_label( i["label"], font_size=self.azimuth_label_font_size, ).next_to( i["point"], direction=i["point"], aligned_edge=i["point"], buff=self.azimuth_label_buff, ) for i in a_points ] elif self.azimuth_units == "degrees": a_tex = [ MathTex( f"{360 * i['label']:g}" + r"^{\circ}", font_size=self.azimuth_label_font_size, ).next_to( i["point"], direction=i["point"], aligned_edge=i["point"], buff=self.azimuth_label_buff, ) for i in a_points ] elif self.azimuth_units == "gradians": a_tex = [ MathTex( f"{400 * i['label']:g}" + r"^{g}", font_size=self.azimuth_label_font_size, ).next_to( i["point"], direction=i["point"], aligned_edge=i["point"], buff=self.azimuth_label_buff, ) for i in a_points ] elif self.azimuth_units is None: a_tex = [ MathTex( f"{i['label']:g}", font_size=self.azimuth_label_font_size, ).next_to( i["point"], direction=i["point"], aligned_edge=i["point"], buff=self.azimuth_label_buff, ) for i in a_points ] a_mobs = VGroup(*a_tex) self.coordinate_labels = VGroup(r_mobs, a_mobs) return self.coordinate_labels def add_coordinates( self, r_values: Iterable[float] | None = None, a_values: Iterable[float] | None = None, ) -> Self: """Adds the coordinates. Parameters ---------- r_values Iterable of values along the radius, by default None. a_values Iterable of values along the azimuth, by default None. """ self.add(self.get_coordinate_labels(r_values, a_values)) return self def get_radian_label( self, number: float, font_size: float = 24, **kwargs: Any ) -> MathTex: constant_label = {"PI radians": r"\pi", "TAU radians": r"\tau"}[ self.azimuth_units ] division = number * {"PI radians": 2, "TAU radians": 1}[self.azimuth_units] frac = fr.Fraction(division).limit_denominator(max_denominator=100) if frac.numerator == 0 & frac.denominator == 0: string = r"0" elif frac.numerator == 1 and frac.denominator == 1: string = constant_label elif frac.numerator == 1: if self.azimuth_compact_fraction: string = ( r"\tfrac{" + constant_label + r"}{" + str(frac.denominator) + "}" ) else: string = r"\tfrac{1}{" + str(frac.denominator) + "}" + constant_label elif frac.denominator == 1: string = str(frac.numerator) + constant_label else: if self.azimuth_compact_fraction: string = ( r"\tfrac{" + str(frac.numerator) + constant_label + r"}{" + str(frac.denominator) + r"}" ) else: string = ( r"\tfrac{" + str(frac.numerator) + r"}{" + str(frac.denominator) + r"}" + constant_label ) return MathTex(string, font_size=font_size, **kwargs) class ComplexPlane(NumberPlane): """A :class:`~.NumberPlane` specialized for use with complex numbers. Examples -------- .. manim:: ComplexPlaneExample :save_last_frame: :ref_classes: Dot MathTex class ComplexPlaneExample(Scene): def construct(self): plane = ComplexPlane().add_coordinates() self.add(plane) d1 = Dot(plane.n2p(2 + 1j), color=YELLOW) d2 = Dot(plane.n2p(-3 - 2j), color=YELLOW) label1 = MathTex("2+i").next_to(d1, UR, 0.1) label2 = MathTex("-3-2i").next_to(d2, UR, 0.1) self.add( d1, label1, d2, label2, ) """ def __init__(self, **kwargs: Any): super().__init__( **kwargs, ) def number_to_point(self, number: float | complex) -> np.ndarray: """Accepts a float/complex number and returns the equivalent point on the plane. Parameters ---------- number The number. Can be a float or a complex number. Returns ------- np.ndarray The point on the plane. """ number = complex(number) return self.coords_to_point(number.real, number.imag) def n2p(self, number: float | complex) -> np.ndarray: """Abbreviation for :meth:`number_to_point`.""" return self.number_to_point(number) def point_to_number(self, point: Point3DLike) -> complex: """Accepts a point and returns a complex number equivalent to that point on the plane. Parameters ---------- point The point in manim's coordinate-system Returns ------- complex A complex number consisting of real and imaginary components. """ x, y = self.point_to_coords(point) return complex(x, y) def p2n(self, point: Point3DLike) -> complex: """Abbreviation for :meth:`point_to_number`.""" return self.point_to_number(point) def _get_default_coordinate_values(self) -> list[float | complex]: """Generate a list containing the numerical values of the plane's labels. Returns ------- List[float | complex] A list of floats representing the x-axis and complex numbers representing the y-axis. """ x_numbers = self.get_x_axis().get_tick_range() y_numbers = self.get_y_axis().get_tick_range() y_numbers = [complex(0, y) for y in y_numbers if y != 0] return [*x_numbers, *y_numbers] def get_coordinate_labels( self, *numbers: Iterable[float | complex], **kwargs: Any ) -> VGroup: """Generates the :class:`~.DecimalNumber` mobjects for the coordinates of the plane. Parameters ---------- numbers An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis. kwargs Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`. Returns ------- :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() self.coordinate_labels = VGroup() for number in numbers: z = complex(number) if abs(z.imag) > abs(z.real): axis = self.get_y_axis() value = z.imag kwargs["unit"] = "i" else: axis = self.get_x_axis() value = z.real number_mob = axis.get_number_mobject(value, **kwargs) self.coordinate_labels.add(number_mob) return self.coordinate_labels def add_coordinates( self, *numbers: Iterable[float | complex], **kwargs: Any ) -> Self: """Adds the labels produced from :meth:`~.NumberPlane.get_coordinate_labels` to the plane. Parameters ---------- numbers An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis. 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 ================================================ FILE: manim/mobject/graphing/functions.py ================================================ """Mobjects representing function graphs.""" from __future__ import annotations __all__ = ["ParametricFunction", "FunctionGraph", "ImplicitFunction"] from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING import numpy as np from isosurfaces import plot_isoline from manim import config from manim.mobject.graphing.scale import LinearBase, _ScaleBase from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VMobject if TYPE_CHECKING: from typing import Any, Self from manim.typing import Point3D, Point3DLike from manim.utils.color import ParsableManimColor from manim.utils.color import PURE_YELLOW class ParametricFunction(VMobject, metaclass=ConvertToOpenGL): """A parametric curve. Parameters ---------- function The function to be plotted in the form of ``(lambda t: (x(t), y(t), z(t)))`` t_range Determines the length that the function spans in the form of (t_min, t_max, step=0.01). By default ``[0, 1]`` scaling Scaling class applied to the points of the function. Default of :class:`~.LinearBase`. use_smoothing Whether to interpolate between the points of the function after they have been created. (Will have odd behaviour with a low number of points) use_vectorized Whether to pass in the generated t value array to the function as ``[t_0, t_1, ...]``. Only use this if your function supports it. Output should be a numpy array of shape ``[[x_0, x_1, ...], [y_0, y_1, ...], [z_0, z_1, ...]]`` but ``z`` can also be 0 if the Axes is 2D discontinuities Values of t at which the function experiences discontinuity. dt The left and right tolerance for the discontinuities. Examples -------- .. manim:: PlotParametricFunction :save_last_frame: class PlotParametricFunction(Scene): def func(self, t): return (np.sin(2 * t), np.sin(3 * t), 0) def construct(self): func = ParametricFunction(self.func, t_range = (0, TAU), fill_opacity=0).set_color(RED) self.add(func.scale(3)) .. manim:: ThreeDParametricSpring :save_last_frame: class ThreeDParametricSpring(ThreeDScene): def construct(self): curve1 = ParametricFunction( lambda u: ( 1.2 * np.cos(u), 1.2 * np.sin(u), u * 0.05 ), color=RED, t_range = (-3*TAU, 5*TAU, 0.01) ).set_shade_in_3d(True) axes = ThreeDAxes() self.add(axes, curve1) self.set_camera_orientation(phi=80 * DEGREES, theta=-60 * DEGREES) self.wait() .. attention:: If your function has discontinuities, you'll have to specify the location of the discontinuities manually. See the following example for guidance. .. manim:: DiscontinuousExample :save_last_frame: class DiscontinuousExample(Scene): def construct(self): ax1 = NumberPlane((-3, 3), (-4, 4)) ax2 = NumberPlane((-3, 3), (-4, 4)) VGroup(ax1, ax2).arrange() discontinuous_function = lambda x: (x ** 2 - 2) / (x ** 2 - 4) incorrect = ax1.plot(discontinuous_function, color=RED) correct = ax2.plot( discontinuous_function, discontinuities=[-2, 2], # discontinuous points dt=0.1, # left and right tolerance of discontinuity color=GREEN, ) self.add(ax1, ax2, incorrect, correct) """ def __init__( self, function: Callable[[float], Point3DLike], t_range: tuple[float, float] | tuple[float, float, float] = (0, 1), scaling: _ScaleBase = LinearBase(), dt: float = 1e-8, discontinuities: Iterable[float] | None = None, use_smoothing: bool = True, use_vectorized: bool = False, **kwargs: Any, ): def internal_parametric_function(t: float) -> Point3D: """Wrap ``function``'s output inside a NumPy array.""" return np.asarray(function(t)) self.function = internal_parametric_function if len(t_range) == 2: t_range = (*t_range, 0.01) self.scaling = scaling self.dt = dt self.discontinuities = discontinuities self.use_smoothing = use_smoothing self.use_vectorized = use_vectorized self.t_min, self.t_max, self.t_step = t_range super().__init__(**kwargs) def get_function(self) -> Callable[[float], Point3D]: return self.function def get_point_from_function(self, t: float) -> Point3D: return self.function(t) def generate_points(self) -> Self: if self.discontinuities is not None: discontinuities = filter( lambda t: self.t_min <= t <= self.t_max, self.discontinuities, ) discontinuities_array = np.array(list(discontinuities)) boundary_times = np.array( [ self.t_min, self.t_max, *(discontinuities_array - self.dt), *(discontinuities_array + self.dt), ], ) boundary_times.sort() else: boundary_times = [self.t_min, self.t_max] for t1, t2 in zip(boundary_times[0::2], boundary_times[1::2], strict=True): t_range = np.array( [ *self.scaling.function(np.arange(t1, t2, self.t_step)), self.scaling.function(t2), ], ) if self.use_vectorized: x, y, z = self.function(t_range) if not isinstance(z, np.ndarray): z = np.zeros_like(x) points = np.stack([x, y, z], axis=1) else: points = np.array([self.function(t) for t in t_range]) self.start_new_path(points[0]) self.add_points_as_corners(points[1:]) if self.use_smoothing: # TODO: not in line with upstream, approx_smooth does not exist self.make_smooth() return self def init_points(self) -> None: self.generate_points() class FunctionGraph(ParametricFunction): """A :class:`ParametricFunction` that spans the length of the scene by default. Examples -------- .. manim:: ExampleFunctionGraph :save_last_frame: class ExampleFunctionGraph(Scene): def construct(self): cos_func = FunctionGraph( lambda t: np.cos(t) + 0.5 * np.cos(7 * t) + (1 / 7) * np.cos(14 * t), color=RED, ) sin_func_1 = FunctionGraph( lambda t: np.sin(t) + 0.5 * np.sin(7 * t) + (1 / 7) * np.sin(14 * t), color=BLUE, ) sin_func_2 = FunctionGraph( lambda t: np.sin(t) + 0.5 * np.sin(7 * t) + (1 / 7) * np.sin(14 * t), x_range=[-4, 4], color=GREEN, ).move_to([0, 1, 0]) self.add(cos_func, sin_func_1, sin_func_2) """ def __init__( self, function: Callable[[float], Any], x_range: tuple[float, float] | tuple[float, float, float] | None = None, color: ParsableManimColor = PURE_YELLOW, **kwargs: Any, ) -> None: if x_range is None: x_range = (-config["frame_x_radius"], config["frame_x_radius"]) self.x_range = x_range self.parametric_function: Callable[[float], Point3D] = lambda t: np.array( [t, function(t), 0] ) self.function = function # type: ignore[assignment] super().__init__(self.parametric_function, self.x_range, color=color, **kwargs) def get_function(self) -> Callable[[float], Any]: return self.function def get_point_from_function(self, x: float) -> Point3D: return self.parametric_function(x) class ImplicitFunction(VMobject, metaclass=ConvertToOpenGL): def __init__( self, func: Callable[[float, float], float], x_range: Sequence[float] | None = None, y_range: Sequence[float] | None = None, min_depth: int = 5, max_quads: int = 1500, use_smoothing: bool = True, **kwargs: Any, ): """An implicit function. Parameters ---------- func The implicit function in the form ``f(x, y) = 0``. x_range The x min and max of the function. y_range The y min and max of the function. min_depth The minimum depth of the function to calculate. max_quads The maximum number of quads to use. use_smoothing Whether or not to smoothen the curves. kwargs Additional parameters to pass into :class:`VMobject` .. note:: A small ``min_depth`` :math:`d` means that some small details might be ignored if they don't cross an edge of one of the :math:`4^d` uniform quads. The value of ``max_quads`` strongly corresponds to the quality of the curve, but a higher number of quads may take longer to render. Examples -------- .. manim:: ImplicitFunctionExample :save_last_frame: class ImplicitFunctionExample(Scene): def construct(self): graph = ImplicitFunction( lambda x, y: x * y ** 2 - x ** 2 * y - 2, color=YELLOW ) self.add(NumberPlane(), graph) """ self.function = func self.min_depth = min_depth self.max_quads = max_quads self.use_smoothing = use_smoothing self.x_range = x_range or [ -config.frame_width / 2, config.frame_width / 2, ] self.y_range = y_range or [ -config.frame_height / 2, config.frame_height / 2, ] super().__init__(**kwargs) def generate_points(self) -> Self: p_min, p_max = ( np.array([self.x_range[0], self.y_range[0]]), np.array([self.x_range[1], self.y_range[1]]), ) curves = plot_isoline( fn=lambda u: self.function(u[0], u[1]), pmin=p_min, pmax=p_max, min_depth=self.min_depth, max_quads=self.max_quads, ) # returns a list of lists of 2D points curves = [ np.pad(curve, [(0, 0), (0, 1)]) for curve in curves if curve != [] ] # add z coord as 0 for curve in curves: self.start_new_path(curve[0]) self.add_points_as_corners(curve[1:]) if self.use_smoothing: self.make_smooth() return self def init_points(self) -> None: self.generate_points() ================================================ FILE: manim/mobject/graphing/number_line.py ================================================ """Mobject representing a number line.""" from __future__ import annotations from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject __all__ = ["NumberLine", "UnitInterval"] from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Any, Self from manim.mobject.geometry.tips import ArrowTip from manim.typing import Point3D, Point3DLike, Vector3D import numpy as np from manim import config from manim.constants import * from manim.mobject.geometry.line import Line from manim.mobject.graphing.scale import LinearBase, _ScaleBase from manim.mobject.text.numbers import DecimalNumber, Integer from manim.mobject.text.tex_mobject import MathTex, Tex from manim.mobject.text.text_mobject import Text from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.bezier import interpolate from manim.utils.config_ops import merge_dicts_recursively from manim.utils.space_ops import normalize class NumberLine(Line): """Creates a number line with tick marks. Parameters ---------- x_range The ``[x_min, x_max, x_step]`` values to create the line. length The length of the number line. unit_size The distance between each tick of the line. Overwritten by :attr:`length`, if specified. include_ticks Whether to include ticks on the number line. tick_size The length of each tick mark. numbers_with_elongated_ticks An iterable of specific values with elongated ticks. longer_tick_multiple Influences how many times larger elongated ticks are than regular ticks (2 = 2x). rotation The angle (in radians) at which the line is rotated. stroke_width The thickness of the line. include_tip Whether to add a tip to the end of the line. tip_width The width of the tip. tip_height The height of the tip. tip_shape The mobject class used to construct the tip, or ``None`` (the default) for the default arrow tip. Passed classes have to inherit from :class:`.ArrowTip`. include_numbers Whether to add numbers to the tick marks. The number of decimal places is determined by the step size, this default can be overridden by ``decimal_number_config``. scaling The way the ``x_range`` is value is scaled, i.e. :class:`~.LogBase` for a logarithmic numberline. Defaults to :class:`~.LinearBase`. font_size The size of the label mobjects. Defaults to 36. label_direction The specific position to which label mobjects are added on the line. label_constructor Determines the mobject class that will be used to construct the labels of the number line. line_to_number_buff The distance between the line and the label mobject. decimal_number_config Arguments that can be passed to :class:`~.numbers.DecimalNumber` to influence number mobjects. numbers_to_exclude An explicit iterable of numbers to not be added to the number line. numbers_to_include An explicit iterable of numbers to add to the number line kwargs Additional arguments to be passed to :class:`~.Line`. .. note:: Number ranges that include both negative and positive values will be generated from the 0 point, and may not include a tick at the min / max values as the tick locations are dependent on the step size. Examples -------- .. manim:: NumberLineExample :save_last_frame: class NumberLineExample(Scene): def construct(self): l0 = NumberLine( x_range=[-10, 10, 2], length=10, color=BLUE, include_numbers=True, label_direction=UP, ) l1 = NumberLine( x_range=[-10, 10, 2], unit_size=0.5, numbers_with_elongated_ticks=[-2, 4], include_numbers=True, font_size=24, ) num6 = l1.numbers[8] num6.set_color(RED) l2 = NumberLine( x_range=[-2.5, 2.5 + 0.5, 0.5], length=12, decimal_number_config={"num_decimal_places": 2}, include_numbers=True, ) l3 = NumberLine( x_range=[-5, 5 + 1, 1], length=6, include_tip=True, include_numbers=True, rotation=10 * DEGREES, ) line_group = VGroup(l0, l1, l2, l3).arrange(DOWN, buff=1) self.add(line_group) """ def __init__( self, x_range: Sequence[float] | None = None, # must be first length: float | None = None, unit_size: float = 1, # ticks include_ticks: bool = True, tick_size: float = 0.1, numbers_with_elongated_ticks: Iterable[float] | None = None, longer_tick_multiple: int = 2, exclude_origin_tick: bool = False, # visuals rotation: float = 0, stroke_width: float = 2.0, # tip include_tip: bool = False, tip_width: float = DEFAULT_ARROW_TIP_LENGTH, tip_height: float = DEFAULT_ARROW_TIP_LENGTH, tip_shape: type[ArrowTip] | None = None, # numbers/labels include_numbers: bool = False, font_size: float = 36, label_direction: Point3DLike = DOWN, label_constructor: type[MathTex] = MathTex, scaling: _ScaleBase = LinearBase(), line_to_number_buff: float = MED_SMALL_BUFF, decimal_number_config: dict | None = None, numbers_to_exclude: Iterable[float] | None = None, numbers_to_include: Iterable[float] | None = None, **kwargs: Any, ): # avoid mutable arguments in defaults if numbers_to_exclude is None: numbers_to_exclude = [] if numbers_with_elongated_ticks is None: numbers_with_elongated_ticks = [] if x_range is None: x_range = [ round(-config["frame_x_radius"]), round(config["frame_x_radius"]), 1, ] elif len(x_range) == 2: # adds x_step if not specified. not sure how to feel about this. a user can't know default without peeking at source code x_range = [*x_range, 1] if decimal_number_config is None: decimal_number_config = { "num_decimal_places": self._decimal_places_from_step(x_range[2]), } # turn into a NumPy array to scale by just applying the function self.x_range = np.array(x_range, dtype=float) self.x_min: float self.x_max: float self.x_step: float self.x_min, self.x_max, self.x_step = scaling.function(self.x_range) self.length = length self.unit_size = unit_size # ticks self.include_ticks = include_ticks self.tick_size = tick_size self.numbers_with_elongated_ticks = numbers_with_elongated_ticks self.longer_tick_multiple = longer_tick_multiple self.exclude_origin_tick = exclude_origin_tick # visuals self.rotation = rotation # tip self.include_tip = include_tip self.tip_width = tip_width self.tip_height = tip_height # numbers self.font_size = font_size self.include_numbers = include_numbers self.label_direction = label_direction self.label_constructor = label_constructor self.line_to_number_buff = line_to_number_buff self.decimal_number_config = decimal_number_config self.numbers_to_exclude = numbers_to_exclude self.numbers_to_include = numbers_to_include self.scaling = scaling super().__init__( self.x_range[0] * RIGHT, self.x_range[1] * RIGHT, stroke_width=stroke_width, **kwargs, ) if self.length: self.set_length(self.length) self.unit_size = self.get_unit_size() else: self.scale(self.unit_size) self.center() if self.include_tip: self.add_tip( tip_length=self.tip_height, tip_width=self.tip_width, tip_shape=tip_shape, ) self.tip.set_stroke(self.stroke_color, self.stroke_width) if self.include_ticks: self.add_ticks() self.rotate(self.rotation) if self.include_numbers or self.numbers_to_include is not None: if self.scaling.custom_labels: tick_range = self.get_tick_range() custom_labels = self.scaling.get_custom_labels( tick_range, unit_decimal_places=decimal_number_config["num_decimal_places"], ) self.add_labels( dict( zip( tick_range, custom_labels, strict=True, ) ), ) else: self.add_numbers( x_values=self.numbers_to_include, excluding=self.numbers_to_exclude, font_size=self.font_size, ) def rotate_about_zero( self, angle: float, axis: Vector3D = OUT, **kwargs: Any ) -> Self: return self.rotate_about_number(0, angle, axis, **kwargs) def rotate_about_number( self, number: float, angle: float, axis: Vector3D = OUT, **kwargs: Any ) -> Self: return self.rotate(angle, axis, about_point=self.n2p(number), **kwargs) def add_ticks(self) -> None: """Adds ticks to the number line. Ticks can be accessed after creation via ``self.ticks``. """ ticks = VGroup() elongated_tick_size = self.tick_size * self.longer_tick_multiple elongated_tick_offsets = ( np.array(self.numbers_with_elongated_ticks) - self.x_min ) for x in self.get_tick_range(): size = self.tick_size if np.any(np.isclose(x - self.x_min, elongated_tick_offsets)): size = elongated_tick_size ticks.add(self.get_tick(x, size)) self.add(ticks) self.ticks = ticks def get_tick(self, x: float, size: float | None = None) -> Line: """Generates a tick and positions it along the number line. Parameters ---------- x The position of the tick. size The factor by which the tick is scaled. Returns ------- :class:`~.Line` A positioned tick. """ if size is None: size = self.tick_size result = Line(size * DOWN, size * UP) result.rotate(self.get_angle()) result.move_to(self.number_to_point(x)) result.match_style(self) return result def get_tick_marks(self) -> VGroup: return self.ticks def get_tick_range(self) -> np.ndarray: """Generates the range of values on which labels are plotted based on the ``x_range`` attribute of the number line. Returns ------- np.ndarray A numpy array of floats represnting values along the number line. """ x_min, x_max, x_step = self.x_range if not self.include_tip: x_max += 1e-6 # Handle cases where min and max are both positive or both negative if x_min < x_max < 0 or x_max > x_min > 0: tick_range = np.arange(x_min, x_max, x_step) else: start_point = 0 if self.exclude_origin_tick: start_point += x_step x_min_segment = np.arange(start_point, np.abs(x_min) + 1e-6, x_step) * -1 x_max_segment = np.arange(start_point, x_max, x_step) tick_range = np.unique(np.concatenate((x_min_segment, x_max_segment))) return self.scaling.function(tick_range) def number_to_point(self, number: float | np.ndarray) -> np.ndarray: """Accepts a value along the number line and returns a point with respect to the scene. Equivalent to `NumberLine @ number` Parameters ---------- number The value to be transformed into a coordinate. Or a list of values. Returns ------- np.ndarray A point with respect to the scene's coordinate system. Or a list of points. Examples -------- >>> from manim import NumberLine >>> number_line = NumberLine() >>> number_line.number_to_point(0) array([0., 0., 0.]) >>> number_line.number_to_point(1) array([1., 0., 0.]) >>> number_line @ 1 array([1., 0., 0.]) >>> number_line.number_to_point([1, 2, 3]) array([[1., 0., 0.], [2., 0., 0.], [3., 0., 0.]]) """ number = np.asarray(number) scalar = number.ndim == 0 number = self.scaling.inverse_function(number) alphas = (number - self.x_range[0]) / (self.x_range[1] - self.x_range[0]) alphas = float(alphas) if scalar else np.vstack(alphas) val = interpolate(self.get_start(), self.get_end(), alphas) return val def point_to_number(self, point: Sequence[float]) -> float: """Accepts a point with respect to the scene and returns a float along the number line. Parameters ---------- point A sequence of values consisting of ``(x_coord, y_coord, z_coord)``. Returns ------- float A float representing a value along the number line. Examples -------- >>> from manim import NumberLine >>> number_line = NumberLine() >>> number_line.point_to_number((0, 0, 0)) np.float64(0.0) >>> number_line.point_to_number((1, 0, 0)) np.float64(1.0) >>> number_line.point_to_number([[0.5, 0, 0], [1, 0, 0], [1.5, 0, 0]]) array([0.5, 1. , 1.5]) """ point = np.asarray(point) start, end = self.get_start_and_end() unit_vect = normalize(end - start) proportion: float = np.dot(point - start, unit_vect) / np.dot( end - start, unit_vect ) return interpolate(self.x_min, self.x_max, proportion) def n2p(self, number: float | np.ndarray) -> Point3D: """Abbreviation for :meth:`~.NumberLine.number_to_point`.""" return self.number_to_point(number) def p2n(self, point: Point3DLike) -> float: """Abbreviation for :meth:`~.NumberLine.point_to_number`.""" return self.point_to_number(point) def get_unit_size(self) -> float: val: float = self.get_length() / (self.x_range[1] - self.x_range[0]) return val def get_unit_vector(self) -> Vector3D: return super().get_unit_vector() * self.unit_size def get_number_mobject( self, x: float, direction: Vector3D | None = None, buff: float | None = None, font_size: float | None = None, label_constructor: type[MathTex] | None = None, **number_config: dict[str, Any], ) -> VMobject: """Generates a positioned :class:`~.DecimalNumber` mobject generated according to ``label_constructor``. Parameters ---------- x The x-value at which the mobject should be positioned. direction Determines the direction at which the label is positioned next to the line. buff The distance of the label from the line. font_size The font size of the label mobject. label_constructor The :class:`~.VMobject` class that will be used to construct the label. Defaults to the ``label_constructor`` attribute of the number line if not specified. Returns ------- :class:`~.DecimalNumber` The positioned mobject. """ number_config_merged = merge_dicts_recursively( self.decimal_number_config, number_config, ) if direction is None: direction = self.label_direction if buff is None: buff = self.line_to_number_buff if font_size is None: font_size = self.font_size if label_constructor is None: label_constructor = self.label_constructor num_mob = DecimalNumber( x, font_size=font_size, mob_class=label_constructor, **number_config_merged, ) num_mob.next_to(self.number_to_point(x), direction=direction, buff=buff) if x < 0 and self.label_direction[0] == 0: # Align without the minus sign num_mob.shift(num_mob[0].width * LEFT / 2) return num_mob def get_number_mobjects(self, *numbers: float, **kwargs: Any) -> VGroup: if len(numbers) == 0: numbers = self.default_numbers_to_display() return VGroup([self.get_number_mobject(number, **kwargs) for number in numbers]) def get_labels(self) -> VGroup: return self.get_number_mobjects() def add_numbers( self, x_values: Iterable[float] | None = None, excluding: Iterable[float] | None = None, font_size: float | None = None, label_constructor: type[MathTex] | None = None, **kwargs: Any, ) -> Self: """Adds :class:`~.DecimalNumber` mobjects representing their position at each tick of the number line. The numbers can be accessed after creation via ``self.numbers``. Parameters ---------- x_values An iterable of the values used to position and create the labels. Defaults to the output produced by :meth:`~.NumberLine.get_tick_range` excluding A list of values to exclude from :attr:`x_values`. font_size The font size of the labels. Defaults to the ``font_size`` attribute of the number line. label_constructor The :class:`~.VMobject` class that will be used to construct the label. Defaults to the ``label_constructor`` attribute of the number line if not specified. """ if x_values is None: x_values = self.get_tick_range() if excluding is None: excluding = self.numbers_to_exclude if font_size is None: font_size = self.font_size if label_constructor is None: label_constructor = self.label_constructor numbers = VGroup() for x in x_values: if x in excluding: continue numbers.add( self.get_number_mobject( x, font_size=font_size, label_constructor=label_constructor, **kwargs, ) ) self.add(numbers) self.numbers = numbers return self def add_labels( self, dict_values: dict[float, str | float | VMobject], direction: Point3DLike | None = None, buff: float | None = None, font_size: float | None = None, label_constructor: type[MathTex] | None = None, ) -> Self: """Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``. The labels can be accessed after creation via ``self.labels``. Parameters ---------- dict_values A dictionary consisting of the position along the number line and the mobject to be added: ``{1: Tex("Monday"), 3: Tex("Tuesday")}``. :attr:`label_constructor` will be used to construct the labels if the value is not a mobject (``str`` or ``float``). direction Determines the direction at which the label is positioned next to the line. buff The distance of the label from the line. font_size The font size of the mobject to be positioned. label_constructor The :class:`~.VMobject` class that will be used to construct the label. Defaults to the ``label_constructor`` attribute of the number line if not specified. Raises ------ 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 if label_constructor is None: label_constructor = self.label_constructor labels = VGroup() for x, label in dict_values.items(): # TODO: remove this check and ability to call # this method via CoordinateSystem.add_coordinates() # must be explicitly called if isinstance(label, str) and label_constructor is MathTex: label = Tex(label) else: label = self._create_label_tex(label, label_constructor) if hasattr(label, "font_size"): assert isinstance(label, (MathTex, Tex, Text, Integer)), label label.font_size = font_size else: raise AttributeError(f"{label} is not compatible with add_labels.") label.next_to(self.number_to_point(x), direction=direction, buff=buff) labels.add(label) self.labels = labels self.add(labels) return self def _create_label_tex( self, label_tex: str | float | VMobject, label_constructor: Callable | None = None, **kwargs: Any, ) -> VMobject: """Checks if the label is a :class:`~.VMobject`, otherwise, creates a label by passing ``label_tex`` to ``label_constructor``. Parameters ---------- label_tex The label for which a mobject should be created. If the label already is a mobject, no new mobject is created. label_constructor Optional. A class or function returning a mobject when passing ``label_tex`` as an argument. If ``None`` is passed (the default), the label constructor from the :attr:`.label_constructor` attribute is used. Returns ------- :class:`~.VMobject` The label. """ if isinstance(label_tex, (VMobject, OpenGLVMobject)): return label_tex if label_constructor is None: label_constructor = self.label_constructor if isinstance(label_tex, str): return label_constructor(label_tex, **kwargs) return label_constructor(str(label_tex), **kwargs) @staticmethod def _decimal_places_from_step(step: float) -> int: step_str = str(step) if "." not in step_str: return 0 return len(step_str.split(".")[-1]) def __matmul__(self, other: float) -> Point3D: return self.n2p(other) def __rmatmul__(self, other: Point3DLike | Mobject) -> float: if isinstance(other, Mobject): other = other.get_center() return self.p2n(other) class UnitInterval(NumberLine): def __init__( self, unit_size: float = 10, numbers_with_elongated_ticks: list[float] | None = None, decimal_number_config: dict[str, Any] | None = None, **kwargs: Any, ): numbers_with_elongated_ticks = ( [0, 1] if numbers_with_elongated_ticks is None else numbers_with_elongated_ticks ) decimal_number_config = ( { "num_decimal_places": 1, } if decimal_number_config is None else decimal_number_config ) super().__init__( x_range=(0, 1, 0.1), unit_size=unit_size, numbers_with_elongated_ticks=numbers_with_elongated_ticks, decimal_number_config=decimal_number_config, **kwargs, ) ================================================ FILE: manim/mobject/graphing/probability.py ================================================ """Mobjects representing objects from probability theory and statistics.""" from __future__ import annotations __all__ = ["SampleSpace", "BarChart"] from collections.abc import Iterable, MutableSequence, Sequence from typing import Any import numpy as np from manim import config, logger from manim.constants import * from manim.mobject.geometry.polygram import Rectangle from manim.mobject.graphing.coordinate_systems import Axes from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.mobject.svg.brace import Brace from manim.mobject.text.tex_mobject import MathTex, Tex from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.typing import Vector3D from manim.utils.color import ( BLUE_E, DARK_GREY, GREEN_E, LIGHT_GREY, MAROON_B, YELLOW, ParsableManimColor, color_gradient, ) from manim.utils.iterables import tuplify EPSILON = 0.0001 class SampleSpace(Rectangle): """A mobject representing a twodimensional rectangular sampling space. Examples -------- .. manim:: ExampleSampleSpace :save_last_frame: class ExampleSampleSpace(Scene): def construct(self): poly1 = SampleSpace(stroke_width=15, fill_opacity=1) poly2 = SampleSpace(width=5, height=3, stroke_width=5, fill_opacity=0.5) poly3 = SampleSpace(width=2, height=2, stroke_width=5, fill_opacity=0.1) poly3.divide_vertically(p_list=np.array([0.37, 0.13, 0.5]), colors=[BLACK, WHITE, GRAY], vect=RIGHT) poly_group = VGroup(poly1, poly2, poly3).arrange() self.add(poly_group) """ def __init__( self, height: float = 3, width: float = 3, fill_color: ParsableManimColor = DARK_GREY, fill_opacity: float = 1, stroke_width: float = 0.5, stroke_color: ParsableManimColor = LIGHT_GREY, default_label_scale_val: float = 1, ): super().__init__( height=height, width=width, fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, stroke_color=stroke_color, ) self.default_label_scale_val = default_label_scale_val def add_title( self, title: str = "Sample space", buff: float = MED_SMALL_BUFF ) -> None: # TODO, should this really exist in SampleSpaceScene title_mob = Tex(title) if title_mob.width > self.width: title_mob.width = self.width title_mob.next_to(self, UP, buff=buff) self.title = title_mob self.add(title_mob) def add_label(self, label: str) -> None: self.label = label def complete_p_list(self, p_list: float | Iterable[float]) -> list[float]: p_list_tuplified: tuple[float] = tuplify(p_list) new_p_list = list(p_list_tuplified) remainder = 1.0 - sum(new_p_list) if abs(remainder) > EPSILON: new_p_list.append(remainder) return new_p_list def get_division_along_dimension( self, p_list: float | Iterable[float], dim: int, colors: Sequence[ParsableManimColor], vect: Vector3D, ) -> VGroup: p_list_complete = self.complete_p_list(p_list) colors_in_gradient = color_gradient(colors, len(p_list_complete)) last_point = self.get_edge_center(-vect) parts = VGroup() for factor, color in zip(p_list_complete, colors_in_gradient, strict=True): part = SampleSpace() part.set_fill(color, 1) part.replace(self, stretch=True) part.stretch(factor, dim) part.move_to(last_point, -vect) last_point = part.get_edge_center(vect) parts.add(part) return parts def get_horizontal_division( self, p_list: float | Iterable[float], colors: Sequence[ParsableManimColor] = [GREEN_E, BLUE_E], vect: Vector3D = DOWN, ) -> VGroup: return self.get_division_along_dimension(p_list, 1, colors, vect) def get_vertical_division( self, p_list: float | Iterable[float], colors: Sequence[ParsableManimColor] = [MAROON_B, YELLOW], vect: Vector3D = RIGHT, ) -> VGroup: return self.get_division_along_dimension(p_list, 0, colors, vect) def divide_horizontally(self, *args: Any, **kwargs: Any) -> None: self.horizontal_parts = self.get_horizontal_division(*args, **kwargs) self.add(self.horizontal_parts) def divide_vertically(self, *args: Any, **kwargs: Any) -> None: self.vertical_parts = self.get_vertical_division(*args, **kwargs) self.add(self.vertical_parts) def get_subdivision_braces_and_labels( self, parts: VGroup, labels: list[str | VMobject | OpenGLVMobject], direction: Vector3D, buff: float = SMALL_BUFF, min_num_quads: int = 1, ) -> VGroup: label_mobs = VGroup() braces = VGroup() for label, part in zip(labels, parts, strict=False): brace = Brace(part, direction, min_num_quads=min_num_quads, buff=buff) if isinstance(label, (VMobject, OpenGLVMobject)): label_mob = label else: label_mob = MathTex(label) label_mob.scale(self.default_label_scale_val) label_mob.next_to(brace, direction, buff) braces.add(brace) assert isinstance(label_mob, VMobject) label_mobs.add(label_mob) parts.braces = braces # type: ignore[attr-defined] parts.labels = label_mobs # type: ignore[attr-defined] parts.label_kwargs = { # type: ignore[attr-defined] "labels": label_mobs.copy(), "direction": direction, "buff": buff, } return VGroup(parts.braces, parts.labels) def get_side_braces_and_labels( self, labels: list[str | VMobject | OpenGLVMobject], direction: Vector3D = LEFT, **kwargs: Any, ) -> VGroup: assert hasattr(self, "horizontal_parts") parts = self.horizontal_parts return self.get_subdivision_braces_and_labels( parts, labels, direction, **kwargs ) def get_top_braces_and_labels( self, labels: list[str | VMobject | OpenGLVMobject], **kwargs: Any ) -> VGroup: assert hasattr(self, "vertical_parts") parts = self.vertical_parts return self.get_subdivision_braces_and_labels(parts, labels, UP, **kwargs) def get_bottom_braces_and_labels( self, labels: list[str | VMobject | OpenGLVMobject], **kwargs: Any ) -> VGroup: assert hasattr(self, "vertical_parts") parts = self.vertical_parts return self.get_subdivision_braces_and_labels(parts, labels, DOWN, **kwargs) def add_braces_and_labels(self) -> None: for attr in "horizontal_parts", "vertical_parts": if not hasattr(self, attr): continue parts = getattr(self, attr) for subattr in "braces", "labels": if hasattr(parts, subattr): self.add(getattr(parts, subattr)) def __getitem__(self, index: int) -> VMobject: if hasattr(self, "horizontal_parts"): return self.horizontal_parts[index] elif hasattr(self, "vertical_parts"): return self.vertical_parts[index] return self.split()[index] class BarChart(Axes): """Creates a bar chart. Inherits from :class:`~.Axes`, so it shares its methods and attributes. Each axis inherits from :class:`~.NumberLine`, so pass in ``x_axis_config``/``y_axis_config`` to control their attributes. Parameters ---------- values A sequence of values that determines the height of each bar. Accepts negative values. bar_names A sequence of names for each bar. Does not have to match the length of ``values``. y_range The y_axis range of values. If ``None``, the range will be calculated based on the min/max of ``values`` and the step will be calculated based on ``y_length``. x_length The length of the x-axis. If ``None``, it is automatically calculated based on the number of values and the width of the screen. y_length The length of the y-axis. bar_colors The color for the bars. Accepts a sequence of colors (can contain just one item). If the length of``bar_colors`` does not match that of ``values``, intermediate colors will be automatically determined. bar_width The length of a bar. Must be between 0 and 1. bar_fill_opacity The fill opacity of the bars. bar_stroke_width The stroke width of the bars. Examples -------- .. manim:: BarChartExample :save_last_frame: class BarChartExample(Scene): def construct(self): chart = BarChart( values=[-5, 40, -10, 20, -3], bar_names=["one", "two", "three", "four", "five"], y_range=[-20, 50, 10], y_length=6, x_length=10, x_axis_config={"font_size": 36}, ) c_bar_lbls = chart.get_bar_labels(font_size=48) self.add(chart, c_bar_lbls) """ def __init__( self, values: MutableSequence[float], bar_names: Sequence[str] | None = None, y_range: Sequence[float] | None = None, x_length: float | None = None, y_length: float | None = None, bar_colors: Iterable[str] = [ "#003f5c", "#58508d", "#bc5090", "#ff6361", "#ffa600", ], bar_width: float = 0.6, bar_fill_opacity: float = 0.7, bar_stroke_width: float = 3, **kwargs: Any, ): if isinstance(bar_colors, str): logger.warning( "Passing a string to `bar_colors` has been deprecated since v0.15.2 and will be removed after v0.17.0, the parameter must be a list. " ) bar_colors = list(bar_colors) y_length = y_length if y_length is not None else config.frame_height - 4 self.values = values self.bar_names = bar_names self.bar_colors = bar_colors self.bar_width = bar_width self.bar_fill_opacity = bar_fill_opacity self.bar_stroke_width = bar_stroke_width x_range = [0, len(self.values), 1] if y_range is None: y_range = [ min(0, min(self.values)), max(0, max(self.values)), round(max(self.values) / y_length, 2), ] elif len(y_range) == 2: y_range = [*y_range, round(max(self.values) / y_length, 2)] if x_length is None: x_length = min(len(self.values), config.frame_width - 2) x_axis_config = {"font_size": 24, "label_constructor": Tex} self._update_default_configs( (x_axis_config,), (kwargs.pop("x_axis_config", None),) ) self.bars: VGroup = VGroup() self.x_labels: VGroup | None = None self.bar_labels: VGroup | None = None super().__init__( x_range=x_range, y_range=y_range, x_length=x_length, y_length=y_length, x_axis_config=x_axis_config, tips=kwargs.pop("tips", False), **kwargs, ) self._add_bars() if self.bar_names is not None: self._add_x_axis_labels() self.y_axis.add_numbers() def _update_colors(self) -> None: """Initialize the colors of the bars of the chart. Sets the color of ``self.bars`` via ``self.bar_colors``. 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) -> None: """Essentially :meth`:~.NumberLine.add_labels`, but differs in that the direction of the label with respect to the x_axis changes to UP or DOWN depending on the value. UP for negative values and DOWN for positive values. """ assert isinstance(self.bar_names, list) val_range = np.arange( 0.5, len(self.bar_names), 1 ) # 0.5 shifted so that labels are centered, not on ticks labels = VGroup() for i, (value, bar_name) in enumerate( zip(val_range, self.bar_names, strict=True) ): # to accommodate negative bars, the label may need to be # below or above the x_axis depending on the value of the bar direction = UP if self.values[i] < 0 else DOWN bar_name_label: MathTex = self.x_axis.label_constructor(bar_name) bar_name_label.font_size = self.x_axis.font_size bar_name_label.next_to( self.x_axis.number_to_point(value), direction=direction, buff=self.x_axis.line_to_number_buff, ) labels.add(bar_name_label) self.x_axis.labels = labels self.x_axis.add(labels) def _create_bar(self, bar_number: int, value: float) -> Rectangle: """Creates a positioned bar on the chart. Parameters ---------- bar_number Determines the x-position of the bar. value The value that determines the height of the bar. Returns ------- 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 bar_h = abs(self.c2p(0, value)[1] - self.c2p(0, 0)[1]) # width of the bar bar_w = self.c2p(self.bar_width, 0)[0] - self.c2p(0, 0)[0] bar = Rectangle( height=bar_h, width=bar_w, stroke_width=self.bar_stroke_width, fill_opacity=self.bar_fill_opacity, ) pos = UP if (value >= 0) else DOWN bar.next_to(self.c2p(bar_number + 0.5, 0), pos, buff=0) return bar def _add_bars(self) -> None: for i, value in enumerate(self.values): tmp_bar = self._create_bar(bar_number=i, value=value) self.bars.add(tmp_bar) self._update_colors() self.add_to_back(self.bars) def get_bar_labels( self, color: ParsableManimColor | None = None, font_size: float = 24, buff: float = MED_SMALL_BUFF, label_constructor: type[MathTex] = Tex, ) -> VGroup: """Annotates each bar with its corresponding value. Use ``self.bar_labels`` to access the labels after creation. Parameters ---------- color The color of each label. By default ``None`` and is based on the parent's bar color. font_size The font size of each label. buff The distance from each label to its bar. By default 0.4. label_constructor The Mobject class to construct the labels, by default :class:`~.Tex`. Examples -------- .. manim:: GetBarLabelsExample :save_last_frame: class GetBarLabelsExample(Scene): def construct(self): chart = BarChart(values=[10, 9, 8, 7, 6, 5, 4, 3, 2, 1], y_range=[0, 10, 1]) c_bar_lbls = chart.get_bar_labels( color=WHITE, label_constructor=MathTex, font_size=36 ) self.add(chart, c_bar_lbls) """ bar_labels = VGroup() for bar, value in zip(self.bars, self.values, strict=False): bar_lbl: MathTex = label_constructor(str(value)) if color is None: bar_lbl.set_color(bar.get_fill_color()) else: bar_lbl.set_color(color) bar_lbl.font_size = font_size pos = UP if (value >= 0) else DOWN bar_lbl.next_to(bar, pos, buff=buff) bar_labels.add(bar_lbl) return bar_labels def change_bar_values( self, values: Iterable[float], update_colors: bool = True ) -> None: """Updates the height of the bars of the chart. Parameters ---------- values The values that will be used to update the height of the bars. Does not have to match the number of bars. update_colors Whether to re-initalize the colors of the bars based on ``self.bar_colors``. Examples -------- .. manim:: ChangeBarValuesExample :save_last_frame: class ChangeBarValuesExample(Scene): def construct(self): values=[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10] chart = BarChart( values, y_range=[-10, 10, 2], y_axis_config={"font_size": 24}, ) self.add(chart) 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, strict=False)): chart_val = self.values[i] if chart_val > 0: bar_lim = bar.get_bottom() aligned_edge = DOWN else: bar_lim = bar.get_top() aligned_edge = UP # check if the bar has height if chart_val != 0: quotient = value / chart_val if quotient < 0: aligned_edge = UP if chart_val > 0 else DOWN # if the bar is already positive, then we now want to move it # so that it is negative. So, we move the top edge of the bar # to the location of the previous bottom # if already negative, then we move the bottom edge of the bar # to the location of the previous top bar.stretch_to_fit_height(abs(quotient) * bar.height) else: # create a new bar since the current one has a height of zero (doesn't exist) temp_bar = self._create_bar(i, value) self.bars.remove(bar) self.bars.insert(i, temp_bar) bar.move_to(bar_lim, aligned_edge) if update_colors: self._update_colors() self.values[: len(list(values))] = values ================================================ FILE: manim/mobject/graphing/scale.py ================================================ from __future__ import annotations import math from collections.abc import Iterable from typing import TYPE_CHECKING, Any, overload import numpy as np __all__ = ["LogBase", "LinearBase"] from manim.mobject.text.numbers import Integer if TYPE_CHECKING: from collections.abc import Callable from manim.mobject.types.vectorized_mobject import VMobject class _ScaleBase: """Scale baseclass for graphing/functions. Parameters ---------- custom_labels Whether to create custom labels when plotted on a :class:`~.NumberLine`. """ def __init__(self, custom_labels: bool = False): self.custom_labels = custom_labels @overload def function(self, value: float) -> float: ... @overload def function(self, value: np.ndarray) -> np.ndarray: ... def function(self, value: float) -> float: """The function that will be used to scale the values. Parameters ---------- value The number/``np.ndarray`` to be scaled. Returns ------- float The value after it has undergone the scaling. Raises ------ NotImplementedError Must be subclassed. """ raise NotImplementedError def inverse_function(self, value: float) -> float: """The inverse of ``function``. Used for plotting on a particular axis. Raises ------ NotImplementedError Must be subclassed. """ raise NotImplementedError def get_custom_labels( self, val_range: Iterable[float], **kw_args: Any, ) -> Iterable[VMobject]: """Custom instructions for generating labels along an axis. Parameters ---------- val_range The position of labels. Also used for defining the content of the labels. Returns ------- Dict A list consisting of the labels. Can be passed to :meth:`~.NumberLine.add_labels() along with ``val_range``. Raises ------ NotImplementedError Can be subclassed, optional. """ raise NotImplementedError class LinearBase(_ScaleBase): def __init__(self, scale_factor: float = 1.0): """The default scaling class. Parameters ---------- scale_factor The slope of the linear function, by default 1.0 """ super().__init__() self.scale_factor = scale_factor def function(self, value: float) -> float: """Multiplies the value by the scale factor. Parameters ---------- value Value to be multiplied by the scale factor. """ return self.scale_factor * value def inverse_function(self, value: float) -> float: """Inverse of function. Divides the value by the scale factor. Parameters ---------- value value to be divided by the scale factor. """ return value / self.scale_factor class LogBase(_ScaleBase): def __init__(self, base: float = 10, custom_labels: bool = True): """Scale for logarithmic graphs/functions. Parameters ---------- base The base of the log, by default 10. custom_labels For use with :class:`~.Axes`: Whether or not to include ``LaTeX`` axis labels, by default True. Examples -------- .. code-block:: python func = ParametricFunction(lambda x: x, scaling=LogBase(base=2)) """ super().__init__() self.base = base self.custom_labels = custom_labels def function(self, value: float) -> float: """Scales the value to fit it to a logarithmic scale.``self.function(5)==10**5``""" return_value: float = self.base**value return return_value def inverse_function(self, value: float) -> float: """Inverse of ``function``. The value must be greater than 0""" if isinstance(value, np.ndarray): condition = value.any() <= 0 func: Callable[[float, float], float] def func(value: float, base: float) -> float: return_value: float = np.log(value) / np.log(base) return return_value else: condition = value <= 0 func = math.log if condition: raise ValueError( "log(0) is undefined. Make sure the value is in the domain of the function" ) value = func(value, self.base) return value def get_custom_labels( self, val_range: Iterable[float], unit_decimal_places: int = 0, **base_config: Any, ) -> list[Integer]: """Produces custom :class:`~.Integer` labels in the form of ``10^2``. Parameters ---------- val_range The iterable of values used to create the labels. Determines the exponent. unit_decimal_places The number of decimal places to include in the exponent base_config Additional arguments to be passed to :class:`~.Integer`. """ # uses `format` syntax to control the number of decimal places. tex_labels: list[Integer] = [ Integer( self.base, unit="^{%s}" % (f"{self.inverse_function(i):.{unit_decimal_places}f}"), # noqa: UP031 **base_config, ) for i in val_range ] return tex_labels ================================================ FILE: manim/mobject/logo.py ================================================ """Utilities for Manim's logo and banner.""" from __future__ import annotations __all__ = ["ManimBanner"] from typing import Any import svgelements as se from manim.animation.updaters.update import UpdateFromAlphaFunc from manim.mobject.geometry.arc import Circle from manim.mobject.geometry.polygram import Square, Triangle from manim.mobject.mobject import Mobject from manim.typing import Vector3D from .. import constants as cst from ..animation.animation import override_animation from ..animation.composition import AnimationGroup, Succession from ..animation.creation import Create, SpiralIn from ..animation.fading import FadeIn from ..mobject.svg.svg_mobject import VMobjectFromSVGPath from ..mobject.types.vectorized_mobject import VGroup from ..utils.rate_functions import ease_in_out_cubic, smooth MANIM_SVG_PATHS: list[se.Path] = [ se.Path( # double stroke letter M "M4.64259-2.092154L2.739726-6.625156C2.660025-6.824408 2.650062-6.824408 " "2.381071-6.824408H.52802C.348692-6.824408 .199253-6.824408 .199253-6.645" "081C.199253-6.475716 .37858-6.475716 .428394-6.475716C.547945-6.475716 ." "816936-6.455791 1.036115-6.37609V-1.05604C1.036115-.846824 1.036115-.408" "468 .358655-.348692C.169365-.328767 .169365-.18929 .169365-.179328C.1693" "65 0 .328767 0 .508095 0H2.052304C2.231631 0 2.381071 0 2.381071-.179328" "C2.381071-.268991 2.30137-.33873 2.221669-.348692C1.454545-.408468 1.454" "545-.826899 1.454545-1.05604V-6.017435L1.464508-6.027397L3.895392-.20921" "5C3.975093-.029888 4.044832 0 4.104608 0C4.224159 0 4.254047-.079701 4.3" "03861-.199253L6.744707-6.027397L6.75467-6.017435V-1.05604C6.75467-.84682" "4 6.75467-.408468 6.07721-.348692C5.88792-.328767 5.88792-.18929 5.88792" "-.179328C5.88792 0 6.047323 0 6.22665 0H8.886675C9.066002 0 9.215442 0 9" ".215442-.179328C9.215442-.268991 9.135741-.33873 9.05604-.348692C8.28891" "7-.408468 8.288917-.826899 8.288917-1.05604V-5.768369C8.288917-5.977584 " "8.288917-6.41594 8.966376-6.475716C9.066002-6.485679 9.155666-6.535492 9" ".155666-6.645081C9.155666-6.824408 9.006227-6.824408 8.826899-6.824408H6" ".90411C6.645081-6.824408 6.625156-6.824408 6.535492-6.615193L4.64259-2.0" "92154ZM4.343711-1.912827C4.423412-1.743462 4.433375-1.733499 4.552927-1." "693649L4.11457-.637609H4.094645L1.823163-6.057285C1.77335-6.1868 1.69364" "9-6.356164 1.554172-6.475716H2.420922L4.343711-1.912827ZM1.334994-.34869" "2H1.165629C1.185554-.37858 1.205479-.408468 1.225405-.428394C1.235367-.4" "38356 1.235367-.448319 1.24533-.458281L1.334994-.348692ZM7.103362-6.4757" "16H8.159402C7.940224-6.22665 7.940224-5.967621 7.940224-5.788294V-1.0361" "15C7.940224-.856787 7.940224-.597758 8.169365-.348692H6.884184C7.103362-" ".597758 7.103362-.856787 7.103362-1.036115V-6.475716Z" ), se.Path( # letter a "M1.464508-4.024907C1.464508-4.234122 1.743462-4.393524 2.092154-4.393524" "C2.669988-4.393524 2.929016-4.124533 2.929016-3.516812V-2.789539C1.77335" "-2.440847 .249066-2.042341 .249066-.916563C.249066-.308842 .71731 .13947" "7 1.354919 .139477C1.92279 .139477 2.381071-.059776 2.929016-.557908C3.0" "38605-.049813 3.257783 .139477 3.745953 .139477C4.174346 .139477 4.48318" "8-.019925 4.861768-.428394L4.712329-.637609L4.612702-.537983C4.582814-.5" "08095 4.552927-.498132 4.503113-.498132C4.363636-.498132 4.293898-.58779" "6 4.293898-.747198V-3.347447C4.293898-4.184309 3.536737-4.712329 2.32129" "5-4.712329C1.195517-4.712329 .438356-4.204234 .438356-3.457036C.438356-3" ".048568 .67746-2.799502 1.085928-2.799502C1.484433-2.799502 1.763387-3.0" "38605 1.763387-3.377335C1.763387-3.676214 1.464508-3.88543 1.464508-4.02" "4907ZM2.919054-.996264C2.650062-.687422 2.450809-.56787 2.211706-.56787C" "1.912827-.56787 1.703611-.836862 1.703611-1.235367C1.703611-1.8132 2.122" "042-2.231631 2.919054-2.440847V-.996264Z" ), se.Path( # letter n "M2.948941-4.044832C3.297634-4.044832 3.466999-3.775841 3.466999-3.217933" "V-.806974C3.466999-.438356 3.337484-.278954 2.998755-.239103V0H5.339975V" "-.239103C4.951432-.268991 4.851806-.388543 4.851806-.806974V-3.307597C4." "851806-4.164384 4.323786-4.712329 3.506849-4.712329C2.909091-4.712329 2." "450809-4.433375 2.082192-3.845579V-4.592777H.179328V-4.353674C.617684-4." "283935 .707347-4.184309 .707347-3.765878V-.836862C.707347-.418431 .62764" "6-.328767 .179328-.239103V0H2.580324V-.239103C2.211706-.288917 2.092154-" ".438356 2.092154-.806974V-3.466999C2.092154-3.576588 2.530511-4.044832 2" ".948941-4.044832Z" ), se.Path( # letter i "M2.15193-4.592777H.239103V-4.353674C.67746-4.26401 .767123-4.174346 .767" "123-3.765878V-.836862C.767123-.428394 .697385-.348692 .239103-.239103V0H" "2.6401V-.239103C2.291407-.288917 2.15193-.428394 2.15193-.806974V-4.5927" "77ZM1.454545-6.884184C1.026152-6.884184 .67746-6.535492 .67746-6.117061C" ".67746-5.668742 1.006227-5.339975 1.444583-5.339975S2.221669-5.668742 2." "221669-6.107098C2.221669-6.535492 1.882939-6.884184 1.454545-6.884184Z" ), se.Path( # letter m "M2.929016-4.044832C3.317559-4.044832 3.466999-3.815691 3.466999-3.217933" "V-.806974C3.466999-.398506 3.35741-.268991 2.988792-.239103V0H5.32005V-." "239103C4.971357-.278954 4.851806-.428394 4.851806-.806974V-3.466999C4.85" "1806-3.576588 5.310087-4.044832 5.69863-4.044832C6.07721-4.044832 6.2266" "5-3.805729 6.22665-3.217933V-.806974C6.22665-.388543 6.117061-.268991 5." "738481-.239103V0H8.109589V-.239103C7.721046-.259029 7.611457-.37858 7.61" "1457-.806974V-3.307597C7.611457-4.164384 7.083437-4.712329 6.266501-4.71" "2329C5.69863-4.712329 5.32005-4.483188 4.801993-3.845579C4.503113-4.4732" "25 4.154421-4.712329 3.526775-4.712329S2.440847-4.443337 2.062267-3.8455" "79V-4.592777H.179328V-4.353674C.617684-4.293898 .707347-4.174346 .707347" "-3.765878V-.836862C.707347-.428394 .617684-.318804 .179328-.239103V0H2.5" "50436V-.239103C2.201743-.288917 2.092154-.428394 2.092154-.806974V-3.466" "999C2.092154-3.58655 2.530511-4.044832 2.929016-4.044832Z" ), ] class ManimBanner(VGroup): r"""Convenience class representing Manim's banner. Can be animated using custom methods. Parameters ---------- dark_theme If ``True`` (the default), the dark theme version of the logo (with light text font) will be rendered. Otherwise, if ``False``, the light theme version (with dark text font) is used. Examples -------- .. manim:: DarkThemeBanner class DarkThemeBanner(Scene): def construct(self): banner = ManimBanner() self.play(banner.create()) self.play(banner.expand()) self.wait() self.play(Unwrite(banner)) .. manim:: LightThemeBanner class LightThemeBanner(Scene): def construct(self): self.camera.background_color = "#ece6e2" banner = ManimBanner(dark_theme=False) self.play(banner.create()) self.play(banner.expand()) self.wait() self.play(Unwrite(banner)) """ def __init__(self, dark_theme: bool = True): super().__init__() logo_green = "#81b29a" logo_blue = "#454866" logo_red = "#e07a5f" m_height_over_anim_height = 0.75748 self.font_color = "#ece6e2" if dark_theme else "#343434" self.scale_factor = 1.0 self.M = VMobjectFromSVGPath(MANIM_SVG_PATHS[0]).flip(cst.RIGHT).center() self.M.set(stroke_width=0).scale( 7 * cst.DEFAULT_FONT_SIZE * cst.SCALE_FACTOR_PER_FONT_POINT ) self.M.set_fill(color=self.font_color, opacity=1).shift( 2.25 * cst.LEFT + 1.5 * cst.UP ) self.circle = Circle(color=logo_green, fill_opacity=1).shift(cst.LEFT) self.square = Square(color=logo_blue, fill_opacity=1).shift(cst.UP) self.triangle = Triangle(color=logo_red, fill_opacity=1).shift(cst.RIGHT) self.shapes = VGroup(self.triangle, self.square, self.circle) self.add(self.shapes, self.M) self.move_to(cst.ORIGIN) anim = VGroup() for ind, path in enumerate(MANIM_SVG_PATHS[1:]): tex = VMobjectFromSVGPath(path).flip(cst.RIGHT).center() tex.set(stroke_width=0).scale( cst.DEFAULT_FONT_SIZE * cst.SCALE_FACTOR_PER_FONT_POINT ) if ind > 0: tex.next_to(anim, buff=0.01) tex.align_to(self.M, cst.DOWN) anim.add(tex) anim.set_fill(color=self.font_color, opacity=1) anim.height = m_height_over_anim_height * self.M.height # Note: "anim" is only shown in the expanded state # and thus not yet added to the submobjects of self. self.anim = anim def scale(self, scale_factor: float, **kwargs: Any) -> ManimBanner: """Scale the banner by the specified scale factor. Parameters ---------- scale_factor The factor used for scaling the banner. Returns ------- :class:`~.ManimBanner` The scaled banner. """ self.scale_factor *= scale_factor # Note: self.anim is only added to self after expand() if self.anim not in self.submobjects: self.anim.scale(scale_factor, **kwargs) return super().scale(scale_factor, **kwargs) @override_animation(Create) def create(self, run_time: float = 2) -> AnimationGroup: """The creation animation for Manim's logo. Parameters ---------- run_time The run time of the animation. Returns ------- :class:`~.AnimationGroup` An animation to be used in a :meth:`.Scene.play` call. """ return AnimationGroup( SpiralIn(self.shapes, run_time=run_time), FadeIn(self.M, run_time=run_time / 2), lag_ratio=0.1, ) def expand(self, run_time: float = 1.5, direction: str = "center") -> Succession: """An animation that expands Manim's logo into its banner. The returned animation transforms the banner from its initial state (representing Manim's logo with just the icons) to its expanded state (showing the full name together with the icons). See the class documentation for how to use this. .. note:: Before calling this method, the text "anim" is not a submobject of the banner object. After the expansion, it is added as a submobject so subsequent animations to the banner object apply to the text "anim" as well. Parameters ---------- run_time The run time of the animation. direction The direction in which the logo is expanded. Returns ------- :class:`~.Succession` An animation to be used in a :meth:`.Scene.play` call. Examples -------- .. manim:: ExpandDirections class ExpandDirections(Scene): def construct(self): banners = [ManimBanner().scale(0.5).shift(UP*x) for x in [-2, 0, 2]] self.play( banners[0].expand(direction="right"), banners[1].expand(direction="center"), banners[2].expand(direction="left"), ) """ if direction not in ["left", "right", "center"]: raise ValueError("direction must be 'left', 'right' or 'center'.") m_shape_offset = 6.25 * self.scale_factor shape_sliding_overshoot = self.scale_factor * 0.8 m_anim_buff = 0.06 self.anim.next_to(self.M, buff=m_anim_buff).align_to(self.M, cst.DOWN) self.anim.set_opacity(0) self.shapes.save_state() m_clone = self.anim[-1].copy() self.add(m_clone) m_clone.move_to(self.shapes) self.M.save_state() left_group = VGroup(self.M, self.anim, m_clone) def shift(vector: Vector3D) -> None: self.shapes.restore() left_group.align_to(self.M.saved_state, cst.LEFT) if direction == "right": self.shapes.shift(vector) elif direction == "center": self.shapes.shift(vector / 2) left_group.shift(-vector / 2) elif direction == "left": left_group.shift(-vector) def slide_and_uncover(mob: Mobject, alpha: float) -> None: shift(alpha * (m_shape_offset + shape_sliding_overshoot) * cst.RIGHT) # Add letters when they are covered for letter in mob.anim: if mob.square.get_center()[0] > letter.get_center()[0]: letter.set_opacity(1) self.add_to_back(letter) # Finish animation if alpha == 1: self.remove(*[self.anim]) self.add_to_back(self.anim) mob.shapes.set_z_index(0) mob.shapes.save_state() mob.M.save_state() def slide_back(mob: Mobject, alpha: float) -> None: if alpha == 0: m_clone.set_opacity(1) m_clone.move_to(mob.anim[-1]) mob.anim.set_opacity(1) shift(alpha * shape_sliding_overshoot * cst.LEFT) if alpha == 1: mob.remove(m_clone) mob.add_to_back(mob.shapes) return Succession( UpdateFromAlphaFunc( self, slide_and_uncover, run_time=run_time * 2 / 3, rate_func=ease_in_out_cubic, ), UpdateFromAlphaFunc( self, slide_back, run_time=run_time * 1 / 3, rate_func=smooth, ), ) ================================================ FILE: manim/mobject/matrix.py ================================================ r"""Mobjects representing matrices. Examples -------- .. manim:: MatrixExamples :save_last_frame: class MatrixExamples(Scene): def construct(self): m0 = Matrix([["\\pi", 0], [-1, 1]]) m1 = IntegerMatrix([[1.5, 0.], [12, -1.3]], left_bracket="(", right_bracket=")") m2 = DecimalMatrix( [[3.456, 2.122], [33.2244, 12.33]], element_to_mobject_config={"num_decimal_places": 2}, left_bracket=r"\{", right_bracket=r"\}") m3 = MobjectMatrix( [[Circle().scale(0.3), Square().scale(0.3)], [MathTex("\\pi").scale(2), Star().scale(0.3)]], left_bracket="\\langle", right_bracket="\\rangle") g = Group(m0, m1, m2, m3).arrange_in_grid(buff=2) self.add(g) """ from __future__ import annotations __all__ = [ "Matrix", "DecimalMatrix", "IntegerMatrix", "MobjectMatrix", "matrix_to_tex_string", "matrix_to_mobject", "get_det_text", ] import itertools as it from collections.abc import Callable, Iterable from typing import Any, Self import numpy as np from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.text.numbers import DecimalNumber, Integer from manim.mobject.text.tex_mobject import MathTex, Tex from manim.typing import Vector2DLike, Vector3DLike from ..constants import * from ..mobject.types.vectorized_mobject import VGroup, VMobject # TO DO : The following two functions are not used in this file. # Not sure if we should keep it or not. def matrix_to_tex_string(matrix: np.ndarray) -> str: matrix = np.array(matrix).astype("str") if matrix.ndim == 1: matrix = matrix.reshape((matrix.size, 1)) n_rows, n_cols = matrix.shape prefix = "\\left[ \\begin{array}{%s}" % ("c" * n_cols) suffix = "\\end{array} \\right]" rows = [" & ".join(row) for row in matrix] return prefix + " \\\\ ".join(rows) + suffix def matrix_to_mobject(matrix: np.ndarray) -> MathTex: return MathTex(matrix_to_tex_string(matrix)) class Matrix(VMobject, metaclass=ConvertToOpenGL): r"""A mobject that displays a matrix on the screen. Parameters ---------- matrix A numpy 2d array or list of lists. v_buff Vertical distance between elements, by default 0.8. h_buff Horizontal distance between elements, by default 1.3. bracket_h_buff Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``. bracket_v_buff Height of the brackets, by default ``MED_SMALL_BUFF``. add_background_rectangles_to_entries ``True`` if should add backgraound rectangles to entries, by default ``False``. include_background_rectangle ``True`` if should include background rectangle, by default ``False``. element_to_mobject The mobject class used to construct the elements, by default :class:`~.MathTex`. element_to_mobject_config Additional arguments to be passed to the constructor in ``element_to_mobject``, by default ``{}``. element_alignment_corner The corner to which elements are aligned, by default ``DR``. left_bracket The left bracket type, by default ``"["``. right_bracket The right bracket type, by default ``"]"``. stretch_brackets ``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``. bracket_config Additional arguments to be passed to :class:`~.MathTex` when constructing the brackets. Examples -------- The first example shows a variety of uses of this module while the second example exlpains the use of the options `add_background_rectangles_to_entries` and `include_background_rectangle`. .. manim:: MatrixExamples :save_last_frame: class MatrixExamples(Scene): def construct(self): 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=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=r"\langle", right_bracket=r"\rangle") m4 = Matrix([[2, 1], [-1, 3]], ).set_column_colors(RED, GREEN) m5 = Matrix([[2, 1], [-1, 3]], ).set_row_colors(RED, GREEN) g = Group( m0,m1,m2,m3,m4,m5 ).arrange_in_grid(buff=2) self.add(g) .. manim:: BackgroundRectanglesExample :save_last_frame: class BackgroundRectanglesExample(Scene): def construct(self): background= Rectangle().scale(3.2) background.set_fill(opacity=.5) background.set_color([TEAL, RED, YELLOW]) self.add(background) m0 = Matrix([[12, -30], [-1, 15]], add_background_rectangles_to_entries=True) m1 = Matrix([[2, 0], [-1, 1]], include_background_rectangle=True) m2 = Matrix([[12, -30], [-1, 15]]) g = Group(m0, m1, m2).arrange(buff=2) self.add(g) """ def __init__( self, matrix: Iterable[Iterable[Any] | Vector2DLike], v_buff: float = 0.8, h_buff: float = 1.3, bracket_h_buff: float = MED_SMALL_BUFF, bracket_v_buff: float = MED_SMALL_BUFF, add_background_rectangles_to_entries: bool = False, include_background_rectangle: bool = False, element_to_mobject: type[VMobject] | Callable[..., VMobject] = MathTex, element_to_mobject_config: dict[str, Any] = {}, element_alignment_corner: Vector3DLike = DR, left_bracket: str = "[", right_bracket: str = "]", stretch_brackets: bool = True, bracket_config: dict = {}, **kwargs: Any, ): self.v_buff = v_buff self.h_buff = h_buff self.bracket_h_buff = bracket_h_buff self.bracket_v_buff = bracket_v_buff self.add_background_rectangles_to_entries = add_background_rectangles_to_entries self.include_background_rectangle = include_background_rectangle self.element_to_mobject = element_to_mobject self.element_to_mobject_config = element_to_mobject_config self.element_alignment_corner = element_alignment_corner self.left_bracket = left_bracket self.right_bracket = right_bracket self.stretch_brackets = stretch_brackets super().__init__(**kwargs) mob_matrix = self._matrix_to_mob_matrix(matrix) self._organize_mob_matrix(mob_matrix) self.elements = VGroup(*it.chain(*mob_matrix)) self.add(self.elements) self._add_brackets(self.left_bracket, self.right_bracket, **bracket_config) self.center() self.mob_matrix = mob_matrix if self.add_background_rectangles_to_entries: for mob in self.elements: mob.add_background_rectangle() if self.include_background_rectangle: self.add_background_rectangle() def _matrix_to_mob_matrix( self, matrix: Iterable[Iterable[Any]] ) -> list[list[VMobject]]: return [ [ self.element_to_mobject(item, **self.element_to_mobject_config) for item in row ] for row in matrix ] def _organize_mob_matrix(self, matrix: list[list[VMobject]]) -> Self: for i, row in enumerate(matrix): for j, _ in enumerate(row): mob = matrix[i][j] mob.move_to( i * self.v_buff * DOWN + j * self.h_buff * RIGHT, self.element_alignment_corner, ) return self def _add_brackets(self, left: str = "[", right: str = "]", **kwargs: Any) -> Self: """Adds the brackets to the Matrix mobject. See Latex document for various bracket types. Parameters ---------- left the left bracket, by default "[" right the right bracket, by default "]" Returns ------- :class:`Matrix` The current matrix object (self). """ # Height per row of LaTeX array with default settings BRACKET_HEIGHT = 0.5977 n = int((self.height) / BRACKET_HEIGHT) + 1 empty_tex_array = "".join( [ r"\begin{array}{c}", *n * [r"\quad \\"], r"\end{array}", ] ) tex_left = "".join( [ r"\left" + left, empty_tex_array, r"\right.", ] ) tex_right = "".join( [ r"\left.", empty_tex_array, r"\right" + right, ] ) l_bracket = MathTex(tex_left, **kwargs) r_bracket = MathTex(tex_right, **kwargs) bracket_pair = VGroup(l_bracket, r_bracket) if self.stretch_brackets: bracket_pair.stretch_to_fit_height(self.height + 2 * self.bracket_v_buff) l_bracket.next_to(self, LEFT, self.bracket_h_buff) r_bracket.next_to(self, RIGHT, self.bracket_h_buff) self.brackets = bracket_pair self.add(l_bracket, r_bracket) return self def get_columns(self) -> VGroup: r"""Return columns of the matrix as VGroups. Returns -------- :class:`~.VGroup` The VGroup contains a nested VGroup for each column of the matrix. Examples -------- .. manim:: GetColumnsExample :save_last_frame: class GetColumnsExample(Scene): def construct(self): m0 = Matrix([[r"\pi", 3], [1, 5]]) m0.add(SurroundingRectangle(m0.get_columns()[1])) self.add(m0) """ return VGroup( *( VGroup(*(row[i] for row in self.mob_matrix)) for i in range(len(self.mob_matrix[0])) ) ) def set_column_colors(self, *colors: str) -> Self: r"""Set individual colors for each columns of the matrix. Parameters ---------- colors The list of colors; each color specified corresponds to a column. Returns ------- :class:`Matrix` The current matrix object (self). Examples -------- .. manim:: SetColumnColorsExample :save_last_frame: class SetColumnColorsExample(Scene): def construct(self): m0 = Matrix([["\\pi", 1], [-1, 3]], ).set_column_colors([RED,BLUE], GREEN) self.add(m0) """ columns = self.get_columns() for color, column in zip(colors, columns, strict=False): column.set_color(color) return self def get_rows(self) -> VGroup: r"""Return rows of the matrix as VGroups. Returns -------- :class:`~.VGroup` The VGroup contains a nested VGroup for each row of the matrix. Examples -------- .. manim:: GetRowsExample :save_last_frame: class GetRowsExample(Scene): def construct(self): m0 = Matrix([["\\pi", 3], [1, 5]]) m0.add(SurroundingRectangle(m0.get_rows()[1])) self.add(m0) """ return VGroup(*(VGroup(*row) for row in self.mob_matrix)) def set_row_colors(self, *colors: str) -> Self: r"""Set individual colors for each row of the matrix. Parameters ---------- colors The list of colors; each color specified corresponds to a row. Returns ------- :class:`Matrix` The current matrix object (self). Examples -------- .. manim:: SetRowColorsExample :save_last_frame: class SetRowColorsExample(Scene): def construct(self): m0 = Matrix([["\\pi", 1], [-1, 3]], ).set_row_colors([RED,BLUE], GREEN) self.add(m0) """ rows = self.get_rows() for color, row in zip(colors, rows, strict=False): row.set_color(color) return self def add_background_to_entries(self) -> Self: """Add a black background rectangle to the matrix, see above for an example. Returns ------- :class:`Matrix` The current matrix object (self). """ for mob in self.get_entries(): mob.add_background_rectangle() return self def get_mob_matrix(self) -> list[list[VMobject]]: """Return the underlying mob matrix mobjects. Returns -------- List[:class:`~.VGroup`] Each VGroup contains a row of the matrix. """ return self.mob_matrix def get_entries(self) -> VGroup: """Return the individual entries of the matrix. Returns -------- :class:`~.VGroup` VGroup containing entries of the matrix. Examples -------- .. manim:: GetEntriesExample :save_last_frame: class GetEntriesExample(Scene): def construct(self): m0 = Matrix([[2, 3], [1, 5]]) ent = m0.get_entries() colors = [BLUE, GREEN, YELLOW, RED] for k in range(len(colors)): ent[k].set_color(colors[k]) self.add(m0) """ return self.elements def get_brackets(self) -> VGroup: r"""Return the bracket mobjects. Returns -------- :class:`~.VGroup` A VGroup containing the left and right bracket. Examples -------- .. manim:: GetBracketsExample :save_last_frame: class GetBracketsExample(Scene): def construct(self): m0 = Matrix([["\\pi", 3], [1, 5]]) bra = m0.get_brackets() colors = [BLUE, GREEN] for k in range(len(colors)): bra[k].set_color(colors[k]) self.add(m0) """ return self.brackets class DecimalMatrix(Matrix): r"""A mobject that displays a matrix with decimal entries on the screen. Examples -------- .. manim:: DecimalMatrixExample :save_last_frame: class DecimalMatrixExample(Scene): def construct(self): m0 = DecimalMatrix( [[3.456, 2.122], [33.2244, 12]], element_to_mobject_config={"num_decimal_places": 2}, left_bracket="\\{", right_bracket="\\}") self.add(m0) """ def __init__( self, matrix: Iterable[Iterable[Any]], element_to_mobject: type[VMobject] | Callable[..., VMobject] = DecimalNumber, element_to_mobject_config: dict[str, Any] = {"num_decimal_places": 1}, **kwargs: Any, ): """ Will round/truncate the decimal places as per the provided config. Parameters ---------- matrix A numpy 2d array or list of lists element_to_mobject Mobject to use, by default DecimalNumber element_to_mobject_config Config for the desired mobject, by default {"num_decimal_places": 1} """ super().__init__( matrix, element_to_mobject=element_to_mobject, element_to_mobject_config=element_to_mobject_config, **kwargs, ) class IntegerMatrix(Matrix): """A mobject that displays a matrix with integer entries on the screen. Examples -------- .. manim:: IntegerMatrixExample :save_last_frame: class IntegerMatrixExample(Scene): def construct(self): m0 = IntegerMatrix( [[3.7, 2], [42.2, 12]], left_bracket="(", right_bracket=")") self.add(m0) """ def __init__( self, matrix: Iterable[Iterable[Any]], element_to_mobject: type[VMobject] | Callable[..., VMobject] = Integer, **kwargs: Any, ): """ Will round if there are decimal entries in the matrix. Parameters ---------- matrix A numpy 2d array or list of lists element_to_mobject Mobject to use, by default Integer """ super().__init__(matrix, element_to_mobject=element_to_mobject, **kwargs) class MobjectMatrix(Matrix): r"""A mobject that displays a matrix of mobject entries on the screen. Examples -------- .. manim:: MobjectMatrixExample :save_last_frame: class MobjectMatrixExample(Scene): def construct(self): a = Circle().scale(0.3) b = Square().scale(0.3) c = MathTex("\\pi").scale(2) d = Star().scale(0.3) m0 = MobjectMatrix([[a, b], [c, d]]) self.add(m0) """ def __init__( self, matrix: Iterable[Iterable[Any]], element_to_mobject: type[VMobject] | Callable[..., VMobject] = lambda m: m, **kwargs: Any, ): super().__init__(matrix, element_to_mobject=element_to_mobject, **kwargs) def get_det_text( matrix: Matrix, determinant: int | str | None = None, background_rect: bool = False, initial_scale_factor: float = 2, ) -> VGroup: r"""Helper function to create determinant. Parameters ---------- matrix The matrix whose determinant is to be created determinant The value of the determinant of the matrix background_rect The background rectangle initial_scale_factor The scale of the text `det` w.r.t the matrix Returns -------- :class:`~.VGroup` A VGroup containing the determinant Examples -------- .. manim:: DeterminantOfAMatrix :save_last_frame: class DeterminantOfAMatrix(Scene): def construct(self): matrix = Matrix([ [2, 0], [-1, 1] ]) # scaling down the `det` string det = get_det_text(matrix, determinant=3, initial_scale_factor=1) # must add the matrix self.add(matrix) self.add(det) """ parens = MathTex("(", ")") parens.scale(initial_scale_factor) parens.stretch_to_fit_height(matrix.height) l_paren, r_paren = parens.split() l_paren.next_to(matrix, LEFT, buff=0.1) r_paren.next_to(matrix, RIGHT, buff=0.1) det = Tex("det") det.scale(initial_scale_factor) det.next_to(l_paren, LEFT, buff=0.1) if background_rect: det.add_background_rectangle() det_text = VGroup(det, l_paren, r_paren) if determinant is not None: eq = MathTex("=") eq.next_to(r_paren, RIGHT, buff=0.1) result = MathTex(str(determinant)) result.next_to(eq, RIGHT, buff=0.2) det_text.add(eq, result) return det_text ================================================ FILE: manim/mobject/mobject.py ================================================ """Base classes for objects that can be displayed.""" from __future__ import annotations __all__ = ["Mobject", "Group", "override_animate"] import copy import inspect import itertools as it import math import operator as op import random import sys import types import warnings from collections.abc import Callable, Iterable, Iterator, Sequence from functools import partialmethod, reduce from pathlib import Path from typing import TYPE_CHECKING, Any, cast import numpy as np from manim.data_structures import MethodWithArgs from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from .. import config, logger from ..constants import * from ..utils.color import ( BLACK, PURE_YELLOW, WHITE, ManimColor, ParsableManimColor, color_gradient, interpolate_color, ) from ..utils.exceptions import MultiAnimationOverrideException from ..utils.iterables import list_update, remove_list_redundancies from ..utils.paths import straight_path from ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix if TYPE_CHECKING: from typing import Self, TypeAlias from PIL import Image from manim.mobject.types.point_cloud_mobject import Point from manim.typing import ( FunctionOverride, MappingFunction, MatrixMN, MultiMappingFunction, PathFuncType, Point3D, Point3D_Array, Point3DLike, Point3DLike_Array, Vector3D, Vector3DLike, ) from ..animation.animation import Animation from ..camera.camera import Camera _TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], object] _NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], object] _Updater: TypeAlias = _NonTimeBasedUpdater | _TimeBasedUpdater class Mobject: """Mathematical Object: base class for objects that can be displayed on screen. There is a compatibility layer that allows for getting and setting generic attributes with ``get_*`` and ``set_*`` methods. See :meth:`set` for more details. Attributes ---------- submobjects : List[:class:`Mobject`] The contained objects. points : :class:`numpy.ndarray` The points of the objects. .. seealso:: :class:`~.VMobject` """ original_id: str _original__init__: Callable[..., None] animation_overrides: dict[ type[Animation], FunctionOverride, ] = {} @classmethod def __init_subclass__(cls, **kwargs: Any) -> None: super().__init_subclass__(**kwargs) cls.animation_overrides = {} cls._add_intrinsic_animation_overrides() cls._original__init__ = cls.__init__ def __init__( self, color: ParsableManimColor | list[ParsableManimColor] = WHITE, name: str | None = None, dim: int = 3, target: Mobject | None = None, z_index: float = 0, ): self.name = self.__class__.__name__ if name is None else name self.dim = dim self.target = target self.z_index = z_index self.point_hash = None self.submobjects: list[Mobject] = [] self.updaters: list[_Updater] = [] self.updating_suspended = False self.color = ManimColor.parse(color) self.reset_points() self.generate_points() self.init_colors() def _assert_valid_submobjects(self, submobjects: Iterable[Mobject]) -> Self: """Check that all submobjects are actually instances of :class:`Mobject`, and that none of them is ``self`` (a :class:`Mobject` cannot contain itself). This is an auxiliary function called when adding Mobjects to the :attr:`submobjects` list. This function is intended to be overridden by subclasses such as :class:`VMobject`, which should assert that only other VMobjects may be added into it. Parameters ---------- submobjects The list containing values to validate. Returns ------- :class:`Mobject` The Mobject itself. Raises ------ TypeError If any of the values in `submobjects` is not a :class:`Mobject`. ValueError If there was an attempt to add a :class:`Mobject` as its own submobject. """ return self._assert_valid_submobjects_internal(submobjects, Mobject) def _assert_valid_submobjects_internal( self, submobjects: Iterable[Mobject], mob_class: type[Mobject] ) -> Self: for i, submob in enumerate(submobjects): if not isinstance(submob, mob_class): error_message = ( f"Only values of type {mob_class.__name__} can be added " f"as submobjects of {type(self).__name__}, but the value " f"{submob} (at index {i}) is of type " f"{type(submob).__name__}." ) # Intended for subclasses such as VMobject, which # cannot have regular Mobjects as submobjects if isinstance(submob, Mobject): error_message += ( " You can try adding this value into a Group instead." ) raise TypeError(error_message) if submob is self: raise ValueError( f"Cannot add {type(self).__name__} as a submobject of " f"itself (at index {i})." ) return self @classmethod def animation_override_for( cls, animation_class: type[Animation], ) -> FunctionOverride | None: """Returns the function defining a specific animation override for this class. Parameters ---------- animation_class The animation class for which the override function should be returned. Returns ------- Optional[Callable[[Mobject, ...], Animation]] The function returning the override animation or ``None`` if no such animation override is defined. """ if animation_class in cls.animation_overrides: return cls.animation_overrides[animation_class] return None @classmethod def _add_intrinsic_animation_overrides(cls) -> None: """Initializes animation overrides marked with the :func:`~.override_animation` decorator. """ for method_name in dir(cls): # Ignore dunder methods if method_name.startswith("__"): continue method = getattr(cls, method_name) if hasattr(method, "_override_animation"): animation_class = method._override_animation cls.add_animation_override(animation_class, method) @classmethod def add_animation_override( cls, animation_class: type[Animation], override_func: FunctionOverride, ) -> None: """Add an animation override. This does not apply to subclasses. Parameters ---------- animation_class The animation type to be overridden override_func The function returning an animation replacing the default animation. It gets passed the parameters given to the animation constructor. Raises ------ MultiAnimationOverrideException If the overridden animation was already overridden. """ if animation_class not in cls.animation_overrides: cls.animation_overrides[animation_class] = override_func else: raise MultiAnimationOverrideException( f"The animation {animation_class.__name__} for " f"{cls.__name__} is overridden by more than one method: " f"{cls.animation_overrides[animation_class].__qualname__} and " f"{override_func.__qualname__}.", ) @classmethod def set_default(cls, **kwargs: Any) -> None: """Sets the default values of keyword arguments. If this method is called without any additional keyword arguments, the original default values of the initialization method of this class are restored. Parameters ---------- kwargs Passing any keyword argument will update the default values of the keyword arguments of the initialization function of this class. Examples -------- :: >>> from manim import Square, GREEN >>> Square.set_default(color=GREEN, fill_opacity=0.25) >>> s = Square(); s.color, s.fill_opacity (ManimColor('#83C167'), 0.25) >>> Square.set_default() >>> s = Square(); s.color, s.fill_opacity (ManimColor('#FFFFFF'), 0.0) .. manim:: ChangedDefaultTextcolor :save_last_frame: config.background_color = WHITE class ChangedDefaultTextcolor(Scene): def construct(self): Text.set_default(color=BLACK) self.add(Text("Changing default values is easy!")) # we revert the colour back to the default to prevent a bug in the docs. Text.set_default(color=WHITE) """ if kwargs: # Apparently mypy does not correctly understand `partialmethod`: # see https://github.com/python/mypy/issues/8619 cls.__init__ = partialmethod(cls.__init__, **kwargs) # type: ignore[assignment] else: # error: Cannot assign to a method [method-assign] cls.__init__ = cls._original__init__ @property def animate(self) -> _AnimationBuilder | Self: """Used to animate the application of any method of :code:`self`. Any method called on :code:`animate` is converted to an animation of applying that method on the mobject itself. For example, :code:`square.set_fill(WHITE)` sets the fill color of a square, while :code:`square.animate.set_fill(WHITE)` animates this action. Multiple methods can be put in a single animation once via chaining: :: self.play(my_mobject.animate.shift(RIGHT).rotate(PI)) .. warning:: Passing multiple animations for the same :class:`Mobject` in one call to :meth:`~.Scene.play` is discouraged and will most likely not work properly. Instead of writing an animation like :: self.play( my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI) ) make use of method chaining. Keyword arguments that can be passed to :meth:`.Scene.play` can be passed directly after accessing ``.animate``, like so:: self.play(my_mobject.animate(rate_func=linear).shift(RIGHT)) This is especially useful when animating simultaneous ``.animate`` calls that you want to behave differently:: self.play( mobject1.animate(run_time=2).rotate(PI), mobject2.animate(rate_func=there_and_back).shift(RIGHT), ) .. seealso:: :func:`override_animate` Examples -------- .. manim:: AnimateExample class AnimateExample(Scene): def construct(self): s = Square() self.play(Create(s)) self.play(s.animate.shift(RIGHT)) self.play(s.animate.scale(2)) self.play(s.animate.rotate(PI / 2)) self.play(Uncreate(s)) .. manim:: AnimateChainExample class AnimateChainExample(Scene): def construct(self): s = Square() self.play(Create(s)) self.play(s.animate.shift(RIGHT).scale(2).rotate(PI / 2)) self.play(Uncreate(s)) .. manim:: AnimateWithArgsExample class AnimateWithArgsExample(Scene): def construct(self): s = Square() c = Circle() VGroup(s, c).arrange(RIGHT, buff=2) self.add(s, c) self.play( s.animate(run_time=2).rotate(PI / 2), c.animate(rate_func=there_and_back).shift(RIGHT), ) .. warning:: ``.animate`` will interpolate the :class:`~.Mobject` between its points prior to ``.animate`` and its points after applying ``.animate`` to it. This may result in unexpected behavior when attempting to interpolate along paths, or rotations (see :meth:`.rotate`). If you want animations to consider the points between, consider using :class:`~.ValueTracker` with updaters instead (see :meth:`.add_updater`). """ return _AnimationBuilder(self) @property def always(self) -> Self: """Call a method on a mobject every frame. This is syntactic sugar for ``mob.add_updater(lambda m: m.method(*args, **kwargs), call_updater=True)``. Note that this will call the method immediately. If this behavior is not desired, you should use :meth:`add_updater` directly. .. warning:: Chaining of methods is allowed, but each method will be added as its own updater. If you are chaining methods, make sure they do not interfere with each other or you may get unexpected results. .. warning:: :attr:`always` is not compatible with :meth:`.ValueTracker.get_value`, because the value will be computed once and then never updated again. Use :meth:`add_updater` if you would like to use a :class:`~.ValueTracker` to update the value. Example ------- .. manim:: AlwaysExample class AlwaysExample(Scene): def construct(self): sq = Square().to_edge(LEFT) t = Text("Hello World!") t.always.next_to(sq, UP) self.add(sq, t) self.play(sq.animate.to_edge(RIGHT)) """ # can't use typing.cast because Self is under TYPE_CHECKING return _UpdaterBuilder(self) # type: ignore[return-value] def __deepcopy__(self, clone_from_id: dict[int, Mobject]) -> Self: cls = self.__class__ result = cls.__new__(cls) clone_from_id[id(self)] = result for k, v in self.__dict__.items(): setattr(result, k, copy.deepcopy(v, clone_from_id)) result.original_id = str(id(self)) return result def __repr__(self) -> str: return str(self.name) def reset_points(self) -> Self: """Sets :attr:`points` to be an empty array.""" self.points = np.zeros((0, self.dim)) return self def init_colors(self, propagate_colors: bool = True) -> object: """Initializes the colors. Gets called upon creation. This is an empty method that can be implemented by subclasses. """ def generate_points(self) -> object: """Initializes :attr:`points` and therefore the shape. Gets called upon creation. This is an empty method that can be implemented by subclasses. """ def add(self, *mobjects: Mobject) -> Self: """Add mobjects as submobjects. The mobjects are added to :attr:`submobjects`. Subclasses of mobject may implement ``+`` and ``+=`` dunder methods. Parameters ---------- mobjects The mobjects to add. Returns ------- :class:`Mobject` ``self`` Raises ------ :class:`ValueError` When a mobject tries to add itself. :class:`TypeError` When trying to add an object that is not an instance of :class:`Mobject`. Notes ----- A mobject cannot contain itself, and it cannot contain a submobject more than once. If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene). See Also -------- :meth:`remove` :meth:`add_to_back` Examples -------- :: >>> outer = Mobject() >>> inner = Mobject() >>> outer = outer.add(inner) Duplicates are not added again:: >>> outer = outer.add(inner) >>> len(outer.submobjects) 1 Only Mobjects can be added:: >>> outer.add(3) Traceback (most recent call last): ... TypeError: Only values of type Mobject can be added as submobjects of Mobject, but the value 3 (at index 0) is of type int. Adding an object to itself raises an error:: >>> outer.add(outer) Traceback (most recent call last): ... ValueError: Cannot add Mobject as a submobject of itself (at index 0). A given mobject cannot be added as a submobject twice to some parent:: >>> parent = Mobject(name="parent") >>> child = Mobject(name="child") >>> parent.add(child, child) [...] WARNING ... parent >>> parent.submobjects [child] """ self._assert_valid_submobjects(mobjects) unique_mobjects = remove_list_redundancies(mobjects) if len(mobjects) != len(unique_mobjects): logger.warning( "Attempted adding some Mobject as a child more than once, " "this is not possible. Repetitions are ignored.", ) self.submobjects = list_update(self.submobjects, unique_mobjects) return self def insert(self, index: int, mobject: Mobject) -> None: """Inserts a mobject at a specific position into self.submobjects Effectively just calls ``self.submobjects.insert(index, mobject)``, where ``self.submobjects`` is a list. Highly adapted from ``Mobject.add``. Parameters ---------- index The index at which mobject The mobject to be inserted. """ self._assert_valid_submobjects([mobject]) self.submobjects.insert(index, mobject) def __add__(self, mobject: Mobject) -> Self: raise NotImplementedError def __iadd__(self, mobject: Mobject) -> Self: raise NotImplementedError def add_to_back(self, *mobjects: Mobject) -> Self: """Add all passed mobjects to the back of the submobjects. If :attr:`submobjects` already contains the given mobjects, they just get moved to the back instead. Parameters ---------- mobjects The mobjects to add. Returns ------- :class:`Mobject` ``self`` .. note:: Technically, this is done by adding (or moving) the mobjects to the head of :attr:`submobjects`. The head of this list is rendered first, which places the corresponding mobjects behind the subsequent list members. Raises ------ :class:`ValueError` When a mobject tries to add itself. :class:`TypeError` When trying to add an object that is not an instance of :class:`Mobject`. Notes ----- A mobject cannot contain itself, and it cannot contain a submobject more than once. If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene). See Also -------- :meth:`remove` :meth:`add` """ self._assert_valid_submobjects(mobjects) self.remove(*mobjects) # dict.fromkeys() removes duplicates while maintaining order self.submobjects = list(dict.fromkeys(mobjects)) + self.submobjects return self def remove(self, *mobjects: Mobject) -> Self: """Remove :attr:`submobjects`. The mobjects are removed from :attr:`submobjects`, if they exist. Subclasses of mobject may implement ``-`` and ``-=`` dunder methods. Parameters ---------- mobjects The mobjects to remove. Returns ------- :class:`Mobject` ``self`` See Also -------- :meth:`add` """ for mobject in mobjects: if mobject in self.submobjects: self.submobjects.remove(mobject) return self def __sub__(self, other: Mobject) -> Self: raise NotImplementedError def __isub__(self, other: Mobject) -> Self: raise NotImplementedError def set(self, **kwargs: Any) -> Self: """Sets attributes. I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``. This is a convenience to be used along with :attr:`animate` to animate setting attributes. In addition to this method, there is a compatibility layer that allows ``get_*`` and ``set_*`` methods to get and set generic attributes. For instance:: >>> mob = Mobject() >>> mob.set_foo(0) Mobject >>> mob.get_foo() 0 >>> mob.foo 0 This compatibility layer does not interfere with any ``get_*`` or ``set_*`` methods that are explicitly defined. .. warning:: This compatibility layer is for backwards compatibility and is not guaranteed to stay around. Where applicable, please prefer getting/setting attributes normally or with the :meth:`set` method. Parameters ---------- **kwargs The attributes and corresponding values to set. Returns ------- :class:`Mobject` ``self`` Examples -------- :: >>> mob = Mobject() >>> mob.set(foo=0) Mobject >>> mob.foo 0 """ for attr, value in kwargs.items(): setattr(self, attr, value) return self def __getattr__(self, attr: str) -> types.MethodType: # Add automatic compatibility layer # between properties and get_* and set_* # methods. # # In python 3.9+ we could change this # logic to use str.remove_prefix instead. if attr.startswith("get_"): # Remove the "get_" prefix to_get = attr[4:] def getter(self: Mobject) -> Any: warnings.warn( "This method is not guaranteed to stay around. Please prefer " "getting the attribute normally.", DeprecationWarning, stacklevel=2, ) return getattr(self, to_get) # Return a bound method return types.MethodType(getter, self) if attr.startswith("set_"): # Remove the "set_" prefix to_set = attr[4:] def setter(self: Mobject, value: Any) -> Mobject: warnings.warn( "This method is not guaranteed to stay around. Please prefer " "setting the attribute normally or with Mobject.set().", DeprecationWarning, stacklevel=2, ) setattr(self, to_set, value) return self # Return a bound method return types.MethodType(setter, self) # Unhandled attribute, therefore error raise AttributeError(f"{type(self).__name__} object has no attribute '{attr}'") @property def width(self) -> float: """The width of the mobject. Returns ------- :class:`float` Examples -------- .. manim:: WidthExample class WidthExample(Scene): def construct(self): decimal = DecimalNumber().to_edge(UP) rect = Rectangle(color=BLUE) rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5) decimal.add_updater(lambda d: d.set_value(rect.width)) self.add(rect_copy, rect, decimal) self.play(rect.animate.set(width=7)) self.wait() See also -------- :meth:`length_over_dim` """ # Get the length across the X dimension return self.length_over_dim(0) @width.setter def width(self, value: float) -> None: self.scale_to_fit_width(value) @property def height(self) -> float: """The height of the mobject. Returns ------- :class:`float` Examples -------- .. manim:: HeightExample class HeightExample(Scene): def construct(self): decimal = DecimalNumber().to_edge(UP) rect = Rectangle(color=BLUE) rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5) decimal.add_updater(lambda d: d.set_value(rect.height)) self.add(rect_copy, rect, decimal) self.play(rect.animate.set(height=5)) self.wait() See also -------- :meth:`length_over_dim` """ # Get the length across the Y dimension return self.length_over_dim(1) @height.setter def height(self, value: float) -> None: self.scale_to_fit_height(value) @property def depth(self) -> float: """The depth of the mobject. Returns ------- :class:`float` See also -------- :meth:`length_over_dim` """ # Get the length across the Z dimension return self.length_over_dim(2) @depth.setter def depth(self, value: float) -> None: self.scale_to_fit_depth(value) # Can't be staticmethod because of point_cloud_mobject.py def get_array_attrs(self) -> list[str]: return ["points"] def apply_over_attr_arrays(self, func: MultiMappingFunction) -> Self: for attr in self.get_array_attrs(): setattr(self, attr, func(getattr(self, attr))) return self # Displaying def get_image(self, camera: Camera | None = None) -> Image.Image: if camera is None: camera = Camera() camera.capture_mobject(self) return camera.get_image() def show(self, camera: Camera | None = None) -> None: self.get_image(camera=camera).show() def save_image(self, name: str | None = None) -> None: """Saves an image of only this :class:`Mobject` at its position to a png file. """ self.get_image().save( Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"), ) def copy(self) -> Self: """Create and return an identical copy of the :class:`Mobject` including all :attr:`submobjects`. Returns ------- :class:`Mobject` The copy. Note ---- The clone is initially not visible in the Scene, even if the original was. """ return copy.deepcopy(self) def generate_target(self, use_deepcopy: bool = False) -> Self: self.target = None # Prevent unbounded linear recursion if use_deepcopy: self.target = copy.deepcopy(self) else: self.target = self.copy() return self.target # Updating def update(self, dt: float = 0, recursive: bool = True) -> Self: """Apply all updaters. Does nothing if updating is suspended. Parameters ---------- dt The parameter ``dt`` to pass to the update functions. Usually this is the time in seconds since the last call of ``update``. recursive Whether to recursively update all submobjects. Returns ------- :class:`Mobject` ``self`` See Also -------- :meth:`add_updater` :meth:`get_updaters` """ if self.updating_suspended: return self for updater in self.updaters: if "dt" in inspect.signature(updater).parameters: time_based_updater = cast(_TimeBasedUpdater, updater) time_based_updater(self, dt) else: non_time_based_updater = cast(_NonTimeBasedUpdater, updater) non_time_based_updater(self) if recursive: for submob in self.submobjects: submob.update(dt, recursive=recursive) return self def get_time_based_updaters(self) -> list[_TimeBasedUpdater]: """Return all updaters using the ``dt`` parameter. The updaters use this parameter as the input for difference in time. Returns ------- List[:class:`Callable`] The list of time based updaters. See Also -------- :meth:`get_updaters` :meth:`has_time_based_updater` """ rv: list[_TimeBasedUpdater] = [] for updater in self.updaters: if "dt" in inspect.signature(updater).parameters: time_based_updater = cast(_TimeBasedUpdater, updater) rv.append(time_based_updater) return rv def has_time_based_updater(self) -> bool: """Test if ``self`` has a time based updater. Returns ------- :class:`bool` ``True`` if at least one updater uses the ``dt`` parameter, ``False`` otherwise. See Also -------- :meth:`get_time_based_updaters` """ return any( "dt" in inspect.signature(updater).parameters for updater in self.updaters ) def get_updaters(self) -> list[_Updater]: """Return all updaters. Returns ------- List[:class:`Callable`] The list of updaters. See Also -------- :meth:`add_updater` :meth:`get_time_based_updaters` """ return self.updaters def get_family_updaters(self) -> list[_Updater]: return list(it.chain(*(sm.get_updaters() for sm in self.get_family()))) def add_updater( self, update_function: _Updater, index: int | None = None, call_updater: bool = False, ) -> Self: """Add an update function to this mobject. Update functions, or updaters in short, are functions that are applied to the Mobject in every frame. Parameters ---------- update_function The update function to be added. Whenever :meth:`update` is called, this update function gets called using ``self`` as the first parameter. The updater can have a second parameter ``dt``. If it uses this parameter, it gets called using a second value ``dt``, usually representing the time in seconds since the last call of :meth:`update`. index The index at which the new updater should be added in ``self.updaters``. In case ``index`` is ``None`` the updater will be added at the end. call_updater Whether or not to call the updater initially. If ``True``, the updater will be called using ``dt=0``. Returns ------- :class:`Mobject` ``self`` Examples -------- .. manim:: NextToUpdater class NextToUpdater(Scene): def construct(self): def update_label(mobject): mobject.set_value(dot.get_center()[0]) mobject.next_to(dot) dot = Dot(RIGHT*3) label = DecimalNumber() label.add_updater(update_label) self.add(dot, label) self.play(Rotating(dot, angle=TAU, about_point=ORIGIN, run_time=TAU, rate_func=linear)) .. manim:: DtUpdater class DtUpdater(Scene): def construct(self): square = Square() #Let the square rotate 90° per second square.add_updater(lambda mobject, dt: mobject.rotate(dt*90*DEGREES)) self.add(square) self.wait(2) See also -------- :meth:`get_updaters` :meth:`remove_updater` :class:`~.UpdateFromFunc` :class:`~.Rotating` :meth:`rotate` :attr:`~.Mobject.animate` """ if index is None: self.updaters.append(update_function) else: self.updaters.insert(index, update_function) if call_updater: parameters = inspect.signature(update_function).parameters if "dt" in parameters: time_based_updater = cast(_TimeBasedUpdater, update_function) time_based_updater(self, 0) else: non_time_based_updater = cast(_NonTimeBasedUpdater, update_function) non_time_based_updater(self) return self def remove_updater(self, update_function: _Updater) -> Self: """Remove an updater. If the same updater is applied multiple times, every instance gets removed. Parameters ---------- update_function The update function to be removed. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`clear_updaters` :meth:`add_updater` :meth:`get_updaters` """ while update_function in self.updaters: self.updaters.remove(update_function) return self def clear_updaters(self, recursive: bool = True) -> Self: """Remove every updater. Parameters ---------- recursive Whether to recursively call ``clear_updaters`` on all submobjects. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`remove_updater` :meth:`add_updater` :meth:`get_updaters` """ self.updaters = [] if recursive: for submob in self.submobjects: submob.clear_updaters() return self def match_updaters(self, mobject: Mobject) -> Self: """Match the updaters of the given mobject. Parameters ---------- mobject The mobject whose updaters get matched. Returns ------- :class:`Mobject` ``self`` Note ---- All updaters from submobjects are removed, but only updaters of the given mobject are matched, not those of it's submobjects. See also -------- :meth:`add_updater` :meth:`clear_updaters` """ self.clear_updaters() for updater in mobject.get_updaters(): self.add_updater(updater) return self def suspend_updating(self, recursive: bool = True) -> Self: """Disable updating from updaters and animations. Parameters ---------- recursive Whether to recursively suspend updating on all submobjects. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`resume_updating` :meth:`add_updater` """ self.updating_suspended = True if recursive: for submob in self.submobjects: submob.suspend_updating(recursive) return self def resume_updating(self, recursive: bool = True) -> Self: """Enable updating from updaters and animations. Parameters ---------- recursive Whether to recursively enable updating on all submobjects. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`suspend_updating` :meth:`add_updater` """ self.updating_suspended = False if recursive: for submob in self.submobjects: submob.resume_updating(recursive) self.update(dt=0, recursive=recursive) return self # Transforming operations def apply_to_family(self, func: Callable[[Mobject], None]) -> None: """Apply a function to ``self`` and every submobject with points recursively. Parameters ---------- func The function to apply to each mobject. ``func`` gets passed the respective (sub)mobject as parameter. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`family_members_with_points` """ for mob in self.family_members_with_points(): func(mob) def shift(self, *vectors: Vector3DLike) -> Self: """Shift by the given vectors. Parameters ---------- vectors Vectors to shift by. If multiple vectors are given, they are added together. Returns ------- :class:`Mobject` ``self`` See also -------- :meth:`move_to` """ total_vector = reduce(op.add, vectors) for mob in self.family_members_with_points(): mob.points = mob.points.astype("float") mob.points += total_vector return self def scale( self, scale_factor: float, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: r"""Scale the size by a factor. Default behavior is to scale about the center of the mobject. Parameters ---------- scale_factor The scaling factor :math:`\alpha`. If :math:`0 < |\alpha| < 1`, the mobject will shrink, and for :math:`|\alpha| > 1` it will grow. Furthermore, if :math:`\alpha < 0`, the mobject is also flipped. about_point The point about which to apply the scaling. about_edge The edge about which to apply the scaling. Returns ------- :class:`Mobject` ``self`` Examples -------- .. manim:: MobjectScaleExample :save_last_frame: class MobjectScaleExample(Scene): def construct(self): f1 = Text("F") f2 = Text("F").scale(2) f3 = Text("F").scale(0.5) f4 = Text("F").scale(-1) vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT) self.add(vgroup) See also -------- :meth:`move_to` """ self.apply_points_function_about_point( lambda points: scale_factor * points, about_point, about_edge ) return self def rotate_about_origin(self, angle: float, axis: Vector3DLike = OUT) -> Self: """Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0].""" return self.rotate(angle, axis, about_point=ORIGIN) def rotate( self, angle: float, axis: Vector3DLike = OUT, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, **kwargs: Any, ) -> Self: """Rotates the :class:`~.Mobject` around a specified axis and point. Parameters ---------- angle The angle of rotation in radians. Predefined constants such as ``DEGREES`` can also be used to specify the angle in degrees. axis The rotation axis (see :class:`~.Rotating` for more). about_point The point about which the mobject rotates. If ``None``, rotation occurs around the center of the mobject. about_edge The edge about which to apply the scaling. Returns ------- :class:`Mobject` ``self`` (for method chaining) .. note:: To animate a rotation, use :class:`~.Rotating` or :class:`~.Rotate` instead of ``.animate.rotate(...)``. The ``.animate.rotate(...)`` syntax only applies a transformation from the initial state to the final rotated state (interpolation between the two states), without showing proper rotational motion based on the angle (from 0 to the given angle). Examples -------- .. manim:: RotateMethodExample :save_last_frame: class RotateMethodExample(Scene): def construct(self): circle = Circle(radius=1, color=BLUE) line = Line(start=ORIGIN, end=RIGHT) arrow1 = Arrow(start=ORIGIN, end=RIGHT, buff=0, color=GOLD) group1 = VGroup(circle, line, arrow1) group2 = group1.copy() arrow2 = group2[2] arrow2.rotate(angle=PI / 4, about_point=arrow2.get_start()) group3 = group1.copy() arrow3 = group3[2] arrow3.rotate(angle=120 * DEGREES, about_point=arrow3.get_start()) self.add(VGroup(group1, group2, group3).arrange(RIGHT, buff=1)) See also -------- :class:`~.Rotating`, :class:`~.Rotate`, :attr:`~.Mobject.animate`, :meth:`apply_points_function_about_point` """ rot_matrix = rotation_matrix(angle, axis) self.apply_points_function_about_point( lambda points: np.dot(points, rot_matrix.T), about_point, about_edge ) return self def flip( self, axis: Vector3DLike = UP, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: """Flips/Mirrors an mobject about its center. Examples -------- .. manim:: FlipExample :save_last_frame: class FlipExample(Scene): def construct(self): s= Line(LEFT, RIGHT+UP).shift(4*LEFT) self.add(s) s2= s.copy().flip() self.add(s2) """ return self.rotate( TAU / 2, axis, about_point=about_point, about_edge=about_edge ) def stretch( self, factor: float, dim: int, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: def func(points: Point3D_Array) -> Point3D_Array: points[:, dim] *= factor return points self.apply_points_function_about_point(func, about_point, about_edge) return self def apply_function( self, function: MappingFunction, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: # Default to applying matrix about the origin, not mobjects center if about_point is None and about_edge is None: about_point = ORIGIN def multi_mapping_function(points: Point3D_Array) -> Point3D_Array: result: Point3D_Array = np.apply_along_axis(function, 1, points) return result self.apply_points_function_about_point( multi_mapping_function, about_point, about_edge, ) return self def apply_function_to_position(self, function: MappingFunction) -> Self: self.move_to(function(self.get_center())) return self def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self: for submob in self.submobjects: submob.apply_function_to_position(function) return self def apply_matrix( self, matrix: MatrixMN, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: # Default to applying matrix about the origin, not mobjects center if about_point is None and about_edge is None: about_point = ORIGIN full_matrix = np.identity(self.dim) matrix = np.array(matrix) full_matrix[: matrix.shape[0], : matrix.shape[1]] = matrix self.apply_points_function_about_point( lambda points: np.dot(points, full_matrix.T), about_point, about_edge ) return self def apply_complex_function( self, function: Callable[[complex], complex], *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: """Applies a complex function to a :class:`Mobject`. The x and y Point3Ds correspond to the real and imaginary parts respectively. Example ------- .. manim:: ApplyFuncExample class ApplyFuncExample(Scene): def construct(self): circ = Circle().scale(1.5) circ_ref = circ.copy() circ.apply_complex_function( lambda x: np.exp(x*1j) ) t = ValueTracker(0) circ.add_updater( lambda x: x.become(circ_ref.copy().apply_complex_function( lambda x: np.exp(x+t.get_value()*1j) )).set_color(BLUE) ) self.add(circ_ref) self.play(TransformFromCopy(circ_ref, circ)) self.play(t.animate.set_value(TAU), run_time=3) """ def R3_func(point: Point3D) -> Point3D: x, y, z = point xy_complex = function(complex(x, y)) return np.array([xy_complex.real, xy_complex.imag, z]) return self.apply_function( R3_func, about_point=about_point, about_edge=about_edge ) def reverse_points(self) -> Self: for mob in self.family_members_with_points(): mob.apply_over_attr_arrays(lambda arr: np.array(list(reversed(arr)))) return self def repeat(self, count: int) -> Self: """This can make transition animations nicer""" def repeat_array(array: Point3D_Array) -> Point3D_Array: return reduce(lambda a1, a2: np.append(a1, a2, axis=0), [array] * count) for mob in self.family_members_with_points(): mob.apply_over_attr_arrays(repeat_array) return self # In place operations. # Note, much of these are now redundant with default behavior of # above methods # TODO: name is inconsistent with OpenGLMobject.apply_points_function() def apply_points_function_about_point( self, func: MultiMappingFunction, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: if about_point is None: if about_edge is None: about_edge = ORIGIN about_point = self.get_critical_point(about_edge) # Make a copy to prevent mutation of the original array if about_point is a view about_point = np.array(about_point, copy=True) for mob in self.family_members_with_points(): mob.points -= about_point mob.points = func(mob.points) mob.points += about_point return self def pose_at_angle(self, **kwargs: Any) -> Self: self.rotate(TAU / 14, RIGHT + UP, **kwargs) return self # Positioning methods def center(self) -> Self: """Moves the center of the mobject to the center of the scene. Returns ------- :class:`.Mobject` The centered mobject. """ self.shift(-self.get_center()) return self def align_on_border( self, direction: Vector3DLike, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER ) -> Self: """Direction just needs to be a vector pointing towards side or corner in the 2d plane. """ target_point = np.sign(direction) * ( config["frame_x_radius"], config["frame_y_radius"], 0, ) point_to_align = self.get_critical_point(direction) shift_val = target_point - point_to_align - buff * np.array(direction) shift_val = shift_val * abs(np.sign(direction)) self.shift(shift_val) return self def to_corner( self, corner: Vector3DLike = DL, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER ) -> Self: """Moves this :class:`~.Mobject` to the given corner of the screen. Returns ------- :class:`.Mobject` The newly positioned mobject. Examples -------- .. manim:: ToCornerExample :save_last_frame: class ToCornerExample(Scene): def construct(self): c = Circle() c.to_corner(UR) t = Tex("To the corner!") t2 = MathTex("x^3").shift(DOWN) self.add(c,t,t2) t.to_corner(DL, buff=0) t2.to_corner(UL, buff=1.5) """ return self.align_on_border(corner, buff) def to_edge( self, edge: Vector3DLike = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER ) -> Self: """Moves this :class:`~.Mobject` to the given edge of the screen, without affecting its position in the other dimension. Returns ------- :class:`.Mobject` The newly positioned mobject. Examples -------- .. manim:: ToEdgeExample :save_last_frame: class ToEdgeExample(Scene): def construct(self): tex_top = Tex("I am at the top!") tex_top.to_edge(UP) tex_side = Tex("I am moving to the side!") c = Circle().shift(2*DOWN) self.add(tex_top, tex_side, c) tex_side.to_edge(LEFT) c.to_edge(RIGHT, buff=0) """ return self.align_on_border(edge, buff) def next_to( self, mobject_or_point: Mobject | Point3DLike, direction: Vector3DLike = RIGHT, buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER, aligned_edge: Vector3DLike = ORIGIN, submobject_to_align: Mobject | None = None, index_of_submobject_to_align: int | None = None, coor_mask: Vector3DLike = np.array([1, 1, 1]), ) -> Self: """Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or Point3D. Examples -------- .. manim:: GeometricShapes :save_last_frame: class GeometricShapes(Scene): def construct(self): d = Dot() c = Circle() s = Square() t = Triangle() d.next_to(c, RIGHT) s.next_to(c, LEFT) t.next_to(c, DOWN) self.add(d, c, s, t) """ np_direction = np.asarray(direction) np_aligned_edge = np.asarray(aligned_edge) if isinstance(mobject_or_point, Mobject): mob = mobject_or_point if index_of_submobject_to_align is not None: target_aligner = mob[index_of_submobject_to_align] else: target_aligner = mob target_point = target_aligner.get_critical_point( np_aligned_edge + np_direction ) else: target_point = mobject_or_point if submobject_to_align is not None: aligner = submobject_to_align elif index_of_submobject_to_align is not None: aligner = self[index_of_submobject_to_align] else: aligner = self point_to_align = aligner.get_critical_point(np_aligned_edge - np_direction) self.shift((target_point - point_to_align + buff * np_direction) * coor_mask) return self def shift_onto_screen(self, **kwargs: Any) -> Self: space_lengths = [config["frame_x_radius"], config["frame_y_radius"]] for vect in UP, DOWN, LEFT, RIGHT: dim = np.argmax(np.abs(vect)) buff = kwargs.get("buff", DEFAULT_MOBJECT_TO_EDGE_BUFFER) max_val = space_lengths[dim] - buff edge_center = self.get_edge_center(vect) if np.dot(edge_center, vect) > max_val: self.to_edge(vect, **kwargs) return self def is_off_screen(self) -> bool: if self.get_left()[0] > config["frame_x_radius"]: return True if self.get_right()[0] < -config["frame_x_radius"]: return True if self.get_bottom()[1] > config["frame_y_radius"]: return True rv: bool = self.get_top()[1] < -config["frame_y_radius"] return rv def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self: return self.stretch(factor, dim, about_point=point) def rescale_to_fit( self, length: float, dim: int, stretch: bool = False, **kwargs: Any ) -> Self: old_length = self.length_over_dim(dim) if old_length == 0: return self if stretch: self.stretch(length / old_length, dim, **kwargs) else: self.scale(length / old_length, **kwargs) return self def scale_to_fit_width(self, width: float, **kwargs: Any) -> Self: """Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional. Returns ------- :class:`Mobject` ``self`` Examples -------- :: >>> from manim import * >>> sq = Square() >>> sq.height np.float64(2.0) >>> sq.scale_to_fit_width(5) Square >>> sq.width np.float64(5.0) >>> sq.height np.float64(5.0) """ return self.rescale_to_fit(width, 0, stretch=False, **kwargs) def stretch_to_fit_width(self, width: float, **kwargs: Any) -> Self: """Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional. Returns ------- :class:`Mobject` ``self`` Examples -------- :: >>> from manim import * >>> sq = Square() >>> sq.height np.float64(2.0) >>> sq.stretch_to_fit_width(5) Square >>> sq.width np.float64(5.0) >>> sq.height np.float64(2.0) """ return self.rescale_to_fit(width, 0, stretch=True, **kwargs) def scale_to_fit_height(self, height: float, **kwargs: Any) -> Self: """Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional. Returns ------- :class:`Mobject` ``self`` Examples -------- :: >>> from manim import * >>> sq = Square() >>> sq.width np.float64(2.0) >>> sq.scale_to_fit_height(5) Square >>> sq.height np.float64(5.0) >>> sq.width np.float64(5.0) """ return self.rescale_to_fit(height, 1, stretch=False, **kwargs) def stretch_to_fit_height(self, height: float, **kwargs: Any) -> Self: """Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional. Returns ------- :class:`Mobject` ``self`` Examples -------- :: >>> from manim import * >>> sq = Square() >>> sq.width np.float64(2.0) >>> sq.stretch_to_fit_height(5) Square >>> sq.height np.float64(5.0) >>> sq.width np.float64(2.0) """ return self.rescale_to_fit(height, 1, stretch=True, **kwargs) def scale_to_fit_depth(self, depth: float, **kwargs: Any) -> 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: Any) -> 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: float, dim: int, direction: Vector3DLike = ORIGIN ) -> Self: curr = self.get_coord(dim, direction) shift_vect = np.zeros(self.dim) shift_vect[dim] = value - curr self.shift(shift_vect) return self def set_x(self, x: float, direction: Vector3DLike = ORIGIN) -> Self: """Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)""" return self.set_coord(x, 0, direction) def set_y(self, y: float, direction: Vector3DLike = ORIGIN) -> Self: """Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)""" return self.set_coord(y, 1, direction) def set_z(self, z: float, direction: Vector3DLike = ORIGIN) -> Self: """Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)""" return self.set_coord(z, 2, direction) def space_out_submobjects(self, factor: float = 1.5, **kwargs: Any) -> Self: self.scale(factor, **kwargs) for submob in self.submobjects: submob.scale(1.0 / factor) return self def move_to( self, point_or_mobject: Point3DLike | Mobject, aligned_edge: Vector3DLike = ORIGIN, coor_mask: Vector3DLike = np.array([1, 1, 1]), ) -> Self: """Move center of the :class:`~.Mobject` to certain Point3D.""" if isinstance(point_or_mobject, Mobject): target = point_or_mobject.get_critical_point(aligned_edge) else: target = point_or_mobject point_to_align = self.get_critical_point(aligned_edge) self.shift((target - point_to_align) * coor_mask) return self def replace( self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False ) -> Self: if not mobject.get_num_points() and not mobject.submobjects: raise Warning("Attempting to replace mobject with no points") if stretch: self.stretch_to_fit_width(mobject.width) self.stretch_to_fit_height(mobject.height) else: self.rescale_to_fit( mobject.length_over_dim(dim_to_match), dim_to_match, stretch=False, ) self.shift(mobject.get_center() - self.get_center()) return self def surround( self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False, buff: float = MED_SMALL_BUFF, ) -> Self: self.replace(mobject, dim_to_match, stretch) length = mobject.length_over_dim(dim_to_match) self.scale((length + buff) / length) return self def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self: curr_start, curr_end = self.get_start_and_end() curr_vect = curr_end - curr_start if np.all(curr_vect == 0): # TODO: this looks broken. It makes self.points a Point3D instead # of a Point3D_Array. However, modifying this breaks some tests # where this is currently expected. self.points = np.array(start) return self target_vect = np.asarray(end) - np.asarray(start) axis = ( normalize(np.cross(curr_vect, target_vect)) if np.linalg.norm(np.cross(curr_vect, target_vect)) != 0 else OUT ) self.scale( np.linalg.norm(target_vect) / np.linalg.norm(curr_vect), about_point=curr_start, ) self.rotate( angle_between_vectors(curr_vect, target_vect), about_point=curr_start, axis=axis, ) self.shift(start - curr_start) return self # Background rectangle def add_background_rectangle( self, color: ParsableManimColor | None = None, opacity: float = 0.75, **kwargs: Any, ) -> Self: """Add a BackgroundRectangle as submobject. The BackgroundRectangle is added behind other submobjects. This can be used to increase the mobjects visibility in front of a noisy background. Parameters ---------- color The color of the BackgroundRectangle opacity The opacity of the BackgroundRectangle kwargs Additional keyword arguments passed to the BackgroundRectangle constructor Returns ------- :class:`Mobject` ``self`` See Also -------- :meth:`add_to_back` :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 self.background_rectangle = BackgroundRectangle( self, color=color, fill_opacity=opacity, **kwargs ) self.add_to_back(self.background_rectangle) return self def add_background_rectangle_to_submobjects(self, **kwargs: Any) -> Self: for submobject in self.submobjects: submobject.add_background_rectangle(**kwargs) return self def add_background_rectangle_to_family_members_with_points( self, **kwargs: Any ) -> Self: for mob in self.family_members_with_points(): mob.add_background_rectangle(**kwargs) return self # Color functions def set_color( self, color: ParsableManimColor = PURE_YELLOW, alpha: Any = None, family: bool = True, ) -> Self: """Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color """ if family: for submob in self.submobjects: submob.set_color(color, family=family) self.color = ManimColor.parse(color) return self def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self: """ Parameters ---------- colors The colors to use for the gradient. Use like `set_color_by_gradient(RED, BLUE, GREEN)`. self.color = ManimColor.parse(color) return self """ self.set_submobject_colors_by_gradient(*colors) return self def set_colors_by_radial_gradient( self, center: Point3DLike | None = None, radius: float = 1, inner_color: ParsableManimColor = WHITE, outer_color: ParsableManimColor = BLACK, ) -> Self: self.set_submobject_colors_by_radial_gradient( center, radius, inner_color, outer_color, ) return self def set_submobject_colors_by_gradient(self, *colors: ParsableManimColor) -> Self: if len(colors) == 0: raise ValueError("Need at least one color") elif len(colors) == 1: return self.set_color(*colors) mobs = self.family_members_with_points() new_colors = color_gradient(colors, len(mobs)) for mob, color in zip(mobs, new_colors, strict=True): mob.set_color(color, family=False) return self def set_submobject_colors_by_radial_gradient( self, center: Point3DLike | None = None, radius: float = 1, inner_color: ParsableManimColor = WHITE, outer_color: ParsableManimColor = BLACK, ) -> Self: if center is None: center = self.get_center() for mob in self.family_members_with_points(): t = np.linalg.norm(mob.get_center() - center) / radius t = min(t, 1) mob_color = interpolate_color( ManimColor(inner_color), ManimColor(outer_color), t ) mob.set_color(mob_color, family=False) return self def to_original_color(self) -> Self: self.set_color(self.color) return self def fade_to( self, color: ParsableManimColor, alpha: float, family: bool = True ) -> Self: if self.get_num_points() > 0: new_color = interpolate_color(self.get_color(), ManimColor(color), alpha) self.set_color(new_color, family=False) if family: for submob in self.submobjects: submob.fade_to(color, alpha) return self def fade(self, darkness: float = 0.5, family: bool = True) -> Self: if family: for submob in self.submobjects: submob.fade(darkness, family) return self def get_color(self) -> ManimColor: """Returns the color of the :class:`~.Mobject` Examples -------- :: >>> from manim import Square, RED >>> Square(color=RED).get_color() == RED True """ return self.color ## def save_state(self) -> Self: """Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`.""" if hasattr(self, "saved_state"): # Prevent exponential growth of data self.saved_state = None self.saved_state = self.copy() return self def restore(self) -> Self: """Restores the state that was previously saved with :meth:`~.Mobject.save_state`.""" if not hasattr(self, "saved_state") or self.saved_state is None: raise Exception("Trying to restore without having saved") self.become(self.saved_state) return self def reduce_across_dimension( self, reduce_func: Callable[[Iterable[float]], float], dim: int ) -> float: """Find the min or max value from a dimension across all points in this and submobjects.""" assert dim >= 0 assert dim <= 2 if len(self.submobjects) == 0 and len(self.points) == 0: # If we have no points and no submobjects, return 0 (e.g. center) return 0 # If we do not have points (but do have submobjects) # use only the points from those. if len(self.points) == 0: # noqa: SIM108 rv = None else: # Otherwise, be sure to include our own points rv = reduce_func(self.points[:, dim]) # Recursively ask submobjects (if any) for the biggest/ # smallest dimension they have and compare it to the return value. for mobj in self.submobjects: value = mobj.reduce_across_dimension(reduce_func, dim) rv = value if rv is None else reduce_func([value, rv]) assert rv is not None return rv def nonempty_submobjects(self) -> Sequence[Mobject]: return [ submob for submob in self.submobjects if len(submob.submobjects) != 0 or len(submob.points) != 0 ] def get_merged_array(self, array_attr: str) -> np.ndarray: """Return all of a given attribute from this mobject and all submobjects. May contain duplicates; the order is in a depth-first (pre-order) traversal of the submobjects. """ result = getattr(self, array_attr) for submob in self.submobjects: result = np.append(result, submob.get_merged_array(array_attr), axis=0) return result def get_all_points(self) -> Point3D_Array: """Return all points from this mobject and all submobjects. May contain duplicates; the order is in a depth-first (pre-order) traversal of the submobjects. """ return self.get_merged_array("points") # Getters def get_points_defining_boundary(self) -> Point3D_Array: return self.get_all_points() def get_num_points(self) -> int: return len(self.points) def get_extremum_along_dim( self, points: Point3DLike_Array | None = None, dim: int = 0, key: int = 0 ) -> float: np_points: Point3D_Array = ( self.get_points_defining_boundary() if points is None else np.asarray(points) ) values = np_points[:, dim] if key < 0: rv: float = np.min(values) return rv elif key == 0: rv = (np.min(values) + np.max(values)) / 2 return rv else: rv = np.max(values) return rv def get_critical_point(self, direction: Vector3DLike) -> Point3D: """Picture a box bounding the :class:`~.Mobject`. Such a box has 9 'critical points': 4 corners, 4 edge center, the center. This returns one of them, along the given direction. :: sample = Arc(start_angle=PI / 7, angle=PI / 5) # These are all equivalent max_y_1 = sample.get_top()[1] max_y_2 = sample.get_critical_point(UP)[1] max_y_3 = sample.get_extremum_along_dim(dim=1, key=1) """ result = np.zeros(self.dim) all_points = self.get_points_defining_boundary() if len(all_points) == 0: return result for dim in range(self.dim): result[dim] = self.get_extremum_along_dim( all_points, dim=dim, key=np.array(direction[dim]), ) return result # Pseudonyms for more general get_critical_point method def get_edge_center(self, direction: Vector3DLike) -> Point3D: """Get edge Point3Ds for certain direction.""" return self.get_critical_point(direction) def get_corner(self, direction: Vector3DLike) -> Point3D: """Get corner Point3Ds for certain direction.""" return self.get_critical_point(direction) def get_center(self) -> Point3D: """Get center Point3Ds""" return self.get_critical_point(np.zeros(self.dim)) def get_center_of_mass(self) -> Point3D: return np.apply_along_axis(np.mean, 0, self.get_all_points()) def get_boundary_point(self, direction: Vector3DLike) -> Point3D: all_points = self.get_points_defining_boundary() index = np.argmax(np.dot(all_points, direction)) return all_points[index] def get_midpoint(self) -> Point3D: """Get Point3Ds of the middle of the path that forms the :class:`~.Mobject`. Examples -------- .. manim:: AngleMidPoint :save_last_frame: class AngleMidPoint(Scene): def construct(self): line1 = Line(ORIGIN, 2*RIGHT) line2 = Line(ORIGIN, 2*RIGHT).rotate_about_origin(80*DEGREES) a = Angle(line1, line2, radius=1.5, other_angle=False) d = Dot(a.get_midpoint()).set_color(RED) self.add(line1, line2, a, d) self.wait() """ return self.point_from_proportion(0.5) def get_top(self) -> Point3D: """Get top Point3Ds of a box bounding the :class:`~.Mobject`""" return self.get_edge_center(UP) def get_bottom(self) -> Point3D: """Get bottom Point3Ds of a box bounding the :class:`~.Mobject`""" return self.get_edge_center(DOWN) def get_right(self) -> Point3D: """Get right Point3Ds of a box bounding the :class:`~.Mobject`""" return self.get_edge_center(RIGHT) def get_left(self) -> Point3D: """Get left Point3Ds of a box bounding the :class:`~.Mobject`""" return self.get_edge_center(LEFT) def get_zenith(self) -> Point3D: """Get zenith Point3Ds of a box bounding a 3D :class:`~.Mobject`.""" return self.get_edge_center(OUT) def get_nadir(self) -> Point3D: """Get nadir (opposite the zenith) Point3Ds of a box bounding a 3D :class:`~.Mobject`.""" return self.get_edge_center(IN) def length_over_dim(self, dim: int) -> float: """Measure the length of an :class:`~.Mobject` in a certain direction.""" max_coord: float = self.reduce_across_dimension( max, dim, ) min_coord: float = self.reduce_across_dimension(min, dim) return max_coord - min_coord def get_coord(self, dim: int, direction: Vector3DLike = ORIGIN) -> float: """Meant to generalize ``get_x``, ``get_y`` and ``get_z``""" return self.get_extremum_along_dim(dim=dim, key=np.array(direction)[dim]) def get_x(self, direction: Vector3DLike = ORIGIN) -> float: """Returns x Point3D of the center of the :class:`~.Mobject` as ``float``""" return self.get_coord(0, direction) def get_y(self, direction: Vector3DLike = ORIGIN) -> float: """Returns y Point3D of the center of the :class:`~.Mobject` as ``float``""" return self.get_coord(1, direction) def get_z(self, direction: Vector3DLike = ORIGIN) -> float: """Returns z Point3D of the center of the :class:`~.Mobject` as ``float``""" return self.get_coord(2, direction) def get_start(self) -> Point3D: """Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.""" self.throw_error_if_no_points() return np.array(self.points[0]) def get_end(self) -> Point3D: """Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.""" self.throw_error_if_no_points() return np.array(self.points[-1]) def get_start_and_end(self) -> tuple[Point3D, Point3D]: """Returns starting and ending point of a stroke as a ``tuple``.""" return self.get_start(), self.get_end() def point_from_proportion(self, alpha: float) -> Point3D: raise NotImplementedError("Please override in a child class.") def proportion_from_point(self, point: Point3DLike) -> float: raise NotImplementedError("Please override in a child class.") def get_pieces(self, n_pieces: float) -> Group: template = self.copy() template.submobjects = [] alphas = np.linspace(0, 1, n_pieces + 1) return Group( *( template.copy().pointwise_become_partial(self, a1, a2) for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True) ) ) def get_z_index_reference_point(self) -> Point3D: # TODO, better place to define default z_index_group? z_index_group = getattr(self, "z_index_group", self) return z_index_group.get_center() def has_points(self) -> bool: """Check if :class:`~.Mobject` contains points.""" return len(self.points) > 0 def has_no_points(self) -> bool: """Check if :class:`~.Mobject` *does not* contains points.""" return not self.has_points() # Match other mobject properties def match_color(self, mobject: Mobject) -> Self: """Match the color with the color of another :class:`~.Mobject`.""" return self.set_color(mobject.get_color()) def match_dim_size(self, mobject: Mobject, dim: int, **kwargs: Any) -> Self: """Match the specified dimension with the dimension of another :class:`~.Mobject`.""" return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs) def match_width(self, mobject: Mobject, **kwargs: Any) -> Self: """Match the width with the width of another :class:`~.Mobject`.""" return self.match_dim_size(mobject, 0, **kwargs) def match_height(self, mobject: Mobject, **kwargs: Any) -> Self: """Match the height with the height of another :class:`~.Mobject`.""" return self.match_dim_size(mobject, 1, **kwargs) def match_depth(self, mobject: Mobject, **kwargs: Any) -> Self: """Match the depth with the depth of another :class:`~.Mobject`.""" return self.match_dim_size(mobject, 2, **kwargs) def match_coord( self, mobject: Mobject, dim: int, direction: Vector3DLike = ORIGIN ) -> Self: """Match the Point3Ds with the Point3Ds of another :class:`~.Mobject`.""" return self.set_coord( mobject.get_coord(dim, direction), dim=dim, direction=direction, ) def match_x(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self: """Match x coord. to the x coord. of another :class:`~.Mobject`.""" return self.match_coord(mobject, 0, direction) def match_y(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self: """Match y coord. to the x coord. of another :class:`~.Mobject`.""" return self.match_coord(mobject, 1, direction) def match_z(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self: """Match z coord. to the x coord. of another :class:`~.Mobject`.""" return self.match_coord(mobject, 2, direction) def align_to( self, mobject_or_point: Mobject | Point3DLike, direction: Vector3DLike = ORIGIN, ) -> Self: """Aligns mobject to another :class:`~.Mobject` in a certain direction. Examples: mob1.align_to(mob2, UP) moves mob1 vertically so that its top edge lines ups with mob2's top edge. """ if isinstance(mobject_or_point, Mobject): point = mobject_or_point.get_critical_point(direction) else: point = mobject_or_point for dim in range(self.dim): if direction[dim] != 0: self.set_coord(point[dim], dim, direction) return self # Family matters def __getitem__(self, value: Any) -> Mobject | Group: self_list = self.split() if isinstance(value, slice): GroupClass = self.get_group_class() return GroupClass(*self_list.__getitem__(value)) rv: Mobject | Group = self_list.__getitem__(value) return rv def __iter__(self) -> Iterator[Mobject]: return iter(self.split()) def __len__(self) -> int: return len(self.split()) def get_group_class(self) -> type[Group]: return Group @staticmethod def get_mobject_type_class() -> type[Mobject]: """Return the base class of this mobject type.""" return Mobject def split(self) -> list[Mobject]: result: list[Mobject] = [self] if len(self.points) > 0 else [] return result + self.submobjects def get_family(self, recurse: bool = True) -> list[Mobject]: """Lists all mobjects in the hierarchy (family) of the given mobject, including the mobject itself and all its submobjects recursively. Parameters ---------- recurse Just for consistency with get_family method in OpenGLMobject. Returns ------- list[Mobject] A list of mobjects in the family of the given mobject. Examples -------- :: >>> from manim import Square, Rectangle, VGroup, Group, Mobject, VMobject >>> s, r, m, v = Square(), Rectangle(), Mobject(), VMobject() >>> vg = VGroup(s, r) >>> gr = Group(vg, m, v) >>> gr.get_family() [Group, VGroup(Square, Rectangle), Square, Rectangle, Mobject, VMobject] See also -------- :meth:`~.Mobject.family_members_with_points`, :meth:`~.Mobject.align_data` """ sub_families = [x.get_family() for x in self.submobjects] all_mobjects = [self] + list(it.chain(*sub_families)) return remove_list_redundancies(all_mobjects) def family_members_with_points(self) -> list[Mobject]: """Filters the list of family members (generated by :meth:`.get_family`) to include only mobjects with points. Returns ------- list[Mobject] A list of mobjects that have points. Examples -------- :: >>> from manim import Square, Rectangle, VGroup, Group, Mobject, VMobject >>> s, r, m, v = Square(), Rectangle(), Mobject(), VMobject() >>> vg = VGroup(s, r) >>> gr = Group(vg, m, v) >>> gr.family_members_with_points() [Square, Rectangle] See also -------- :meth:`~.Mobject.get_family` """ return [m for m in self.get_family() if m.get_num_points() > 0] def arrange( self, direction: Vector3DLike = RIGHT, buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER, center: bool = True, **kwargs: Any, ) -> Self: """Sorts :class:`~.Mobject` next to each other on screen. Examples -------- .. manim:: Example :save_last_frame: class Example(Scene): def construct(self): s1 = Square() s2 = Square() s3 = Square() s4 = Square() x = VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.0) self.add(x) """ for m1, m2 in zip(self.submobjects[:-1], self.submobjects[1:], strict=True): m2.next_to(m1, direction, buff, **kwargs) if center: self.center() return self def arrange_in_grid( self, rows: int | None = None, cols: int | None = None, buff: float | tuple[float, float] = MED_SMALL_BUFF, cell_alignment: Vector3DLike = ORIGIN, row_alignments: str | None = None, # "ucd" col_alignments: str | None = None, # "lcr" row_heights: Iterable[float | None] | None = None, col_widths: Iterable[float | None] | None = None, flow_order: str = "rd", **kwargs: Any, ) -> Self: """Arrange submobjects in a grid. Parameters ---------- rows The number of rows in the grid. cols The number of columns in the grid. buff The gap between grid cells. To specify a different buffer in the horizontal and vertical directions, a tuple of two values can be given - ``(row, col)``. cell_alignment The way each submobject is aligned in its grid cell. row_alignments The vertical alignment for each row (top to bottom). Accepts the following characters: ``"u"`` - up, ``"c"`` - center, ``"d"`` - down. col_alignments The horizontal alignment for each column (left to right). Accepts the following characters ``"l"`` - left, ``"c"`` - center, ``"r"`` - right. row_heights Defines a list of heights for certain rows (top to bottom). If the list contains ``None``, the corresponding row will fit its height automatically based on the highest element in that row. col_widths Defines a list of widths for certain columns (left to right). If the list contains ``None``, the corresponding column will fit its width automatically based on the widest element in that column. flow_order The order in which submobjects fill the grid. Can be one of the following values: "rd", "dr", "ld", "dl", "ru", "ur", "lu", "ul". ("rd" -> fill rightwards then downwards) Returns ------- :class:`Mobject` ``self`` Raises ------ ValueError If ``rows`` and ``cols`` are too small to fit all submobjects. ValueError If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`, :code:`row_alignments` and :code:`row_heights` have mismatching sizes. Notes ----- If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big enough to fit all submobjects. If neither is set, they will be chosen to be about the same, tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high). If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are defined, the latter has higher priority. Examples -------- .. manim:: ExampleBoxes :save_last_frame: class ExampleBoxes(Scene): def construct(self): boxes=VGroup(*[Square() for s in range(0,6)]) boxes.arrange_in_grid(rows=2, buff=0.1) self.add(boxes) .. manim:: ArrangeInGrid :save_last_frame: class ArrangeInGrid(Scene): def construct(self): boxes = VGroup(*[ Rectangle(WHITE, 0.5, 0.5).add(Text(str(i+1)).scale(0.5)) for i in range(24) ]) self.add(boxes) boxes.arrange_in_grid( buff=(0.25,0.5), col_alignments="lccccr", row_alignments="uccd", col_widths=[1, *[None]*4, 1], row_heights=[1, None, None, 1], flow_order="dr" ) """ from manim.mobject.geometry.line import Line mobs = self.submobjects.copy() start_pos = self.get_center() # get cols / rows values if given (implicitly) def init_size( num: int | None, alignments: str | None, sizes: Iterable[float | None] | None, ) -> int | None: if num is not None: return num if alignments is not None: return len(alignments) if sizes is not None: return len(list(sizes)) return None cols = init_size(cols, col_alignments, col_widths) rows = init_size(rows, row_alignments, row_heights) # calculate rows cols if rows is None and cols is None: cols = math.ceil(math.sqrt(len(mobs))) # make the grid as close to quadratic as possible. # choosing cols first can results in cols>rows. # This is favored over rows>cols since in general # the scene is wider than high. if rows is None: assert isinstance(cols, int) rows = math.ceil(len(mobs) / cols) if cols is None: cols = math.ceil(len(mobs) / rows) if rows * cols < len(mobs): raise ValueError("Too few rows and columns to fit all submobjetcs.") # rows and cols are now finally valid. if isinstance(buff, tuple): buff_x = buff[0] buff_y = buff[1] else: buff_x = buff_y = buff # Initialize alignments correctly def init_alignments( alignments: str | None, num: int, char_to_direction: dict[str, Vector3D], name: str, dir_: Vector3D, ) -> list[Vector3D]: if alignments is None: # Use cell_alignment as fallback return [cell_alignment * dir_] * num if len(alignments) != num: raise ValueError(f"{name}_alignments has a mismatching size.") alignment_directions = [char_to_direction[char] for char in alignments] return alignment_directions row_alignment_directions = init_alignments( row_alignments, rows, {"u": UP, "c": ORIGIN, "d": DOWN}, "row", RIGHT, ) col_alignment_directions = init_alignments( col_alignments, cols, {"l": LEFT, "c": ORIGIN, "r": RIGHT}, "col", UP, ) # Now row_alignment[r] + col_alignment[c] is the alignment in cell [r][c] mapper: dict[str, Callable[[int, int], int]] = { "dr": lambda r, c: (rows - r - 1) + c * rows, "dl": lambda r, c: (rows - r - 1) + (cols - c - 1) * rows, "ur": lambda r, c: r + c * rows, "ul": lambda r, c: r + (cols - c - 1) * rows, "rd": lambda r, c: (rows - r - 1) * cols + c, "ld": lambda r, c: (rows - r - 1) * cols + (cols - c - 1), "ru": lambda r, c: r * cols + c, "lu": lambda r, c: r * cols + (cols - c - 1), } if flow_order not in mapper: raise ValueError( 'flow_order must be one of the following values: "dr", "rd", "ld" "dl", "ru", "ur", "lu", "ul".', ) get_mob_index_by_position = mapper[flow_order] # Reverse row_alignment_directions and row_heights. Necessary since the # grid filling is handled bottom up for simplicity reasons. row_alignment_directions.reverse() row_heights_list = list(row_heights) if row_heights is not None else [] row_heights_list.reverse() col_widths_list = list(col_widths) if col_widths is not None else [] placeholder = Mobject() # Used to fill up the grid temporarily, doesn't get added to the scene. # In this case a Mobject is better than None since it has width and height # properties of 0. mobs.extend([placeholder] * (rows * cols - len(mobs))) grid = [ [mobs[get_mob_index_by_position(r, c)] for c in range(cols)] for r in range(rows) ] measured_heigths = [ max(grid[r][c].height for c in range(cols)) for r in range(rows) ] measured_widths = [ max(grid[r][c].width for r in range(rows)) for c in range(cols) ] # Initialize row_heights / col_widths correctly using measurements as fallback def init_sizes( sizes: list[float | None] | None, num: int, measures: list[float], name: str ) -> list[float]: if sizes is None or len(sizes) == 0: sizes = [None] * num if len(sizes) != num: raise ValueError(f"{name} has a mismatching size.") return [ size if size is not None else measure for size, measure in zip(sizes, measures, strict=False) ] heights = init_sizes(row_heights_list, rows, measured_heigths, "row_heights") widths = init_sizes(col_widths_list, cols, measured_widths, "col_widths") x, y = 0.0, 0.0 for r in range(rows): x = 0 for c in range(cols): if grid[r][c] is not placeholder: alignment = ( row_alignment_directions[r] + col_alignment_directions[c] ) line = Line( x * RIGHT + y * UP, (x + widths[c]) * RIGHT + (y + heights[r]) * UP, ) # Use a mobject to avoid rewriting align inside # box code that Mobject.move_to(Mobject) already # includes. grid[r][c].move_to(line, alignment) x += widths[c] + buff_x y += heights[r] + buff_y self.move_to(start_pos) return self def sort( self, point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0], submob_func: Callable[[Mobject], Any] | None = None, ) -> Self: """Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``.""" if submob_func is None: def submob_func(m: Mobject) -> float: return point_to_num_func(m.get_center()) self.submobjects.sort(key=submob_func) return self def shuffle(self, recursive: bool = False) -> None: """Shuffles the list of :attr:`submobjects`.""" if recursive: for submob in self.submobjects: submob.shuffle(recursive=True) random.shuffle(self.submobjects) def invert(self, recursive: bool = False) -> None: """Inverts the list of :attr:`submobjects`. Parameters ---------- recursive If ``True``, all submobject lists of this mobject's family are inverted. Examples -------- .. manim:: InvertSumobjectsExample class InvertSumobjectsExample(Scene): def construct(self): s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)]) s2 = s.copy() s2.invert() s2.shift(DOWN) self.play(Write(s), Write(s2)) """ if recursive: for submob in self.submobjects: submob.invert(recursive=True) self.submobjects.reverse() # Just here to keep from breaking old scenes. def arrange_submobjects(self, *args: Any, **kwargs: Any) -> Self: """Arrange the position of :attr:`submobjects` with a small buffer. Examples -------- .. manim:: ArrangeSumobjectsExample :save_last_frame: class ArrangeSumobjectsExample(Scene): def construct(self): s= VGroup(*[Dot().shift(i*0.1*RIGHT*np.random.uniform(-1,1)+UP*np.random.uniform(-1,1)) for i in range(0,15)]) s.shift(UP).set_color(BLUE) s2= s.copy().set_color(RED) s2.arrange_submobjects() s2.shift(DOWN) self.add(s,s2) """ return self.arrange(*args, **kwargs) def sort_submobjects(self, *args: Any, **kwargs: Any) -> Self: """Sort the :attr:`submobjects`""" return self.sort(*args, **kwargs) def shuffle_submobjects(self, *args: Any, **kwargs: Any) -> None: """Shuffles the order of :attr:`submobjects` Examples -------- .. manim:: ShuffleSubmobjectsExample class ShuffleSubmobjectsExample(Scene): def construct(self): s= VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)]) s2= s.copy() s2.shuffle_submobjects() s2.shift(DOWN) self.play(Write(s), Write(s2)) """ return self.shuffle(*args, **kwargs) # Alignment def align_data(self, mobject: Mobject, skip_point_alignment: bool = False) -> None: """Aligns the family structure and data of this mobject with another mobject. Afterwards, the two mobjects will have the same number of submobjects (see :meth:`.align_submobjects`) and the same parent structure (see :meth:`.null_point_align`). If ``skip_point_alignment`` is ``False``, they will also have the same number of points (see :meth:`.align_points`). Parameters ---------- mobject The other mobject this mobject should be aligned to. skip_point_alignment Controls whether or not the computationally expensive point alignment is skipped (default: ``False``). .. note:: This method is primarily used internally by :meth:`.become` and the :class:`~.Transform` animation to ensure that mobjects are structurally compatible before transformation. Examples -------- :: >>> from manim import Rectangle, Line, ORIGIN, RIGHT >>> rect = Rectangle(width=4.0, height=2.0, grid_xstep=1.0, grid_ystep=0.5) >>> line = Line(start=ORIGIN,end=RIGHT) >>> line.align_data(rect) >>> len(line.get_family()) == len(rect.get_family()) True >>> line.get_num_points() == rect.get_num_points() True See also -------- :class:`~.Transform`, :meth:`~.Mobject.become`, :meth:`~.VMobject.align_points`, :meth:`~.Mobject.get_family` """ self.null_point_align(mobject) self.align_submobjects(mobject) if not skip_point_alignment: self.align_points(mobject) # Recurse for m1, m2 in zip(self.submobjects, mobject.submobjects, strict=True): m1.align_data(m2) def get_point_mobject(self, center: Point3DLike | None = None) -> Point: """The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type """ msg = f"get_point_mobject not implemented for {self.__class__.__name__}" raise NotImplementedError(msg) def align_points(self, mobject: Mobject) -> Self: count1 = self.get_num_points() count2 = mobject.get_num_points() if count1 < count2: self.align_points_with_larger(mobject) elif count2 < count1: mobject.align_points_with_larger(self) return self def align_points_with_larger(self, larger_mobject: Mobject) -> None: raise NotImplementedError("Please override in a child class.") def align_submobjects(self, mobject: Mobject) -> Self: mob1 = self mob2 = mobject n1 = len(mob1.submobjects) n2 = len(mob2.submobjects) mob1.add_n_more_submobjects(max(0, n2 - n1)) mob2.add_n_more_submobjects(max(0, n1 - n2)) return self def null_point_align(self, mobject: Mobject) -> Self: """If a :class:`~.Mobject` with points is being aligned to one without, treat both as groups, and push the one with points into its own submobjects list. Returns ------- :class:`Mobject` ``self`` """ for m1, m2 in (self, mobject), (mobject, self): if m1.has_no_points() and m2.has_points(): m2.push_self_into_submobjects() return self def push_self_into_submobjects(self) -> Self: copy = self.copy() copy.submobjects = [] self.reset_points() self.add(copy) return self def add_n_more_submobjects(self, n: int) -> Self | None: if n == 0: return None curr = len(self.submobjects) if curr == 0: # If empty, simply add n point mobjects self.submobjects = [self.get_point_mobject() for k in range(n)] return None target = curr + n # TODO, factor this out to utils so as to reuse # with VMobject.insert_n_curves repeat_indices = (np.arange(target) * curr) // target split_factors = [sum(repeat_indices == i) for i in range(curr)] new_submobs = [] for submob, sf in zip(self.submobjects, split_factors, strict=True): new_submobs.append(submob) new_submobs.extend(submob.copy().fade(1) for _ in range(1, sf)) self.submobjects = new_submobs return self def repeat_submobject(self, submob: Mobject) -> Mobject: return submob.copy() def interpolate( self, mobject1: Mobject, mobject2: Mobject, alpha: float, path_func: PathFuncType = straight_path(), ) -> Self: """Turns this :class:`~.Mobject` into an interpolation between ``mobject1`` and ``mobject2``. The interpolation is applied to the points and color of the mobject. Parameters ---------- mobject1 The starting Mobject. mobject2 The target Mobject. alpha Interpolation factor between 0 (at ``mobject1``) and 1 (at ``mobject2``). path_func The function defining the interpolation path. Defaults to a straight path. Returns ------- :class:`Mobject` ``self`` .. note:: - Both mobjects must have the same number of points. If not, this will raise an error. Use :meth:`~.VMobject.align_points` to match point counts beforehand if needed. - This method is used internally by the :class:`~.Transform` animation to interpolate between two mobjects during a transformation. Examples -------- .. manim:: InterpolateExample :save_last_frame: class InterpolateExample(Scene): def construct(self): # No need for point alignment: dotL = Dot(color=DARK_GREY).to_edge(LEFT) dotR = Dot(color=YELLOW).scale(10).to_edge(RIGHT) dotMid1 = VMobject().interpolate(dotL, dotR, alpha=0.1) dotMid2 = VMobject().interpolate(dotL, dotR, alpha=0.25) dotMid3 = VMobject().interpolate(dotL, dotR, alpha=0.5) dotMid4 = VMobject().interpolate(dotL, dotR, alpha=0.75) dots = VGroup(dotL, dotR, dotMid1, dotMid2, dotMid3, dotMid4) # Needs point alignment: line = Line(ORIGIN, UP).to_edge(LEFT) sq = Square(color=RED, fill_opacity=1, stroke_color=BLUE).to_edge(RIGHT) line.align_points(sq) mid1 = VMobject().interpolate(line, sq, alpha=0.1) mid2 = VMobject().interpolate(line, sq, alpha=0.25) mid3 = VMobject().interpolate(line, sq, alpha=0.5) mid4 = VMobject().interpolate(line, sq, alpha=0.75) linesquares = VGroup(line, sq, mid1, mid2, mid3, mid4) self.add(VGroup(dots, linesquares).arrange(DOWN, buff=1)) See also -------- :class:`~.Transform`, :meth:`~.VMobject.align_points`, :meth:`~.VMobject.interpolate_color` """ self.points = path_func(mobject1.points, mobject2.points, alpha) self.interpolate_color(mobject1, mobject2, alpha) return self def interpolate_color( self, mobject1: Mobject, mobject2: Mobject, alpha: float ) -> None: raise NotImplementedError("Please override in a child class.") def become( self, mobject: Mobject, match_height: bool = False, match_width: bool = False, match_depth: bool = False, match_center: bool = False, stretch: bool = False, ) -> Self: """Edit points, colors and submobjects to be identical to another :class:`~.Mobject` .. note:: If both match_height and match_width are ``True`` then the transformed :class:`~.Mobject` will match the height first and then the width. Parameters ---------- match_height Whether or not to preserve the height of the original :class:`~.Mobject`. match_width Whether or not to preserve the width of the original :class:`~.Mobject`. match_depth Whether or not to preserve the depth of the original :class:`~.Mobject`. match_center Whether or not to preserve the center of the original :class:`~.Mobject`. stretch Whether or not to stretch the target mobject to match the the proportions of the original :class:`~.Mobject`. Examples -------- .. manim:: BecomeScene class BecomeScene(Scene): def construct(self): circ = Circle(fill_color=RED, fill_opacity=0.8) square = Square(fill_color=BLUE, fill_opacity=0.2) self.add(circ) self.wait(0.5) circ.become(square) self.wait(0.5) The following examples illustrate how mobject measurements change when using the ``match_...`` and ``stretch`` arguments. We start with a rectangle that is 2 units high and 4 units wide, which we want to turn into a circle of radius 3:: >>> from manim import Rectangle, Circle >>> import numpy as np >>> rect = Rectangle(height=2, width=4) >>> circ = Circle(radius=3) With ``stretch=True``, the target circle is deformed to match the proportions of the rectangle, which results in the target mobject being an ellipse with height 2 and width 4. We can check that the resulting points satisfy the ellipse equation :math:`x^2/a^2 + y^2/b^2 = 1` with :math:`a = 4/2` and :math:`b = 2/2` being the semi-axes:: >>> result = rect.copy().become(circ, stretch=True) >>> result.height, result.width (np.float64(2.0), np.float64(4.0)) >>> ellipse_points = np.array(result.get_anchors()) >>> ellipse_eq = np.sum(ellipse_points**2 * [1/4, 1, 0], axis=1) >>> np.allclose(ellipse_eq, 1) True With ``match_height=True`` and ``match_width=True`` the circle is scaled such that the height or the width of the rectangle will be preserved, respectively. The points of the resulting mobject satisfy the circle equation :math:`x^2 + y^2 = r^2` for the corresponding radius :math:`r`:: >>> result = rect.copy().become(circ, match_height=True) >>> result.height, result.width (np.float64(2.0), np.float64(2.0)) >>> circle_points = np.array(result.get_anchors()) >>> circle_eq = np.sum(circle_points**2, axis=1) >>> np.allclose(circle_eq, 1) True >>> result = rect.copy().become(circ, match_width=True) >>> result.height, result.width (np.float64(4.0), np.float64(4.0)) >>> circle_points = np.array(result.get_anchors()) >>> circle_eq = np.sum(circle_points**2, axis=1) >>> np.allclose(circle_eq, 2**2) True With ``match_center=True``, the resulting mobject is moved such that its center is the same as the center of the original mobject:: >>> rect = rect.shift(np.array([0, 1, 0])) >>> np.allclose(rect.get_center(), circ.get_center()) False >>> result = rect.copy().become(circ, match_center=True) >>> np.allclose(rect.get_center(), result.get_center()) True See also -------- :meth:`~.Mobject.align_data`, :meth:`~.VMobject.interpolate_color` """ if stretch or match_height or match_width or match_depth or match_center: mobject = mobject.copy() if stretch: mobject.stretch_to_fit_height(self.height) mobject.stretch_to_fit_width(self.width) mobject.stretch_to_fit_depth(self.depth) else: if match_height: mobject.match_height(self) if match_width: mobject.match_width(self) if match_depth: mobject.match_depth(self) if match_center: mobject.move_to(self.get_center()) self.align_data(mobject, skip_point_alignment=True) for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=True): sm1.points = np.array(sm2.points) sm1.interpolate_color(sm1, sm2, 1) return self def match_points(self, mobject: Mobject, copy_submobjects: bool = True) -> Self: """Edit points, positions, and submobjects to be identical to another :class:`~.Mobject`, while keeping the style unchanged. Examples -------- .. manim:: MatchPointsScene class MatchPointsScene(Scene): def construct(self): circ = Circle(fill_color=RED, fill_opacity=0.8) square = Square(fill_color=BLUE, fill_opacity=0.2) self.add(circ) self.wait(0.5) self.play(circ.animate.match_points(square)) self.wait(0.5) """ for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=False): sm1.points = np.array(sm2.points) return self # Errors def throw_error_if_no_points(self) -> None: if self.has_no_points(): caller_name = sys._getframe(1).f_code.co_name raise Exception( f"Cannot call Mobject.{caller_name} for a Mobject with no points", ) # About z-index def set_z_index( self, z_index_value: float, family: bool = True, ) -> Self: """Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`. Parameters ---------- z_index_value The new value of :attr:`z_index` set. family If ``True``, the :attr:`z_index` value of all submobjects is also set. Returns ------- :class:`Mobject` The Mobject itself, after :attr:`z_index` is set. For chaining purposes. (Returns `self`.) Examples -------- .. manim:: SetZIndex :save_last_frame: class SetZIndex(Scene): def construct(self): text = Text('z_index = 3', color = PURE_RED).shift(UP).set_z_index(3) square = Square(2, fill_opacity=1).set_z_index(2) tex = Tex(r'zIndex = 1', color = PURE_BLUE).shift(DOWN).set_z_index(1) circle = Circle(radius = 1.7, color = GREEN, fill_opacity = 1) # z_index = 0 # Displaying order is now defined by z_index values self.add(text) self.add(square) self.add(tex) self.add(circle) """ if family: for submob in self.submobjects: submob.set_z_index(z_index_value, family=family) self.z_index = z_index_value return self def set_z_index_by_z_Point3D(self) -> Self: """Sets the :class:`~.Mobject`'s z Point3D to the value of :attr:`z_index`. Returns ------- :class:`Mobject` The Mobject itself, after :attr:`z_index` is set. (Returns `self`.) """ z_coord = self.get_center()[-1] self.set_z_index(z_coord) return self class Group(Mobject, metaclass=ConvertToOpenGL): """Groups together multiple :class:`Mobjects <.Mobject>`. Notes ----- When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group. """ def __init__(self, *mobjects: Any, **kwargs: Any) -> None: super().__init__(**kwargs) self.add(*mobjects) class _AnimationBuilder: def __init__(self, mobject: Mobject) -> None: self.mobject = mobject self.mobject.generate_target() self.overridden_animation: Animation | None = None self.is_chaining = False self.methods: list[MethodWithArgs] = [] # Whether animation args can be passed self.cannot_pass_args = False self.anim_args: dict[str, Any] = {} def __call__(self, **kwargs: Any) -> Self: if self.cannot_pass_args: raise ValueError( "Animation arguments must be passed before accessing methods and can only be passed once", ) self.anim_args = kwargs self.cannot_pass_args = True return self def __getattr__(self, method_name: str) -> Callable[..., _AnimationBuilder]: method = getattr(self.mobject.target, method_name) has_overridden_animation = hasattr(method, "_override_animate") if (self.is_chaining and has_overridden_animation) or self.overridden_animation: raise NotImplementedError( "Method chaining is currently not supported for overridden animations", ) def update_target(*method_args: Any, **method_kwargs: Any) -> _AnimationBuilder: if has_overridden_animation: self.overridden_animation = method._override_animate( self.mobject, *method_args, anim_args=self.anim_args, **method_kwargs, ) else: self.methods.append(MethodWithArgs(method, method_args, method_kwargs)) method(*method_args, **method_kwargs) return self self.is_chaining = True self.cannot_pass_args = True return update_target def build(self) -> Animation: from ..animation.transform import _MethodAnimation anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods) for attr, value in self.anim_args.items(): setattr(anim, attr, value) return anim class _UpdaterBuilder: """Syntactic sugar for adding updaters to mobjects.""" def __init__(self, mobject: Mobject): self._mobject = mobject def __getattr__(self, name: str, /) -> Callable[..., _UpdaterBuilder]: # just return a function that will add the updater def add_updater(*method_args: Any, **method_kwargs: Any) -> _UpdaterBuilder: self._mobject.add_updater( lambda m: getattr(m, name)(*method_args, **method_kwargs), call_updater=True, ) return self return add_updater def override_animate( method: types.MethodType, ) -> Callable[[types.MethodType], types.MethodType]: r"""Decorator for overriding method animations. This allows to specify a method (returning an :class:`~.Animation`) which is called when the decorated method is used with the ``.animate`` syntax for animating the application of a method. .. seealso:: :attr:`~.Mobject.animate` .. note:: Overridden methods cannot be combined with normal or other overridden methods using method chaining with the ``.animate`` syntax. Examples -------- .. manim:: AnimationOverrideExample class CircleWithContent(VGroup): def __init__(self, content): super().__init__() self.circle = Circle() self.content = content self.add(self.circle, content) content.move_to(self.circle.get_center()) def clear_content(self): self.remove(self.content) self.content = None @override_animate(clear_content) def _clear_content_animation(self, anim_args=None): if anim_args is None: anim_args = {} anim = Uncreate(self.content, **anim_args) self.clear_content() return anim class AnimationOverrideExample(Scene): def construct(self): t = Text("hello!") my_mobject = CircleWithContent(t) self.play(Create(my_mobject)) self.play(my_mobject.animate.clear_content()) self.wait() """ temp_method = cast(_AnimationBuilder, method) def decorator(animation_method: types.MethodType) -> types.MethodType: # error: "Callable[..., Animation]" has no attribute "_override_animate" [attr-defined] temp_method._override_animate = animation_method # type: ignore[attr-defined] return animation_method return decorator ================================================ FILE: manim/mobject/opengl/__init__.py ================================================ ================================================ FILE: manim/mobject/opengl/dot_cloud.py ================================================ from __future__ import annotations __all__ = ["TrueDot", "DotCloud"] from typing import Any, Self import numpy as np from manim.constants import ORIGIN, RIGHT, UP from manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject from manim.typing import Point3DLike from manim.utils.color import PURE_YELLOW, ParsableManimColor class DotCloud(OpenGLPMobject): def __init__( self, color: ParsableManimColor = PURE_YELLOW, stroke_width: float = 2.0, radius: float = 2.0, density: float = 10, **kwargs: Any, ): self.radius = radius self.epsilon = 1.0 / density super().__init__( stroke_width=stroke_width, density=density, color=color, **kwargs ) def init_points(self) -> None: self.points = np.array( [ r * (np.cos(theta) * RIGHT + np.sin(theta) * UP) for r in np.arange(self.epsilon, self.radius, self.epsilon) # Num is equal to int(stop - start)/ (step + 1) reformulated. for theta in np.linspace( 0, 2 * np.pi, num=int(2 * np.pi * (r + self.epsilon) / self.epsilon), ) ], dtype=np.float32, ) def make_3d(self, gloss: float = 0.5, shadow: float = 0.2) -> Self: self.set_gloss(gloss) self.set_shadow(shadow) self.apply_depth_test() return self class TrueDot(DotCloud): def __init__( self, center: Point3DLike = ORIGIN, stroke_width: float = 2.0, **kwargs: Any ): self.radius = stroke_width super().__init__(points=[center], stroke_width=stroke_width, **kwargs) ================================================ FILE: manim/mobject/opengl/opengl_compatibility.py ================================================ from __future__ import annotations from abc import ABCMeta from typing import Any from manim import config from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject from manim.mobject.opengl.opengl_three_dimensions import OpenGLSurface from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from ...constants import RendererType __all__ = ["ConvertToOpenGL"] class ConvertToOpenGL(ABCMeta): """Metaclass for swapping (V)Mobject with its OpenGL counterpart at runtime depending on config.renderer. This metaclass should only need to be inherited on the lowest order inheritance classes such as Mobject and VMobject. """ _converted_classes: list[type] = [] def __new__( mcls, name: str, bases: tuple[type, ...], namespace: dict[str, Any] ) -> type: if config.renderer == RendererType.OPENGL: # Must check class names to prevent # cyclic importing. base_names_to_opengl: dict[str, type] = { "Mobject": OpenGLMobject, "VMobject": OpenGLVMobject, "PMobject": OpenGLPMobject, "Mobject1D": OpenGLPMobject, "Mobject2D": OpenGLPMobject, "Surface": OpenGLSurface, } bases = tuple( base_names_to_opengl.get(base.__name__, base) for base in bases ) return super().__new__(mcls, name, bases, namespace) def __init__(cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]): super().__init__(name, bases, namespace) cls._converted_classes.append(cls) ================================================ FILE: manim/mobject/opengl/opengl_geometry.py ================================================ from __future__ import annotations from typing import Any, Self, cast import numpy as np from manim.constants import * from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_vectorized_mobject import ( OpenGLDashedVMobject, OpenGLMobject, OpenGLVGroup, OpenGLVMobject, ) from manim.typing import ( Point3D, Point3D_Array, Point3DLike, QuadraticSpline, Vector2DLike, Vector3D, Vector3DLike, ) from manim.utils.color import * from manim.utils.iterables import adjacent_n_tuples, adjacent_pairs from manim.utils.simple_functions import clip from manim.utils.space_ops import ( angle_between_vectors, angle_of_vector, compass_directions, find_intersection, normalize, rotate_vector, rotation_matrix_transpose, ) DEFAULT_DOT_RADIUS = 0.08 DEFAULT_DASH_LENGTH = 0.05 DEFAULT_ARROW_TIP_LENGTH = 0.35 DEFAULT_ARROW_TIP_WIDTH = 0.35 __all__ = [ "OpenGLTipableVMobject", "OpenGLArc", "OpenGLArcBetweenPoints", "OpenGLCurvedArrow", "OpenGLCurvedDoubleArrow", "OpenGLCircle", "OpenGLDot", "OpenGLEllipse", "OpenGLAnnularSector", "OpenGLSector", "OpenGLAnnulus", "OpenGLLine", "OpenGLDashedLine", "OpenGLTangentLine", "OpenGLElbow", "OpenGLArrow", "OpenGLVector", "OpenGLDoubleArrow", "OpenGLCubicBezier", "OpenGLPolygon", "OpenGLRegularPolygon", "OpenGLTriangle", "OpenGLArrowTip", ] class OpenGLTipableVMobject(OpenGLVMobject): """ Meant for shared functionality between Arc and Line. Functionality can be classified broadly into these groups: * Adding, Creating, Modifying tips - add_tip calls create_tip, before pushing the new tip into the TipableVMobject's list of submobjects - stylistic and positional configuration * Checking for tips - Boolean checks for whether the TipableVMobject has a tip and a starting tip * Getters - Straightforward accessors, returning information pertaining to the TipableVMobject instance's tip(s), its length etc """ # Adding, Creating, Modifying tips def __init__( self, tip_length: float = DEFAULT_ARROW_TIP_LENGTH, normal_vector: Vector3DLike = OUT, tip_config: dict[str, Any] = {}, **kwargs: Any, ): self.tip_length = tip_length self.normal_vector = normal_vector self.tip_config = tip_config super().__init__(**kwargs) def add_tip(self, at_start: bool = False, **kwargs: Any) -> Self: """ Adds a tip to the TipableVMobject instance, recognising that the endpoints might need to be switched if it's a 'starting tip' or not. """ tip = self.create_tip(at_start, **kwargs) self.reset_endpoints_based_on_tip(tip, at_start) self.assign_tip_attr(tip, at_start) self.add(tip) return self def create_tip(self, at_start: bool = False, **kwargs: Any) -> OpenGLArrowTip: """ Stylises the tip, positions it spacially, and returns the newly instantiated tip to the caller. """ tip = self.get_unpositioned_tip(**kwargs) self.position_tip(tip, at_start) return tip def get_unpositioned_tip(self, **kwargs: Any) -> OpenGLArrowTip: """ Returns a tip that has been stylistically configured, but has not yet been given a position in space. """ config = {} config.update(self.tip_config) config.update(kwargs) return OpenGLArrowTip(**config) def position_tip( self, tip: OpenGLArrowTip, at_start: bool = False ) -> OpenGLArrowTip: # Last two control points, defining both # the end, and the tangency direction if at_start: anchor = self.get_start() handle = self.get_first_handle() else: handle = self.get_last_handle() anchor = self.get_end() tip.rotate(angle_of_vector(handle - anchor) - PI - tip.get_angle()) tip.shift(anchor - tip.get_tip_point()) return tip def reset_endpoints_based_on_tip(self, tip: OpenGLArrowTip, at_start: bool) -> Self: if self.get_length() == 0: # Zero length, put_start_and_end_on wouldn't # work return self if at_start: start = tip.get_base() end = self.get_end() else: start = self.get_start() end = tip.get_base() self.put_start_and_end_on(start, end) return self def assign_tip_attr(self, tip: OpenGLArrowTip, at_start: bool) -> Self: if at_start: self.start_tip = tip else: self.tip = tip return self # Checking for tips def has_tip(self) -> bool: return hasattr(self, "tip") and self.tip in self def has_start_tip(self) -> bool: return hasattr(self, "start_tip") and self.start_tip in self # Getters def pop_tips(self) -> OpenGLVGroup: start, end = self.get_start_and_end() result = OpenGLVGroup() if self.has_tip(): result.add(self.tip) self.remove(self.tip) if self.has_start_tip(): result.add(self.start_tip) self.remove(self.start_tip) self.put_start_and_end_on(start, end) return result def get_tips(self) -> OpenGLVGroup: """ Returns a VGroup (collection of VMobjects) containing the TipableVMObject instance's tips. """ result = OpenGLVGroup() if hasattr(self, "tip"): result.add(self.tip) if hasattr(self, "start_tip"): result.add(self.start_tip) return result def get_tip(self) -> OpenGLArrowTip: """Returns the TipableVMobject instance's (first) tip, otherwise throws an exception. """ tips = self.get_tips() if len(tips) == 0: raise Exception("tip not found") else: rv = cast(OpenGLArrowTip, tips[0]) return rv def get_default_tip_length(self) -> float: return self.tip_length def get_first_handle(self) -> Point3D: return self.points[1] def get_last_handle(self) -> Point3D: return self.points[-2] def get_end(self) -> Point3D: if self.has_tip(): return self.tip.get_start() else: return super().get_end() def get_start(self) -> Point3D: if self.has_start_tip(): return self.start_tip.get_start() else: return super().get_start() def get_length(self) -> float: start, end = self.get_start_and_end() rv: float = np.linalg.norm(start - end) return rv class OpenGLArc(OpenGLTipableVMobject): def __init__( self, start_angle: float = 0, angle: float = TAU / 4, radius: float = 1.0, n_components: int = 8, arc_center: Point3DLike = ORIGIN, **kwargs: Any, ): self.start_angle = start_angle self.angle = angle self.radius = radius self.n_components = n_components self.arc_center = arc_center super().__init__(**kwargs) self.orientation = -1 def init_points(self) -> None: self.set_points( OpenGLArc.create_quadratic_bezier_points( angle=self.angle, start_angle=self.start_angle, n_components=self.n_components, ), ) # To maintain proper orientation for fill shaders. self.scale(self.radius, about_point=ORIGIN) self.shift(self.arc_center) @staticmethod def create_quadratic_bezier_points( angle: float, start_angle: float = 0, n_components: int = 8 ) -> QuadraticSpline: samples = np.array( [ [np.cos(a), np.sin(a), 0] for a in np.linspace( start_angle, start_angle + angle, 2 * n_components + 1, ) ], ) theta = angle / n_components samples[1::2] /= np.cos(theta / 2) points = np.zeros((3 * n_components, 3)) points[0::3] = samples[0:-1:2] points[1::3] = samples[1::2] points[2::3] = samples[2::2] return points def get_arc_center(self) -> Point3D: """ Looks at the normals to the first two anchors, and finds their intersection points """ # First two anchors and handles a1, h, a2 = self.points[:3] # Tangent vectors t1 = h - a1 t2 = h - a2 # Normals n1 = rotate_vector(t1, TAU / 4) n2 = rotate_vector(t2, TAU / 4) return find_intersection(a1, n1, a2, n2) def get_start_angle(self) -> float: angle = angle_of_vector(self.get_start() - self.get_arc_center()) rv: float = angle % TAU return rv def get_stop_angle(self) -> float: angle = angle_of_vector(self.get_end() - self.get_arc_center()) rv: float = angle % TAU return rv def move_arc_center_to(self, point: Point3DLike) -> Self: self.shift(point - self.get_arc_center()) return self class OpenGLArcBetweenPoints(OpenGLArc): def __init__( self, start: Point3DLike, end: Point3DLike, angle: float = TAU / 4, **kwargs: Any, ): super().__init__(angle=angle, **kwargs) if angle == 0: self.set_points_as_corners([LEFT, RIGHT]) self.put_start_and_end_on(start, end) class OpenGLCurvedArrow(OpenGLArcBetweenPoints): def __init__(self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any): super().__init__(start_point, end_point, **kwargs) self.add_tip() class OpenGLCurvedDoubleArrow(OpenGLCurvedArrow): def __init__(self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any): super().__init__(start_point, end_point, **kwargs) self.add_tip(at_start=True) class OpenGLCircle(OpenGLArc): def __init__(self, color: ParsableManimColor = RED, **kwargs: Any): super().__init__(0, TAU, color=color, **kwargs) def surround( self, mobject: OpenGLMobject, dim_to_match: int = 0, stretch: bool = False, buff: float = MED_SMALL_BUFF, ) -> Self: # Ignores dim_to_match and stretch; result will always be a circle # TODO: Perhaps create an ellipse class to handle singele-dimension stretching self.replace(mobject, dim_to_match, stretch) self.stretch((self.get_width() + 2 * buff) / self.get_width(), 0) self.stretch((self.get_height() + 2 * buff) / self.get_height(), 1) return self def point_at_angle(self, angle: float) -> Point3D: start_angle = self.get_start_angle() return self.point_from_proportion((angle - start_angle) / TAU) class OpenGLDot(OpenGLCircle): def __init__( self, point: Point3DLike = ORIGIN, radius: float = DEFAULT_DOT_RADIUS, stroke_width: float = 0, fill_opacity: float = 1.0, color: ParsableManimColor = WHITE, **kwargs: Any, ): super().__init__( arc_center=point, radius=radius, stroke_width=stroke_width, fill_opacity=fill_opacity, color=color, **kwargs, ) class OpenGLEllipse(OpenGLCircle): def __init__(self, width: float = 2, height: float = 1, **kwargs: Any): super().__init__(**kwargs) self.set_width(width, stretch=True) self.set_height(height, stretch=True) class OpenGLAnnularSector(OpenGLArc): def __init__( self, inner_radius: float = 1, outer_radius: float = 2, angle: float = TAU / 4, start_angle: float = 0, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, **kwargs: Any, ): self.inner_radius = inner_radius self.outer_radius = outer_radius super().__init__( start_angle=start_angle, angle=angle, fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs, ) def init_points(self) -> None: inner_arc, outer_arc = ( OpenGLArc( start_angle=self.start_angle, angle=self.angle, radius=radius, arc_center=self.arc_center, ) for radius in (self.inner_radius, self.outer_radius) ) outer_arc.reverse_points() self.append_points(inner_arc.points) self.add_line_to(outer_arc.points[0]) self.append_points(outer_arc.points) self.add_line_to(inner_arc.points[0]) class OpenGLSector(OpenGLAnnularSector): def __init__(self, outer_radius: float = 1, inner_radius: float = 0, **kwargs: Any): super().__init__(inner_radius=inner_radius, outer_radius=outer_radius, **kwargs) class OpenGLAnnulus(OpenGLCircle): def __init__( self, inner_radius: float = 1, outer_radius: float = 2, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, mark_paths_closed: bool = False, **kwargs: Any, ): self.mark_paths_closed = mark_paths_closed # is this even used? self.inner_radius = inner_radius self.outer_radius = outer_radius super().__init__( fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs ) def init_points(self) -> None: self.radius = self.outer_radius outer_circle = OpenGLCircle(radius=self.outer_radius) inner_circle = OpenGLCircle(radius=self.inner_radius) inner_circle.reverse_points() self.append_points(outer_circle.points) self.append_points(inner_circle.points) self.shift(self.arc_center) class OpenGLLine(OpenGLTipableVMobject): def __init__( self, start: Point3DLike = LEFT, end: Point3DLike = RIGHT, buff: float = 0, path_arc: float = 0, **kwargs: Any, ): self.dim = 3 self.buff = buff self.path_arc = path_arc self.set_start_and_end_attrs(start, end) super().__init__(**kwargs) def init_points(self) -> None: self.set_points_by_ends(self.start, self.end, self.buff, self.path_arc) def set_points_by_ends( self, start: Point3DLike, end: Point3DLike, buff: float = 0, path_arc: float = 0 ) -> None: if path_arc: self.set_points(OpenGLArc.create_quadratic_bezier_points(path_arc)) self.put_start_and_end_on(start, end) else: self.set_points_as_corners([start, end]) self.account_for_buff(self.buff) def set_path_arc(self, new_value: float) -> None: self.path_arc = new_value self.init_points() def account_for_buff(self, buff: float) -> Self: if buff == 0: return self # length = self.get_length() if self.path_arc == 0 else self.get_arc_length() # if length < 2 * buff: return self buff_prop = buff / length self.pointwise_become_partial(self, buff_prop, 1 - buff_prop) return self def set_start_and_end_attrs( self, start: Mobject | Point3DLike, end: Mobject | Point3DLike ) -> None: # If either start or end are Mobjects, this # gives their centers rough_start = self.pointify(start) rough_end = self.pointify(end) vect = normalize(rough_end - rough_start) # Now that we know the direction between them, # we can find the appropriate boundary point from # start and end, if they're mobjects self.start = self.pointify(start, vect) + self.buff * vect self.end = self.pointify(end, -vect) - self.buff * vect def pointify( self, mob_or_point: Mobject | Point3DLike, direction: Vector3DLike = None ) -> Point3D: """ Take an argument passed into Line (or subclass) and turn it into a 3d point. """ if isinstance(mob_or_point, Mobject): mob = mob_or_point if direction is None: return mob.get_center() else: return mob.get_continuous_bounding_box_point(direction) else: point = mob_or_point result = np.zeros(self.dim) result[: len(point)] = point return result def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self: curr_start, curr_end = self.get_start_and_end() if (curr_start == curr_end).all(): self.set_points_by_ends(start, end, self.path_arc) return super().put_start_and_end_on(start, end) def get_vector(self) -> Vector3D: return self.get_end() - self.get_start() def get_unit_vector(self) -> Vector3D: return normalize(self.get_vector()) def get_angle(self) -> float: return angle_of_vector(self.get_vector()) def get_projection(self, point: Point3DLike) -> Point3D: """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 def get_slope(self) -> float: rv: float = np.tan(self.get_angle()) return rv def set_angle(self, angle: float, about_point: Point3DLike | None = None) -> Self: if about_point is None: about_point = self.get_start() self.rotate( angle - self.get_angle(), about_point=about_point, ) return self def set_length(self, length: float) -> None: self.scale(length / self.get_length()) class OpenGLDashedLine(OpenGLLine): def __init__( self, *args: Any, dash_length: float = DEFAULT_DASH_LENGTH, dashed_ratio: float = 0.5, **kwargs: Any, ): self.dashed_ratio = dashed_ratio self.dash_length = dash_length super().__init__(*args, **kwargs) dashed_ratio = self.dashed_ratio num_dashes = self.calculate_num_dashes(dashed_ratio) dashes = OpenGLDashedVMobject( self, num_dashes=num_dashes, dashed_ratio=dashed_ratio, ) self.clear_points() self.add(*dashes) def calculate_num_dashes(self, dashed_ratio: float) -> int: return max( 2, int(np.ceil((self.get_length() / self.dash_length) * dashed_ratio)), ) def get_start(self) -> Point3D: if len(self.submobjects) > 0: return self.submobjects[0].get_start() else: return super().get_start() def get_end(self) -> Point3D: if len(self.submobjects) > 0: return self.submobjects[-1].get_end() else: return super().get_end() def get_first_handle(self) -> Point3D: return self.submobjects[0].points[1] def get_last_handle(self) -> Point3D: return self.submobjects[-1].points[-2] class OpenGLTangentLine(OpenGLLine): def __init__( self, vmob: OpenGLVMobject, alpha: float, length: float = 1, d_alpha: float = 1e-6, **kwargs: Any, ): self.length = length self.d_alpha = d_alpha da = self.d_alpha a1 = clip(alpha - da, 0, 1) a2 = clip(alpha + da, 0, 1) super().__init__(vmob.pfp(a1), vmob.pfp(a2), **kwargs) self.scale(self.length / self.get_length()) class OpenGLElbow(OpenGLVMobject): def __init__(self, width: float = 0.2, angle: float = 0, **kwargs: Any): self.angle = angle super().__init__(self, **kwargs) self.set_points_as_corners([UP, UP + RIGHT, RIGHT]) self.set_width(width, about_point=ORIGIN) self.rotate(self.angle, about_point=ORIGIN) class OpenGLArrow(OpenGLLine): def __init__( self, start: Point3DLike = LEFT, end: Point3DLike = RIGHT, path_arc: float = 0, fill_color: ParsableManimColor = GREY_A, fill_opacity: float = 1, stroke_width: float = 0, buff: float = MED_SMALL_BUFF, thickness: float = 0.05, tip_width_ratio: float = 5, tip_angle: float = PI / 3, max_tip_length_to_length_ratio: float = 0.5, max_width_to_length_ratio: float = 0.1, **kwargs: Any, ): self.thickness = thickness self.tip_width_ratio = tip_width_ratio self.tip_angle = tip_angle self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_width_to_length_ratio = max_width_to_length_ratio super().__init__( start=start, end=end, buff=buff, path_arc=path_arc, fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs, ) def set_points_by_ends( self, start: Point3DLike, end: Point3DLike, buff: float = 0, path_arc: float = 0 ) -> None: # Find the right tip length and thickness vect = np.asarray(end) - np.asarray(start) length = max(np.linalg.norm(vect), 1e-8) thickness = self.thickness w_ratio = self.max_width_to_length_ratio / (thickness / length) if w_ratio < 1: thickness *= w_ratio tip_width = self.tip_width_ratio * thickness tip_length = tip_width / (2 * np.tan(self.tip_angle / 2)) t_ratio = self.max_tip_length_to_length_ratio / (tip_length / length) if t_ratio < 1: tip_length *= t_ratio tip_width *= t_ratio # Find points for the stem if path_arc == 0: points1 = (length - tip_length) * np.array([RIGHT, 0.5 * RIGHT, ORIGIN]) points1 += thickness * UP / 2 points2 = points1[::-1] + thickness * DOWN else: # Solve for radius so that the tip-to-tail length matches |end - start| a = 2 * (1 - np.cos(path_arc)) b = -2 * tip_length * np.sin(path_arc) c = tip_length**2 - length**2 R = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a) # Find arc points points1 = OpenGLArc.create_quadratic_bezier_points(path_arc) points2 = np.array(points1[::-1]) points1 *= R + thickness / 2 points2 *= R - thickness / 2 if path_arc < 0: tip_length *= -1 rot_T = rotation_matrix_transpose(PI / 2 - path_arc, OUT) for points in points1, points2: points[:] = np.dot(points, rot_T) points += R * DOWN self.set_points(points1) # Tip self.add_line_to(tip_width * UP / 2) self.add_line_to(tip_length * LEFT) self.tip_index = len(self.points) - 1 self.add_line_to(tip_width * DOWN / 2) self.add_line_to(points2[0]) # Close it out self.append_points(points2) self.add_line_to(points1[0]) if length > 0: # Final correction super().scale(length / self.get_length()) self.rotate(angle_of_vector(vect) - self.get_angle()) self.rotate( PI / 2 - np.arccos(normalize(vect)[2]), axis=rotate_vector(self.get_unit_vector(), -PI / 2), ) self.shift(start - self.get_start()) self.refresh_triangulation() def reset_points_around_ends(self) -> Self: self.set_points_by_ends( self.get_start(), self.get_end(), path_arc=self.path_arc, ) return self def get_start(self) -> Point3D: nppc = self.n_points_per_curve points = self.points return (points[0] + points[-nppc]) / 2 def get_end(self) -> Point3D: return self.points[self.tip_index] def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self: self.set_points_by_ends(start, end, buff=0, path_arc=self.path_arc) return self def scale(self, *args: Any, **kwargs: Any) -> Self: super().scale(*args, **kwargs) self.reset_points_around_ends() return self def set_thickness(self, thickness: float) -> Self: self.thickness = thickness self.reset_points_around_ends() return self def set_path_arc(self, path_arc: float) -> None: self.path_arc = path_arc self.reset_points_around_ends() # return self class OpenGLVector(OpenGLArrow): def __init__( self, direction: Vector2DLike | Vector3DLike = RIGHT, buff: float = 0, **kwargs: Any, ): self.buff = buff if len(direction) == 2: direction = np.hstack([direction, 0]) super().__init__(ORIGIN, direction, buff=buff, **kwargs) class OpenGLDoubleArrow(OpenGLArrow): def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) self.add_tip(at_start=True) class OpenGLCubicBezier(OpenGLVMobject): def __init__( self, a0: Point3DLike, h0: Point3DLike, h1: Point3DLike, a1: Point3DLike, **kwargs: Any, ): super().__init__(**kwargs) self.add_cubic_bezier_curve(a0, h0, h1, a1) class OpenGLPolygon(OpenGLVMobject): def __init__(self, *vertices: Point3DLike, **kwargs: Any): self.vertices: Point3D_Array = np.array(vertices) super().__init__(**kwargs) def init_points(self) -> None: verts = self.vertices self.set_points_as_corners([*verts, verts[0]]) def get_vertices(self) -> Point3D_Array: return self.get_start_anchors() def round_corners(self, radius: float = 0.5) -> Self: vertices = self.get_vertices() arcs = [] for v1, v2, v3 in adjacent_n_tuples(vertices, 3): vect1 = v2 - v1 vect2 = v3 - v2 unit_vect1 = normalize(vect1) unit_vect2 = normalize(vect2) angle = angle_between_vectors(vect1, vect2) # Negative radius gives concave curves angle *= np.sign(radius) # Distance between vertex and start of the arc cut_off_length = radius * np.tan(angle / 2) # Determines counterclockwise vs. clockwise sign = np.sign(np.cross(vect1, vect2)[2]) arc = OpenGLArcBetweenPoints( v2 - unit_vect1 * cut_off_length, v2 + unit_vect2 * cut_off_length, angle=sign * angle, n_components=2, ) arcs.append(arc) self.clear_points() # To ensure that we loop through starting with last arcs = [arcs[-1], *arcs[:-1]] for arc1, arc2 in adjacent_pairs(arcs): self.append_points(arc1.points) line = OpenGLLine(arc1.get_end(), arc2.get_start()) # Make sure anchors are evenly distributed len_ratio = line.get_length() / arc1.get_arc_length() line.insert_n_curves(int(arc1.get_num_curves() * len_ratio)) self.append_points(line.points) return self class OpenGLRegularPolygon(OpenGLPolygon): def __init__(self, n: int = 6, start_angle: float | None = None, **kwargs: Any): self.start_angle = start_angle if self.start_angle is None: if n % 2 == 0: self.start_angle = 0 else: self.start_angle = 90 * DEGREES start_vect = rotate_vector(RIGHT, self.start_angle) vertices = compass_directions(n, start_vect) super().__init__(*vertices, **kwargs) class OpenGLTriangle(OpenGLRegularPolygon): def __init__(self, **kwargs: Any): super().__init__(n=3, **kwargs) class OpenGLArrowTip(OpenGLTriangle): def __init__( self, fill_opacity: float = 1, fill_color: ParsableManimColor = WHITE, stroke_width: float = 0, width: float = DEFAULT_ARROW_TIP_WIDTH, length: float = DEFAULT_ARROW_TIP_LENGTH, angle: float = 0, **kwargs: Any, ): super().__init__( start_angle=0, fill_opacity=fill_opacity, fill_color=fill_color, stroke_width=stroke_width, **kwargs, ) self.set_width(width, stretch=True) self.set_height(length, stretch=True) def get_base(self) -> Point3D: return self.point_from_proportion(0.5) def get_tip_point(self) -> Point3D: return self.points[0] def get_vector(self) -> Vector3D: return self.get_tip_point() - self.get_base() def get_angle(self) -> float: return angle_of_vector(self.get_vector()) def get_length(self) -> float: rv: float = np.linalg.norm(self.get_vector()) return rv class OpenGLRectangle(OpenGLPolygon): def __init__( self, color: ParsableManimColor = WHITE, width: float = 4.0, height: float = 2.0, **kwargs: Any, ): super().__init__(UR, UL, DL, DR, color=color, **kwargs) self.set_width(width, stretch=True) self.set_height(height, stretch=True) class OpenGLSquare(OpenGLRectangle): def __init__(self, side_length: float = 2.0, **kwargs: Any): self.side_length = side_length super().__init__(height=side_length, width=side_length, **kwargs) class OpenGLRoundedRectangle(OpenGLRectangle): def __init__(self, corner_radius: float = 0.5, **kwargs: Any): self.corner_radius = corner_radius super().__init__(**kwargs) self.round_corners(self.corner_radius) ================================================ FILE: manim/mobject/opengl/opengl_image_mobject.py ================================================ from __future__ import annotations __all__ = [ "OpenGLImageMobject", ] from pathlib import Path from typing import TYPE_CHECKING, Any import numpy as np from PIL import Image from PIL.Image import Resampling from manim.mobject.opengl.opengl_surface import OpenGLSurface, OpenGLTexturedSurface from manim.utils.images import get_full_raster_image_path if TYPE_CHECKING: import numpy.typing as npt __all__ = ["OpenGLImageMobject"] class OpenGLImageMobject(OpenGLTexturedSurface): def __init__( self, filename_or_array: str | Path | npt.NDArray, width: float | None = None, height: float | None = None, image_mode: str = "RGBA", resampling_algorithm: Resampling = Resampling.BICUBIC, opacity: float = 1, gloss: float = 0, shadow: float = 0, **kwargs: Any, ): self.image = filename_or_array self.resampling_algorithm = resampling_algorithm if isinstance(filename_or_array, np.ndarray): self.size = filename_or_array.shape[1::-1] elif isinstance(filename_or_array, (str, Path)): path = get_full_raster_image_path(filename_or_array) self.size = Image.open(path).size if width is None and height is None: width = 4 * self.size[0] / self.size[1] height = 4 if height is None: height = width * self.size[1] / self.size[0] if width is None: width = height * self.size[0] / self.size[1] surface = OpenGLSurface( lambda u, v: np.array([u, v, 0]), [-width / 2, width / 2], [-height / 2, height / 2], opacity=opacity, gloss=gloss, shadow=shadow, ) super().__init__( surface, self.image, image_mode=image_mode, opacity=opacity, gloss=gloss, shadow=shadow, **kwargs, ) def get_image_from_file( self, image_file: str | Path | np.ndarray, image_mode: str, ) -> Image.Image: if isinstance(image_file, (str, Path)): return super().get_image_from_file(image_file, image_mode) else: return ( Image.fromarray(image_file.astype("uint8")) .convert(image_mode) .resize( image_file.shape[:2] * 200, # assumption of 200 ppmu (pixels per manim unit) would suffice resample=self.resampling_algorithm, ) ) ================================================ FILE: manim/mobject/opengl/opengl_mobject.py ================================================ from __future__ import annotations import copy import inspect import itertools as it import random import sys import types from collections.abc import Callable, Iterable, Iterator, Sequence from functools import partialmethod, wraps from math import ceil from typing import ( TYPE_CHECKING, Any, ClassVar, Never, Protocol, Self, TypeAlias, TypeVar, cast, overload, ) import moderngl import numpy as np import numpy.typing as npt from typing_extensions import ( override, ) from manim import config, logger from manim.constants import * from manim.data_structures import MethodWithArgs from manim.renderer.shader_wrapper import get_colormap_code from manim.typing import ( Point3D, Point3D_Array, Point3DLike, Point3DLike_Array, ) from manim.utils.bezier import integer_interpolate, interpolate from manim.utils.color import ( WHITE, ManimColor, ParsableManimColor, color_gradient, color_to_rgb, rgb_to_hex, ) from manim.utils.config_ops import _Data, _Uniforms # from ..utils.iterables import batch_by_property from manim.utils.iterables import ( batch_by_property, list_update, listify, make_even, resize_array, resize_preserving_order, resize_with_interpolation, uniq_chain, ) from manim.utils.paths import straight_path from manim.utils.space_ops import ( angle_between_vectors, normalize, rotation_matrix_transpose, ) if TYPE_CHECKING: from manim.animation.animation import Animation from manim.renderer.shader_wrapper import ShaderWrapper from manim.typing import ( FloatRGB_Array, FloatRGBA_Array, ManimFloat, MappingFunction, MatrixMN, MultiMappingFunction, PathFuncType, Vector3D, Vector3DLike, ) _TimeBasedUpdater: TypeAlias = Callable[["OpenGLMobject", float], object] _NonTimeBasedUpdater: TypeAlias = Callable[["OpenGLMobject"], object] _Updater: TypeAlias = _NonTimeBasedUpdater | _TimeBasedUpdater _T = TypeVar("_T") _T_np = TypeVar("_T_np", bound=np.generic) def affects_shader_info_id( func: Callable[[OpenGLMobject], OpenGLMobject], ) -> Callable[[OpenGLMobject], OpenGLMobject]: @wraps(func) def wrapper(self: OpenGLMobject) -> OpenGLMobject: for mob in self.get_family(): func(mob) mob.refresh_shader_wrapper_id() return self return wrapper __all__ = ["OpenGLMobject", "OpenGLGroup", "OpenGLPoint", "_AnimationBuilder"] _ShaderDType: TypeAlias = np.void """The dtype for NumPy arrays representing shader data. It's a structured dtype with signature `(point, np.float32, (3,))`.""" _ShaderData: TypeAlias = npt.NDArray[_ShaderDType] class OpenGLMobject: """Mathematical Object: base class for objects that can be displayed on screen. Attributes ---------- submobjects : List[:class:`OpenGLMobject`] The contained objects. points : :class:`numpy.ndarray` The points of the objects. .. seealso:: :class:`~.OpenGLVMobject` """ _original__init__: ClassVar[Callable[..., None]] shader_dtype: ClassVar[Sequence[tuple[str, type[np.generic], tuple[int, ...]]]] = [ ("point", np.float32, (3,)), ] shader_folder: ClassVar[str] = "" # _Data and _Uniforms are set as class variables to tell manim how to handle setting/getting these attributes later. points: _Data[Point3D_Array] = _Data() bounding_box: _Data[Point3D_Array] = _Data() rgbas: _Data[FloatRGBA_Array] = _Data() is_fixed_in_frame: _Uniforms = _Uniforms() is_fixed_orientation: _Uniforms = _Uniforms() fixed_orientation_center: _Uniforms[tuple[float, float, float]] = ( _Uniforms() ) # for fixed orientation reference gloss: _Uniforms = _Uniforms() shadow: _Uniforms = _Uniforms() def __init__( self, color: ParsableManimColor | Sequence[ParsableManimColor] = WHITE, opacity: float = 1, dim: int = 3, # TODO, get rid of this # Lighting parameters # Positive gloss up to 1 makes it reflect the light. gloss: float = 0.0, # Positive shadow up to 1 makes a side opposite the light darker shadow: float = 0.0, # For shaders render_primitive: int = moderngl.TRIANGLES, texture_paths: dict[str, str] | None = None, depth_test: bool = False, # If true, the mobject will not get rotated according to camera position is_fixed_in_frame: bool = False, is_fixed_orientation: bool = False, # Must match in attributes of vert shader # Event listener listen_to_events: bool = False, model_matrix: MatrixMN | None = None, should_render: bool = True, name: str | None = None, **kwargs: Any, ): self.name: str = self.__class__.__name__ if name is None else name # getattr in case data/uniforms are already defined in parent classes. self.data: dict[str, npt.NDArray[Any]] = getattr(self, "data", {}) self.uniforms: dict[str, float | tuple[float, ...]] = getattr( self, "uniforms", {} ) self.opacity: float | Iterable[float] = opacity self.dim: int = dim # TODO, get rid of this # Lighting parameters # Positive gloss up to 1 makes it reflect the light. self.gloss = gloss # Positive shadow up to 1 makes a side opposite the light darker self.shadow = shadow # For shaders self.render_primitive: int = render_primitive self.texture_paths: dict[str, str] | None = texture_paths self.depth_test: bool = depth_test # If true, the mobject will not get rotated according to camera position self.is_fixed_in_frame = float(is_fixed_in_frame) self.is_fixed_orientation = float(is_fixed_orientation) self.fixed_orientation_center = (0, 0, 0) # Must match in attributes of vert shader # Event listener self.listen_to_events: bool = listen_to_events self._submobjects: list[OpenGLMobject] = [] self.parents: list[OpenGLMobject] = [] self.parent: OpenGLMobject | None = None self.family: list[OpenGLMobject] = [self] self.locked_data_keys: set[str] = set() self.needs_new_bounding_box: bool = True if model_matrix is None: self.model_matrix: MatrixMN = np.eye(4) else: self.model_matrix = model_matrix self.init_data() self.init_updaters() # self.init_event_listners() self.init_points() self.color: ManimColor | list[ManimColor] = ManimColor.parse(color) self.init_colors() self.shader_indices: Sequence[int] | None = None if self.depth_test: self.apply_depth_test() self.should_render: bool = should_render def _assert_valid_submobjects(self, submobjects: Iterable[OpenGLMobject]) -> Self: """Check that all submobjects are actually instances of :class:`OpenGLMobject`, and that none of them is ``self`` (an :class:`OpenGLMobject` cannot contain itself). This is an auxiliary function called when adding OpenGLMobjects to the :attr:`submobjects` list. This function is intended to be overridden by subclasses such as :class:`OpenGLVMobject`, which should assert that only other OpenGLVMobjects may be added into it. Parameters ---------- submobjects The list containing values to validate. Returns ------- :class:`OpenGLMobject` The OpenGLMobject itself. Raises ------ TypeError If any of the values in `submobjects` is not an :class:`OpenGLMobject`. ValueError If there was an attempt to add an :class:`OpenGLMobject` as its own submobject. """ return self._assert_valid_submobjects_internal(submobjects, OpenGLMobject) def _assert_valid_submobjects_internal( self, submobjects: Iterable[OpenGLMobject], mob_class: type[OpenGLMobject] ) -> Self: for i, submob in enumerate(submobjects): if not isinstance(submob, mob_class): error_message = ( f"Only values of type {mob_class.__name__} can be added " f"as submobjects of {type(self).__name__}, but the value " f"{submob} (at index {i}) is of type " f"{type(submob).__name__}." ) # Intended for subclasses such as OpenGLVMobject, which # cannot have regular OpenGLMobjects as submobjects if isinstance(submob, OpenGLMobject): error_message += ( " You can try adding this value into a Group instead." ) raise TypeError(error_message) if submob is self: raise ValueError( f"Cannot add {type(self).__name__} as a submobject of " f"itself (at index {i})." ) return self @classmethod def __init_subclass__(cls, **kwargs: Any) -> None: super().__init_subclass__(**kwargs) cls._original__init__ = cls.__init__ @override def __str__(self) -> str: return self.__class__.__name__ @override def __repr__(self) -> str: return str(self.name) def __sub__(self, other: Never) -> object: return NotImplemented def __isub__(self, other: Never) -> object: return NotImplemented def __add__(self, mobject: Never) -> object: return NotImplemented def __iadd__(self, mobject: Never) -> object: return NotImplemented @classmethod def set_default(cls, **kwargs: Any) -> None: """Sets the default values of keyword arguments. If this method is called without any additional keyword arguments, the original default values of the initialization method of this class are restored. Parameters ---------- kwargs Passing any keyword argument will update the default values of the keyword arguments of the initialization function of this class. Examples -------- :: >>> from manim import Square, GREEN >>> Square.set_default(color=GREEN, fill_opacity=0.25) >>> s = Square(); s.color, s.fill_opacity (ManimColor('#83C167'), 0.25) >>> Square.set_default() >>> s = Square(); s.color, s.fill_opacity (ManimColor('#FFFFFF'), 0.0) .. manim:: ChangedDefaultTextcolor :save_last_frame: config.background_color = WHITE class ChangedDefaultTextcolor(Scene): def construct(self): Text.set_default(color=BLACK) self.add(Text("Changing default values is easy!")) # we revert the colour back to the default to prevent a bug in the docs. Text.set_default(color=WHITE) """ if kwargs: # Apparently mypy does not correctly understand `partialmethod`: # see https://github.com/python/mypy/issues/8619 cls.__init__ = partialmethod(cls.__init__, **kwargs) # type: ignore[assignment] else: cls.__init__ = cls._original__init__ def init_data(self) -> None: """Initializes the ``points``, ``bounding_box`` and ``rgbas`` attributes and groups them into self.data. Subclasses can inherit and overwrite this method to extend `self.data`. """ self.points = np.zeros((0, 3)) self.bounding_box = np.zeros((3, 3)) self.rgbas = np.zeros((1, 4)) def init_colors(self) -> None: """Initializes the colors. Gets called upon creation """ self.set_color(self.color, self.opacity) def init_points(self) -> None: """Initializes :attr:`points` and therefore the shape. Gets called upon creation. This is an empty method that can be implemented by subclasses. """ # Typically implemented in subclass, unless purposefully left blank pass def set(self, **kwargs: object) -> Self: """Sets attributes. Mainly to be used along with :attr:`animate` to animate setting attributes. Examples -------- :: >>> mob = OpenGLMobject() >>> mob.set(foo=0) OpenGLMobject >>> mob.foo 0 Parameters ---------- **kwargs The attributes and corresponding values to set. Returns ------- :class:`OpenGLMobject` ``self`` """ for attr, value in kwargs.items(): setattr(self, attr, value) return self 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 @property def animate(self) -> _AnimationBuilder | Self: """Used to animate the application of a method. .. warning:: Passing multiple animations for the same :class:`OpenGLMobject` in one call to :meth:`~.Scene.play` is discouraged and will most likely not work properly. Instead of writing an animation like :: self.play( my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI) ) make use of method chaining for ``animate``, meaning:: self.play(my_mobject.animate.shift(RIGHT).rotate(PI)) Keyword arguments that can be passed to :meth:`.Scene.play` can be passed directly after accessing ``.animate``, like so:: self.play(my_mobject.animate(rate_func=linear).shift(RIGHT)) This is especially useful when animating simultaneous ``.animate`` calls that you want to behave differently:: self.play( mobject1.animate(run_time=2).rotate(PI), mobject2.animate(rate_func=there_and_back).shift(RIGHT), ) .. seealso:: :func:`override_animate` Examples -------- .. manim:: AnimateExample class AnimateExample(Scene): def construct(self): s = Square() self.play(Create(s)) self.play(s.animate.shift(RIGHT)) self.play(s.animate.scale(2)) self.play(s.animate.rotate(PI / 2)) self.play(Uncreate(s)) .. manim:: AnimateChainExample class AnimateChainExample(Scene): def construct(self): s = Square() self.play(Create(s)) self.play(s.animate.shift(RIGHT).scale(2).rotate(PI / 2)) self.play(Uncreate(s)) .. manim:: AnimateWithArgsExample class AnimateWithArgsExample(Scene): def construct(self): s = Square() c = Circle() VGroup(s, c).arrange(RIGHT, buff=2) self.add(s, c) self.play( s.animate(run_time=2).rotate(PI / 2), c.animate(rate_func=there_and_back).shift(RIGHT), ) .. warning:: ``.animate`` will interpolate the :class:`~.OpenGLMobject` between its points prior to ``.animate`` and its points after applying ``.animate`` to it. This may result in unexpected behavior when attempting to interpolate along paths, or rotations. If you want animations to consider the points between, consider using :class:`~.ValueTracker` with updaters instead. """ return _AnimationBuilder(self) @property def width(self) -> float: """The width of the mobject. Returns ------- :class:`float` Examples -------- .. manim:: WidthExample class WidthExample(Scene): def construct(self): decimal = DecimalNumber().to_edge(UP) rect = Rectangle(color=BLUE) rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5) decimal.add_updater(lambda d: d.set_value(rect.width)) self.add(rect_copy, rect, decimal) self.play(rect.animate.set(width=7)) self.wait() See also -------- :meth:`length_over_dim` """ # Get the length across the X dimension return self.length_over_dim(0) # Only these methods should directly affect points @width.setter def width(self, value: float) -> None: self.rescale_to_fit(value, 0, stretch=False) @property def height(self) -> float: """The height of the mobject. Returns ------- :class:`float` Examples -------- .. manim:: HeightExample class HeightExample(Scene): def construct(self): decimal = DecimalNumber().to_edge(UP) rect = Rectangle(color=BLUE) rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5) decimal.add_updater(lambda d: d.set_value(rect.height)) self.add(rect_copy, rect, decimal) self.play(rect.animate.set(height=5)) self.wait() See also -------- :meth:`length_over_dim` """ # Get the length across the Y dimension return self.length_over_dim(1) @height.setter def height(self, value: float) -> None: self.rescale_to_fit(value, 1, stretch=False) @property def depth(self) -> float: """The depth of the mobject. Returns ------- :class:`float` See also -------- :meth:`length_over_dim` """ # Get the length across the Z dimension return self.length_over_dim(2) @depth.setter def depth(self, value: float) -> None: self.rescale_to_fit(value, 2, stretch=False) def resize_points( self, new_length: int, resize_func: Callable[[Point3D_Array, int], Point3D_Array] = resize_array, ) -> Self: if new_length != len(self.points): self.points = resize_func(self.points, new_length) self.refresh_bounding_box() return self def set_points(self, points: Point3DLike_Array) -> Self: if len(points) == len(self.points): self.points[:] = points elif isinstance(points, np.ndarray): self.points = points.copy() else: self.points = np.array(points) self.refresh_bounding_box() return self def apply_over_attr_arrays( self, func: Callable[[npt.NDArray[_T_np]], npt.NDArray[_T_np]] ) -> Self: for attr in self.get_array_attrs(): setattr(self, attr, func(getattr(self, attr))) return self def get_array_attrs(self) -> Iterable[str]: return ["points"] def append_points(self, new_points: Point3DLike_Array) -> Self: self.points = np.vstack([self.points, new_points]) self.refresh_bounding_box() return self def reverse_points(self) -> Self: for mob in self.get_family(): for key in mob.data: mob.data[key] = mob.data[key][::-1] return self def get_midpoint(self) -> Point3D: """Get coordinates of the middle of the path that forms the :class:`~.OpenGLMobject`. Examples -------- .. manim:: AngleMidPoint :save_last_frame: class AngleMidPoint(Scene): def construct(self): line1 = Line(ORIGIN, 2*RIGHT) line2 = Line(ORIGIN, 2*RIGHT).rotate_about_origin(80*DEGREES) a = Angle(line1, line2, radius=1.5, other_angle=False) d = Dot(a.get_midpoint()).set_color(RED) self.add(line1, line2, a, d) self.wait() """ return self.point_from_proportion(0.5) # TODO: name is inconsistent with Mobject.apply_points_function_about_point() def apply_points_function( self, func: MultiMappingFunction, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = ORIGIN, works_on_bounding_box: bool = False, ) -> Self: if about_point is None and about_edge is not None: about_point = self.get_bounding_box_point(about_edge) for mob in self.get_family(): arrs: list[Point3D_Array] = [] if mob.has_points(): arrs.append(mob.points) if works_on_bounding_box: arrs.append(mob.get_bounding_box()) for arr in arrs: if about_point is None: arr[:] = func(arr) else: arr[:] = func(arr - about_point) + about_point if not works_on_bounding_box: self.refresh_bounding_box(recurse_down=True) else: for parent in self.parents: parent.refresh_bounding_box() return self # Others related to points def match_points(self, mobject: OpenGLMobject) -> Self: """Edit points, positions, and submobjects to be identical to another :class:`~.OpenGLMobject`, while keeping the style unchanged. Examples -------- .. manim:: MatchPointsScene class MatchPointsScene(Scene): def construct(self): circ = Circle(fill_color=RED, fill_opacity=0.8) square = Square(fill_color=BLUE, fill_opacity=0.2) self.add(circ) self.wait(0.5) self.play(circ.animate.match_points(square)) self.wait(0.5) """ self.set_points(mobject.points) return self def clear_points(self) -> Self: self.points = np.empty((0, 3)) return self def get_num_points(self) -> int: return len(self.points) def get_all_points(self) -> Point3D_Array: if self.submobjects: return np.vstack([sm.points for sm in self.get_family()]) else: return self.points def has_points(self) -> bool: return self.get_num_points() > 0 def get_bounding_box(self) -> Point3D_Array: if self.needs_new_bounding_box: self.bounding_box = self.compute_bounding_box() self.needs_new_bounding_box = False return self.bounding_box def compute_bounding_box(self) -> Point3D_Array: all_points = np.vstack( [ self.points, *( mob.get_bounding_box() for mob in self.get_family()[1:] if mob.has_points() ), ], ) if len(all_points) == 0: return np.zeros((3, self.dim)) else: # Lower left and upper right corners mins = all_points.min(0) maxs = all_points.max(0) mids = (mins + maxs) / 2 return np.array([mins, mids, maxs]) def refresh_bounding_box( self, recurse_down: bool = False, recurse_up: bool = True ) -> Self: for mob in self.get_family(recurse_down): mob.needs_new_bounding_box = True if recurse_up: for parent in self.parents: parent.refresh_bounding_box() return self def is_point_touching( self, point: Point3DLike, buff: float = MED_SMALL_BUFF ) -> bool: bb = self.get_bounding_box() mins = bb[0] - buff maxs = bb[2] + buff rv: bool = (point >= mins).all() and (point <= maxs).all() return rv # Family matters def __getitem__(self, value: int | slice) -> OpenGLMobject: if isinstance(value, slice): GroupClass = self.get_group_class() return GroupClass(*self.split().__getitem__(value)) return self.split().__getitem__(value) def __iter__(self) -> Iterator[OpenGLMobject]: return iter(self.split()) def __len__(self) -> int: return len(self.split()) def split(self) -> Sequence[OpenGLMobject]: return self.submobjects def assemble_family(self) -> Self: sub_families = (sm.get_family() for sm in self.submobjects) self.family = [self, *uniq_chain(*sub_families)] self.refresh_has_updater_status() self.refresh_bounding_box() for parent in self.parents: parent.assemble_family() return self def get_family(self, recurse: bool = True) -> Sequence[OpenGLMobject]: if recurse and hasattr(self, "family"): return self.family else: return [self] def family_members_with_points(self) -> Sequence[OpenGLMobject]: return [m for m in self.get_family() if m.has_points()] def add(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self: """Add mobjects as submobjects. The mobjects are added to :attr:`submobjects`. Subclasses of mobject may implement ``+`` and ``+=`` dunder methods. Parameters ---------- mobjects The mobjects to add. Returns ------- :class:`OpenGLMobject` ``self`` Raises ------ :class:`ValueError` When a mobject tries to add itself. :class:`TypeError` When trying to add an object that is not an instance of :class:`OpenGLMobject`. Notes ----- A mobject cannot contain itself, and it cannot contain a submobject more than once. If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene). See Also -------- :meth:`remove` :meth:`add_to_back` Examples -------- :: >>> outer = OpenGLMobject() >>> inner = OpenGLMobject() >>> outer = outer.add(inner) Duplicates are not added again:: >>> outer = outer.add(inner) >>> len(outer.submobjects) 1 Only OpenGLMobjects can be added:: >>> outer.add(3) Traceback (most recent call last): ... TypeError: Only values of type OpenGLMobject can be added as submobjects of OpenGLMobject, but the value 3 (at index 0) is of type int. Adding an object to itself raises an error:: >>> outer.add(outer) Traceback (most recent call last): ... ValueError: Cannot add OpenGLMobject as a submobject of itself (at index 0). """ if update_parent: assert len(mobjects) == 1, "Can't set multiple parents." mobjects[0].parent = self self._assert_valid_submobjects(mobjects) if any(mobjects.count(elem) > 1 for elem in mobjects): logger.warning( "Attempted adding some Mobject as a child more than once, " "this is not possible. Repetitions are ignored.", ) for mobject in mobjects: if mobject not in self.submobjects: self.submobjects.append(mobject) if self not in mobject.parents: mobject.parents.append(self) self.assemble_family() return self def insert( self, index: int, mobject: OpenGLMobject, update_parent: bool = False ) -> Self: """Inserts a mobject at a specific position into self.submobjects Effectively just calls ``self.submobjects.insert(index, mobject)``, where ``self.submobjects`` is a list. Highly adapted from ``OpenGLMobject.add``. Parameters ---------- index The index at which mobject The mobject to be inserted. update_parent Whether or not to set ``mobject.parent`` to ``self``. """ if update_parent: mobject.parent = self self._assert_valid_submobjects([mobject]) if mobject not in self.submobjects: self.submobjects.insert(index, mobject) if self not in mobject.parents: mobject.parents.append(self) self.assemble_family() return self def remove(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self: """Remove :attr:`submobjects`. The mobjects are removed from :attr:`submobjects`, if they exist. Subclasses of mobject may implement ``-`` and ``-=`` dunder methods. Parameters ---------- mobjects The mobjects to remove. Returns ------- :class:`OpenGLMobject` ``self`` See Also -------- :meth:`add` """ if update_parent: assert len(mobjects) == 1, "Can't remove multiple parents." mobjects[0].parent = None for mobject in mobjects: if mobject in self.submobjects: self.submobjects.remove(mobject) if self in mobject.parents: mobject.parents.remove(self) self.assemble_family() return self def add_to_back(self, *mobjects: OpenGLMobject) -> Self: # NOTE: is the note true OpenGLMobjects? """Add all passed mobjects to the back of the submobjects. If :attr:`submobjects` already contains the given mobjects, they just get moved to the back instead. Parameters ---------- mobjects The mobjects to add. Returns ------- :class:`OpenGLMobject` ``self`` .. note:: Technically, this is done by adding (or moving) the mobjects to the head of :attr:`submobjects`. The head of this list is rendered first, which places the corresponding mobjects behind the subsequent list members. Raises ------ :class:`ValueError` When a mobject tries to add itself. :class:`TypeError` When trying to add an object that is not an instance of :class:`OpenGLMobject`. Notes ----- A mobject cannot contain itself, and it cannot contain a submobject more than once. If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene). See Also -------- :meth:`remove` :meth:`add` """ self._assert_valid_submobjects(mobjects) self.submobjects = list_update(mobjects, self.submobjects) return self def replace_submobject(self, index: int, new_submob: OpenGLMobject) -> Self: self._assert_valid_submobjects([new_submob]) old_submob = self.submobjects[index] if self in old_submob.parents: old_submob.parents.remove(self) self.submobjects[index] = new_submob self.assemble_family() return self # Submobject organization def arrange( self, direction: Vector3DLike = RIGHT, center: bool = True, **kwargs: Any, ) -> Self: """Sorts :class:`~.OpenGLMobject` next to each other on screen. Examples -------- .. manim:: Example :save_last_frame: class Example(Scene): def construct(self): s1 = Square() s2 = Square() s3 = Square() s4 = Square() x = OpenGLVGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.0) self.add(x) """ for m1, m2 in zip(self.submobjects[:-1], self.submobjects[1:], strict=True): m2.next_to(m1, direction, **kwargs) if center: self.center() return self def arrange_in_grid( self, rows: int | None = None, cols: int | None = None, buff: float | tuple[float, float] = MED_SMALL_BUFF, cell_alignment: Vector3DLike = ORIGIN, row_alignments: str | None = None, # "ucd" col_alignments: str | None = None, # "lcr" row_heights: Sequence[float | None] | None = None, col_widths: Sequence[float | None] | None = None, flow_order: str = "rd", **kwargs: Any, ) -> Self: """Arrange submobjects in a grid. Parameters ---------- rows The number of rows in the grid. cols The number of columns in the grid. buff The gap between grid cells. To specify a different buffer in the horizontal and vertical directions, a tuple of two values can be given - ``(row, col)``. cell_alignment The way each submobject is aligned in its grid cell. row_alignments The vertical alignment for each row (top to bottom). Accepts the following characters: ``"u"`` - up, ``"c"`` - center, ``"d"`` - down. col_alignments The horizontal alignment for each column (left to right). Accepts the following characters ``"l"`` - left, ``"c"`` - center, ``"r"`` - right. row_heights Defines a list of heights for certain rows (top to bottom). If the list contains ``None``, the corresponding row will fit its height automatically based on the highest element in that row. col_widths Defines a list of widths for certain columns (left to right). If the list contains ``None``, the corresponding column will fit its width automatically based on the widest element in that column. flow_order The order in which submobjects fill the grid. Can be one of the following values: "rd", "dr", "ld", "dl", "ru", "ur", "lu", "ul". ("rd" -> fill rightwards then downwards) Returns ------- OpenGLMobject The mobject. NOTES ----- If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big enough to fit all submobjects. If neither is set, they will be chosen to be about the same, tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high). If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are defined, the latter has higher priority. Raises ------ ValueError If ``rows`` and ``cols`` are too small to fit all submobjects. ValueError If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`, :code:`row_alignments` and :code:`row_heights` have mismatching sizes. Examples -------- .. manim:: ExampleBoxes :save_last_frame: class ExampleBoxes(Scene): def construct(self): boxes=VGroup(*[Square() for s in range(0,6)]) boxes.arrange_in_grid(rows=2, buff=0.1) self.add(boxes) .. manim:: ArrangeInGrid :save_last_frame: class ArrangeInGrid(Scene): def construct(self): #Add some numbered boxes: np.random.seed(3) boxes = VGroup(*[ Rectangle(WHITE, np.random.random()+.5, np.random.random()+.5).add(Text(str(i+1)).scale(0.5)) for i in range(22) ]) self.add(boxes) boxes.arrange_in_grid( buff=(0.25,0.5), col_alignments="lccccr", row_alignments="uccd", col_widths=[2, *[None]*4, 2], flow_order="dr" ) """ from manim.mobject.geometry.line import Line mobs = self.submobjects.copy() start_pos = self.get_center() # get cols / rows values if given (implicitly) def init_size( num: int | None, alignments: str | None, sizes: Sequence[float | None] | None, name: str, ) -> int: if num is not None: return num if alignments is not None: return len(alignments) if sizes is not None: return len(sizes) raise ValueError( f"At least one of the following parameters: '{name}s', " f"'{name}_alignments' or " f"'{name}_{'widths' if name == 'col' else 'heights'}', " "must not be None" ) cols = init_size(cols, col_alignments, col_widths, "col") rows = init_size(rows, row_alignments, row_heights, "row") # calculate rows cols if rows is None and cols is None: cols = ceil(np.sqrt(len(mobs))) # make the grid as close to quadratic as possible. # choosing cols first can results in cols>rows. # This is favored over rows>cols since in general # the sceene is wider than high. if rows is None: rows = ceil(len(mobs) / cols) if cols is None: cols = ceil(len(mobs) / rows) if rows * cols < len(mobs): raise ValueError("Too few rows and columns to fit all submobjetcs.") # rows and cols are now finally valid. if isinstance(buff, tuple): buff_x = buff[0] buff_y = buff[1] else: buff_x = buff_y = buff # Initialize alignments correctly def init_alignments( str_alignments: str | None, num: int, mapping: dict[str, Vector3D], name: str, direction: Vector3D, ) -> Sequence[Vector3D]: if str_alignments is None: # Use cell_alignment as fallback return [cast("Vector3D", cell_alignment * direction)] * num if len(str_alignments) != num: raise ValueError(f"{name}_alignments has a mismatching size.") return [mapping[letter] for letter in str_alignments] row_alignments_seq: Sequence[Vector3D] = init_alignments( row_alignments, rows, {"u": UP, "c": ORIGIN, "d": DOWN}, "row", RIGHT, ) col_alignments_seq: Sequence[Vector3D] = init_alignments( col_alignments, cols, {"l": LEFT, "c": ORIGIN, "r": RIGHT}, "col", UP, ) # Now row_alignments_seq[r] + col_alignment_seq[c] is the alignment in cell [r][c] mapper: dict[str, Callable[[int, int], int]] = { "dr": lambda r, c: (rows - r - 1) + c * rows, "dl": lambda r, c: (rows - r - 1) + (cols - c - 1) * rows, "ur": lambda r, c: r + c * rows, "ul": lambda r, c: r + (cols - c - 1) * rows, "rd": lambda r, c: (rows - r - 1) * cols + c, "ld": lambda r, c: (rows - r - 1) * cols + (cols - c - 1), "ru": lambda r, c: r * cols + c, "lu": lambda r, c: r * cols + (cols - c - 1), } if flow_order not in mapper: valid_flow_orders = ",".join([f'"{key}"' for key in mapper]) raise ValueError( f"flow_order must be one of the following values: {valid_flow_orders}.", ) flow_order_func = mapper[flow_order] # Reverse row_alignments and row_heights. Necessary since the # grid filling is handled bottom up for simplicity reasons. if TYPE_CHECKING: @overload def reverse(maybe_list: None) -> None: ... @overload def reverse(maybe_list: Sequence[_T]) -> list[_T]: ... @overload def reverse(maybe_list: Sequence[_T] | None) -> list[_T] | None: ... def reverse(maybe_list: Sequence[_T] | None) -> list[_T] | None: if maybe_list is not None: maybe_list = list(maybe_list) maybe_list.reverse() return maybe_list return None row_alignments_seq = reverse(row_alignments_seq) row_heights = reverse(row_heights) placeholder = OpenGLMobject() # Used to fill up the grid temporarily, doesn't get added to the scene. # In this case a Mobject is better than None since it has width and height # properties of 0. mobs.extend([placeholder] * (rows * cols - len(mobs))) grid = [[mobs[flow_order_func(r, c)] for c in range(cols)] for r in range(rows)] measured_heigths = [ max(grid[r][c].height for c in range(cols)) for r in range(rows) ] measured_widths = [ max(grid[r][c].width for r in range(rows)) for c in range(cols) ] # Initialize row_heights / col_widths correctly using measurements as fallback def init_sizes( sizes: Sequence[float | None] | None, num: int, measures: Sequence[float], name: str, ) -> Sequence[float]: if sizes is None: sizes = [None] * num if len(sizes) != num: raise ValueError(f"{name} has a mismatching size.") return [ size if (size := sizes[i]) is not None else measures[i] for i in range(num) ] heights = init_sizes(row_heights, rows, measured_heigths, "row_heights") widths = init_sizes(col_widths, cols, measured_widths, "col_widths") x, y = 0.0, 0.0 for r in range(rows): x = 0.0 for c in range(cols): if grid[r][c] is not placeholder: alignment = row_alignments_seq[r] + col_alignments_seq[c] line = Line( x * RIGHT + y * UP, (x + widths[c]) * RIGHT + (y + heights[r]) * UP, ) # Use a mobject to avoid rewriting align inside # box code that Mobject.move_to(Mobject) already # includes. grid[r][c].move_to(line, alignment) x += widths[c] + buff_x y += heights[r] + buff_y self.move_to(start_pos) return self def get_grid( self, n_rows: int, n_cols: int, height: float | None = None, **kwargs: Any, ) -> OpenGLGroup: """ Returns a new mobject containing multiple copies of this one arranged in a grid """ grid = self.duplicate(n_rows * n_cols) grid.arrange_in_grid(n_rows, n_cols, **kwargs) if height is not None: grid.set_height(height) return grid def duplicate(self, n: int) -> OpenGLGroup: """Returns an :class:`~.OpenGLGroup` containing ``n`` copies of the mobject.""" return self.get_group_class()(*[self.copy() for _ in range(n)]) def sort( self, point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0], submob_func: Callable[[OpenGLMobject], Any] | None = None, ) -> Self: """Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``.""" if submob_func is not None: self.submobjects.sort(key=submob_func) else: self.submobjects.sort(key=lambda m: point_to_num_func(m.get_center())) return self def shuffle(self, recurse: bool = False) -> Self: """Shuffles the order of :attr:`submobjects` Examples -------- .. manim:: ShuffleSubmobjectsExample class ShuffleSubmobjectsExample(Scene): def construct(self): s= OpenGLVGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)]) s2= s.copy() s2.shuffle() s2.shift(DOWN) self.play(Write(s), Write(s2)) """ if recurse: for submob in self.submobjects: submob.shuffle(recurse=True) random.shuffle(self.submobjects) self.assemble_family() return self def invert(self, recursive: bool = False) -> Self: """Inverts the list of :attr:`submobjects`. Parameters ---------- recursive If ``True``, all submobject lists of this mobject's family are inverted. Examples -------- .. manim:: InvertSumobjectsExample class InvertSumobjectsExample(Scene): def construct(self): s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)]) s2 = s.copy() s2.invert() s2.shift(DOWN) self.play(Write(s), Write(s2)) """ if recursive: for submob in self.submobjects: submob.invert(recursive=True) self.submobjects.reverse() self.assemble_family() return self # Copying def copy(self, shallow: bool = False) -> OpenGLMobject: """Create and return an identical copy of the :class:`OpenGLMobject` including all :attr:`submobjects`. Returns ------- :class:`OpenGLMobject` The copy. Parameters ---------- shallow Controls whether a shallow copy is returned. Note ---- The clone is initially not visible in the Scene, even if the original was. """ if not shallow: return self.deepcopy() # TODO, either justify reason for shallow copy, or # remove this redundancy everywhere # return self.deepcopy() parents = self.parents self.parents = [] copy_mobject = copy.copy(self) self.parents = parents copy_mobject.data = dict(self.data) for key in self.data: copy_mobject.data[key] = self.data[key].copy() # TODO, are uniforms ever numpy arrays? copy_mobject.uniforms = dict(self.uniforms) copy_mobject.submobjects = [] copy_mobject.add(*(sm.copy() for sm in self.submobjects)) copy_mobject.match_updaters(self) copy_mobject.needs_new_bounding_box = self.needs_new_bounding_box # Make sure any mobject or numpy array attributes are copied family = self.get_family() for attr, value in list(self.__dict__.items()): if ( isinstance(value, OpenGLMobject) and value in family and value is not self ): setattr(copy_mobject, attr, value.copy()) if isinstance(value, np.ndarray): setattr(copy_mobject, attr, value.copy()) # if isinstance(value, ShaderWrapper): # setattr(copy_mobject, attr, value.copy()) return copy_mobject def deepcopy(self) -> OpenGLMobject: parents = self.parents self.parents = [] result = copy.deepcopy(self) self.parents = parents return result def generate_target(self, use_deepcopy: bool = False) -> OpenGLMobject: self.target: OpenGLMobject | None = None # Prevent exponential explosion if use_deepcopy: self.target = self.deepcopy() else: self.target = self.copy() return self.target def save_state(self, use_deepcopy: bool = False) -> Self: """Save the current state (position, color & size). Can be restored with :meth:`~.OpenGLMobject.restore`.""" if hasattr(self, "saved_state"): # Prevent exponential growth of data self.saved_state: OpenGLMobject | None = None if use_deepcopy: self.saved_state = self.deepcopy() else: self.saved_state = self.copy() return self def restore(self) -> Self: """Restores the state that was previously saved with :meth:`~.OpenGLMobject.save_state`.""" if not hasattr(self, "saved_state") or self.saved_state is None: raise Exception("Trying to restore without having saved") self.become(self.saved_state) return self # Updating def init_updaters(self) -> None: self.time_based_updaters: list["_TimeBasedUpdater"] = [] # noqa: UP037 self.non_time_updaters: list["_NonTimeBasedUpdater"] = [] # noqa: UP037 self.has_updaters: bool = False self.updating_suspended: bool = False def update(self, dt: float = 0, recurse: bool = True) -> Self: if self.has_updaters and not self.updating_suspended: for time_based_updater in self.time_based_updaters: time_based_updater(self, dt) for non_time_updater in self.non_time_updaters: non_time_updater(self) if recurse: for submob in self.submobjects: submob.update(dt, recurse) return self def get_time_based_updaters(self) -> Sequence[_TimeBasedUpdater]: return self.time_based_updaters def has_time_based_updater(self) -> bool: return len(self.time_based_updaters) > 0 def get_updaters(self) -> Sequence[_Updater]: return cast("list[_Updater]", self.time_based_updaters) + cast( "list[_Updater]", self.non_time_updaters ) def get_family_updaters(self) -> Sequence[_Updater]: return list(it.chain(*(sm.get_updaters() for sm in self.get_family()))) def add_updater( self, update_function: _Updater, index: int | None = None, call_updater: bool = False, ) -> Self: updater_list: list[_TimeBasedUpdater] | list[_NonTimeBasedUpdater] if "dt" in inspect.signature(update_function).parameters: updater_list = self.time_based_updaters else: updater_list = self.non_time_updaters if index is None: cast("list[_Updater]", updater_list).append(update_function) else: cast("list[_Updater]", updater_list).insert(index, update_function) self.refresh_has_updater_status() if call_updater: self.update() return self def remove_updater(self, update_function: _Updater) -> Self: for updater_list in [self.time_based_updaters, self.non_time_updaters]: updater_list = cast("list[_Updater]", updater_list) while update_function in updater_list: updater_list.remove(update_function) self.refresh_has_updater_status() return self def clear_updaters(self, recurse: bool = True) -> Self: self.time_based_updaters = [] self.non_time_updaters = [] self.refresh_has_updater_status() if recurse: for submob in self.submobjects: submob.clear_updaters() return self def match_updaters(self, mobject: OpenGLMobject) -> Self: self.clear_updaters() for updater in mobject.get_updaters(): self.add_updater(updater) return self def suspend_updating(self, recurse: bool = True) -> Self: self.updating_suspended = True if recurse: for submob in self.submobjects: submob.suspend_updating(recurse) return self def resume_updating(self, recurse: bool = True, call_updater: bool = True) -> Self: self.updating_suspended = False if recurse: for submob in self.submobjects: submob.resume_updating(recurse) for parent in self.parents: parent.resume_updating(recurse=False, call_updater=False) if call_updater: self.update(dt=0, recurse=recurse) return self def refresh_has_updater_status(self) -> Self: self.has_updaters = any(mob.get_updaters() for mob in self.get_family()) return self # Transforming operations def shift(self, vector: Vector3DLike) -> Self: self.apply_points_function( lambda points: points + vector, about_edge=None, works_on_bounding_box=True, ) return self def scale( self, scale_factor: float, about_point: Point3DLike | None = None, about_edge: Point3DLike | None = ORIGIN, **_kwargs: object, ) -> Self: r"""Scale the size by a factor. Default behavior is to scale about the center of the mobject. The argument about_edge can be a vector, indicating which side of the mobject to scale about, e.g., mob.scale(about_edge = RIGHT) scales about mob.get_right(). Otherwise, if about_point is given a value, scaling is done with respect to that point. Parameters ---------- scale_factor The scaling factor :math:`\alpha`. If :math:`0 < |\alpha| < 1`, the mobject will shrink, and for :math:`|\alpha| > 1` it will grow. Furthermore, if :math:`\alpha < 0`, the mobject is also flipped. kwargs Additional keyword arguments passed to :meth:`apply_points_function`. Returns ------- OpenGLMobject The scaled mobject. Examples -------- .. manim:: MobjectScaleExample :save_last_frame: class MobjectScaleExample(Scene): def construct(self): f1 = Text("F") f2 = Text("F").scale(2) f3 = Text("F").scale(0.5) f4 = Text("F").scale(-1) vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT) self.add(vgroup) See also -------- :meth:`move_to` """ self.apply_points_function( lambda points: scale_factor * points, about_point=about_point, about_edge=about_edge, works_on_bounding_box=True, ) return self def stretch(self, factor: float, dim: int, **kwargs: Any) -> Self: def func(points: Point3D_Array) -> Point3D_Array: points[:, dim] *= factor return points self.apply_points_function(func, works_on_bounding_box=True, **kwargs) return self def rotate_about_origin(self, angle: float, axis: Vector3DLike = OUT) -> Self: return self.rotate(angle, axis, about_point=ORIGIN) def rotate( self, angle: float, axis: Vector3DLike = OUT, about_point: Point3DLike | None = None, **kwargs: Any, ) -> Self: """Rotates the :class:`~.OpenGLMobject` about a certain point.""" rot_matrix_T = rotation_matrix_transpose(angle, axis) self.apply_points_function( lambda points: np.dot(points, rot_matrix_T), about_point=about_point, **kwargs, ) return self def flip(self, axis: Vector3DLike = UP, **kwargs: Any) -> Self: """Flips/Mirrors an mobject about its center. Examples -------- .. manim:: FlipExample :save_last_frame: class FlipExample(Scene): def construct(self): s= Line(LEFT, RIGHT+UP).shift(4*LEFT) self.add(s) s2= s.copy().flip() self.add(s2) """ return self.rotate(TAU / 2, axis, **kwargs) def apply_function(self, function: MappingFunction, **kwargs: Any) -> Self: # Default to applying matrix about the origin, not mobjects center if len(kwargs) == 0: kwargs["about_point"] = ORIGIN def multi_mapping_function(points: Point3D_Array) -> Point3D_Array: result: Point3D_Array = np.apply_along_axis(function, 1, points) return result self.apply_points_function(multi_mapping_function, **kwargs) return self def apply_function_to_position(self, function: MappingFunction) -> Self: self.move_to(function(self.get_center())) return self def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self: for submob in self.submobjects: submob.apply_function_to_position(function) return self def apply_matrix(self, matrix: MatrixMN, **kwargs: Any) -> Self: # Default to applying matrix about the origin, not mobjects center if ("about_point" not in kwargs) and ("about_edge" not in kwargs): kwargs["about_point"] = ORIGIN full_matrix = np.identity(self.dim) matrix = np.array(matrix) full_matrix[: matrix.shape[0], : matrix.shape[1]] = matrix self.apply_points_function( lambda points: np.dot(points, full_matrix.T), **kwargs ) return self def apply_complex_function( self, function: Callable[[complex], complex], **kwargs: Any ) -> Self: """Applies a complex function to a :class:`OpenGLMobject`. The x and y coordinates correspond to the real and imaginary parts respectively. Example ------- .. manim:: ApplyFuncExample class ApplyFuncExample(Scene): def construct(self): circ = Circle().scale(1.5) circ_ref = circ.copy() circ.apply_complex_function( lambda x: np.exp(x*1j) ) t = ValueTracker(0) circ.add_updater( lambda x: x.become(circ_ref.copy().apply_complex_function( lambda x: np.exp(x+t.get_value()*1j) )).set_color(BLUE) ) self.add(circ_ref) self.play(TransformFromCopy(circ_ref, circ)) self.play(t.animate.set_value(TAU), run_time=3) """ def R3_func(point: Point3D) -> Point3D: x, y, z = point xy_complex = function(complex(x, y)) return np.array([xy_complex.real, xy_complex.imag, z]) return self.apply_function(R3_func, **kwargs) def hierarchical_model_matrix(self) -> MatrixMN: if self.parent is None: return self.model_matrix model_matrices = [self.model_matrix] current_object = self while current_object.parent is not None: model_matrices.append(current_object.parent.model_matrix) current_object = current_object.parent return np.linalg.multi_dot(list(reversed(model_matrices))) def wag( self, direction: Vector3DLike = RIGHT, axis: Vector3DLike = DOWN, wag_factor: float = 1.0, ) -> Self: for mob in self.family_members_with_points(): alphas = np.dot(mob.points, np.transpose(axis)) alphas -= min(alphas) alphas /= max(alphas) alphas = alphas**wag_factor mob.set_points( mob.points + np.dot( alphas.reshape((len(alphas), 1)), np.array(direction).reshape((1, mob.dim)), ), ) return self # Positioning methods def center(self) -> Self: """Moves the mobject to the center of the Scene.""" self.shift(-self.get_center()) return self def align_on_border( self, direction: Vector3DLike, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER, ) -> Self: """ Direction just needs to be a vector pointing towards side or corner in the 2d plane. """ target_point = np.sign(direction) * ( config["frame_x_radius"], config["frame_y_radius"], 0, ) point_to_align = self.get_bounding_box_point(direction) shift_val = target_point - point_to_align - buff * np.asarray(direction) shift_val = shift_val * abs(np.sign(direction)) self.shift(shift_val) return self def to_corner( self, corner: Vector3DLike = LEFT + DOWN, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER, ) -> Self: return self.align_on_border(corner, buff) def to_edge( self, edge: Vector3DLike = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER, ) -> Self: return self.align_on_border(edge, buff) def next_to( self, mobject_or_point: OpenGLMobject | Point3DLike, direction: Vector3DLike = RIGHT, buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER, aligned_edge: Vector3DLike = ORIGIN, submobject_to_align: OpenGLMobject | None = None, index_of_submobject_to_align: int | None = None, coor_mask: Vector3DLike = np.array([1, 1, 1]), ) -> Self: """Move this :class:`~.OpenGLMobject` next to another's :class:`~.OpenGLMobject` or coordinate. Examples -------- .. manim:: GeometricShapes :save_last_frame: class GeometricShapes(Scene): def construct(self): d = Dot() c = Circle() s = Square() t = Triangle() d.next_to(c, RIGHT) s.next_to(c, LEFT) t.next_to(c, DOWN) self.add(d, c, s, t) """ np_direction = np.asarray(direction) np_aligned_edge = np.asarray(aligned_edge) target_point: Point3DLike if isinstance(mobject_or_point, OpenGLMobject): mob = mobject_or_point if index_of_submobject_to_align is not None: target_aligner = mob[index_of_submobject_to_align] else: target_aligner = mob target_point = target_aligner.get_bounding_box_point( np_aligned_edge + np_direction, ) else: target_point = mobject_or_point if submobject_to_align is not None: aligner = submobject_to_align elif index_of_submobject_to_align is not None: aligner = self[index_of_submobject_to_align] else: aligner = self point_to_align = aligner.get_bounding_box_point(np_aligned_edge - np_direction) self.shift((target_point - point_to_align + buff * np_direction) * coor_mask) return self def shift_onto_screen(self, **kwargs: Any) -> Self: space_lengths: list[float] = [ config["frame_x_radius"], config["frame_y_radius"], ] for vect in UP, DOWN, LEFT, RIGHT: dim = np.argmax(np.abs(vect)) buff: float = kwargs.get("buff", DEFAULT_MOBJECT_TO_EDGE_BUFFER) max_val = space_lengths[dim] - buff edge_center = self.get_edge_center(vect) if np.dot(edge_center, vect) > max_val: self.to_edge(vect, buff=buff) return self def is_off_screen(self) -> bool: if self.get_left()[0] > config.frame_x_radius: return True if self.get_right()[0] < config.frame_x_radius: return True if self.get_bottom()[1] > config.frame_y_radius: return True return cast(float, self.get_top()[1]) < -config.frame_y_radius def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self: return self.stretch(factor, dim, about_point=point) def rescale_to_fit( self, length: float, dim: int, stretch: bool = False, **kwargs: Any, ) -> Self: old_length = self.length_over_dim(dim) if old_length == 0: return self if stretch: self.stretch(length / old_length, dim, **kwargs) else: self.scale(length / old_length, **kwargs) return self def stretch_to_fit_width(self, width: float, **kwargs: Any) -> Self: """Stretches the :class:`~.OpenGLMobject` to fit a width, not keeping height/depth proportional. Returns ------- :class:`OpenGLMobject` ``self`` Examples -------- :: >>> from manim import * >>> import numpy as np >>> sq = Square() >>> sq.height np.float64(2.0) >>> sq.stretch_to_fit_width(5) Square >>> sq.width np.float64(5.0) >>> sq.height np.float64(2.0) """ return self.rescale_to_fit(width, 0, stretch=True, **kwargs) def stretch_to_fit_height(self, height: float, **kwargs: Any) -> Self: """Stretches the :class:`~.OpenGLMobject` to fit a height, not keeping width/height proportional.""" return self.rescale_to_fit(height, 1, stretch=True, **kwargs) def stretch_to_fit_depth(self, depth: float, **kwargs: Any) -> Self: """Stretches the :class:`~.OpenGLMobject` to fit a depth, not keeping width/height proportional.""" return self.rescale_to_fit(depth, 1, stretch=True, **kwargs) def set_width( self, width: float, stretch: bool = False, **kwargs: Any, ) -> Self: """Scales the :class:`~.OpenGLMobject` to fit a width while keeping height/depth proportional. Returns ------- :class:`OpenGLMobject` ``self`` Examples -------- :: >>> from manim import * >>> import numpy as np >>> sq = Square() >>> sq.height np.float64(2.0) >>> sq.scale_to_fit_width(5) Square >>> sq.width np.float64(5.0) >>> sq.height np.float64(5.0) """ return self.rescale_to_fit(width, 0, stretch=stretch, **kwargs) scale_to_fit_width = set_width def set_height( self, height: float, stretch: bool = False, **kwargs: Any, ) -> Self: """Scales the :class:`~.OpenGLMobject` to fit a height while keeping width/depth proportional.""" return self.rescale_to_fit(height, 1, stretch=stretch, **kwargs) scale_to_fit_height = set_height def set_depth( self, depth: float, stretch: bool = False, **kwargs: Any, ) -> Self: """Scales the :class:`~.OpenGLMobject` to fit a depth while keeping width/height proportional.""" return self.rescale_to_fit(depth, 2, stretch=stretch, **kwargs) scale_to_fit_depth = set_depth def set_coord( self, value: float, dim: int, direction: Vector3DLike = ORIGIN ) -> Self: curr = self.get_coord(dim, direction) shift_vect = np.zeros(self.dim) shift_vect[dim] = value - curr self.shift(shift_vect) return self def set_x(self, x: float, direction: Vector3DLike = ORIGIN) -> Self: """Set x value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)""" return self.set_coord(x, 0, direction) def set_y(self, y: float, direction: Vector3DLike = ORIGIN) -> Self: """Set y value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)""" return self.set_coord(y, 1, direction) def set_z(self, z: float, direction: Vector3DLike = ORIGIN) -> Self: """Set z value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)""" return self.set_coord(z, 2, direction) def space_out_submobjects(self, factor: float = 1.5, **kwargs: Any) -> Self: self.scale(factor, **kwargs) for submob in self.submobjects: submob.scale(1.0 / factor) return self def move_to( self, point_or_mobject: Point3DLike | OpenGLMobject, aligned_edge: Vector3DLike = ORIGIN, coor_mask: Vector3DLike = np.array([1, 1, 1]), ) -> Self: """Move center of the :class:`~.OpenGLMobject` to certain coordinate.""" target: Point3DLike if isinstance(point_or_mobject, OpenGLMobject): target = point_or_mobject.get_bounding_box_point(aligned_edge) else: target = point_or_mobject point_to_align = self.get_bounding_box_point(aligned_edge) self.shift((target - point_to_align) * coor_mask) return self def replace( self, mobject: OpenGLMobject, dim_to_match: int = 0, stretch: bool = False, ) -> Self: if not mobject.get_num_points() and not mobject.submobjects: self.scale(0) return self if stretch: for i in range(self.dim): self.rescale_to_fit(mobject.length_over_dim(i), i, stretch=True) else: self.rescale_to_fit( mobject.length_over_dim(dim_to_match), dim_to_match, stretch=False, ) self.shift(mobject.get_center() - self.get_center()) return self def surround( self, mobject: OpenGLMobject, dim_to_match: int = 0, stretch: bool = False, buff: float = MED_SMALL_BUFF, ) -> Self: self.replace(mobject, dim_to_match, stretch) length = mobject.length_over_dim(dim_to_match) self.scale((length + buff) / length) return self def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self: curr_start, curr_end = self.get_start_and_end() curr_vect = curr_end - curr_start if np.all(curr_vect == 0): raise Exception("Cannot position endpoints of closed loop") target_vect = np.array(end) - np.array(start) axis = ( normalize(np.cross(curr_vect, target_vect)) if np.linalg.norm(np.cross(curr_vect, target_vect)) != 0 else OUT ) self.scale( float(np.linalg.norm(target_vect) / np.linalg.norm(curr_vect)), about_point=curr_start, ) self.rotate( angle_between_vectors(curr_vect, target_vect), about_point=curr_start, axis=axis, ) self.shift(start - curr_start) return self # Color functions def set_rgba_array( self, color: ParsableManimColor | Iterable[ParsableManimColor] | None = None, opacity: float | Iterable[float] | None = None, name: str = "rgbas", recurse: bool = True, ) -> Self: if color is not None: rgbs: FloatRGB_Array = np.array([color_to_rgb(c) for c in listify(color)]) if opacity is not None: opacities = listify(opacity) # Color only if color is not None and opacity is None: for mob in self.get_family(recurse): mob.data[name] = resize_array( mob.data[name] if name in mob.data else np.empty((1, 3)), len(rgbs) ) mob.data[name][:, :3] = rgbs # Opacity only if color is None and opacity is not None: for mob in self.get_family(recurse): mob.data[name] = resize_array( mob.data[name] if name in mob.data else np.empty((1, 3)), len(opacities), ) mob.data[name][:, 3] = opacities # Color and opacity if color is not None and opacity is not None: rgbas: FloatRGBA_Array = np.array( [[*rgb, o] for rgb, o in zip(*make_even(rgbs, opacities), strict=True)] ) for mob in self.get_family(recurse): mob.data[name] = rgbas.copy() return self def set_rgba_array_direct( self, rgbas: FloatRGBA_Array, name: str = "rgbas", recurse: bool = True, ) -> Self: """Directly set rgba data from `rgbas` and optionally do the same recursively with submobjects. This can be used if the `rgbas` have already been generated with the correct shape and simply need to be set. Parameters ---------- rgbas the rgba to be set as data name the name of the data attribute to be set recurse set to true to recursively apply this method to submobjects """ for mob in self.get_family(recurse): mob.data[name] = rgbas.copy() return self def set_color( self, color: ParsableManimColor | Sequence[ParsableManimColor] | None, opacity: float | Iterable[float] | None = None, recurse: bool = True, ) -> Self: self.set_rgba_array(color, opacity, recurse=False) # Recurse to submobjects differently from how set_rgba_array # in case they implement set_color differently if color is not None: self.color = ManimColor.parse(color) if opacity is not None: self.opacity = opacity if recurse: for submob in self.submobjects: submob.set_color(color, recurse=True) return self def set_opacity( self, opacity: float | Iterable[float] | None, recurse: bool = True ) -> Self: self.set_rgba_array(color=None, opacity=opacity, recurse=False) if recurse: for submob in self.submobjects: submob.set_opacity(opacity, recurse=True) return self def get_color(self) -> str: return rgb_to_hex(self.rgbas[0, :3]) def get_opacity(self) -> float: rv: float = self.rgbas[0, 3] return rv def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self: return self.set_submobject_colors_by_gradient(*colors) def set_submobject_colors_by_gradient(self, *colors: ParsableManimColor) -> Self: if len(colors) == 0: raise Exception("Need at least one color") elif len(colors) == 1: return self.set_color(*colors) # mobs = self.family_members_with_points() mobs = self.submobjects new_colors = color_gradient(colors, len(mobs)) for mob, color in zip(mobs, new_colors, strict=True): mob.set_color(color) return self def fade(self, darkness: float = 0.5, recurse: bool = True) -> Self: return self.set_opacity(1.0 - darkness, recurse=recurse) def get_gloss(self) -> float: return self.gloss def set_gloss(self, gloss: float, recurse: bool = True) -> Self: for mob in self.get_family(recurse): mob.gloss = gloss return self def get_shadow(self) -> float: return self.shadow def set_shadow(self, shadow: float, recurse: bool = True) -> Self: for mob in self.get_family(recurse): mob.shadow = shadow return self # Background rectangle def add_background_rectangle( self, color: ParsableManimColor | None = None, opacity: float = 0.75, **kwargs: Any, ) -> Self: # TODO, this does not behave well when the mobject has points, # since it gets displayed on top """Add a BackgroundRectangle as submobject. The BackgroundRectangle is added behind other submobjects. This can be used to increase the mobjects visibility in front of a noisy background. Parameters ---------- color The color of the BackgroundRectangle opacity The opacity of the BackgroundRectangle kwargs Additional keyword arguments passed to the BackgroundRectangle constructor Returns ------- :class:`OpenGLMobject` ``self`` See Also -------- :meth:`add_to_back` :class:`~.BackgroundRectangle` """ from manim.mobject.geometry.shape_matchers import BackgroundRectangle self.background_rectangle: BackgroundRectangle = BackgroundRectangle( self, # type: ignore[arg-type] color=color, fill_opacity=opacity, **kwargs, ) self.add_to_back(self.background_rectangle) # type: ignore[arg-type] return self def add_background_rectangle_to_submobjects(self, **kwargs: Any) -> Self: for submobject in self.submobjects: submobject.add_background_rectangle(**kwargs) return self def add_background_rectangle_to_family_members_with_points( self, **kwargs: Any ) -> Self: for mob in self.family_members_with_points(): mob.add_background_rectangle(**kwargs) return self # Getters def get_bounding_box_point(self, direction: Vector3DLike) -> Point3D: bb = self.get_bounding_box() indices = (np.sign(direction) + 1).astype(int) return np.array([bb[indices[i]][i] for i in range(3)]) def get_edge_center(self, direction: Vector3DLike) -> Point3D: """Get edge coordinates for certain direction.""" return self.get_bounding_box_point(direction) def get_corner(self, direction: Vector3DLike) -> Point3D: """Get corner coordinates for certain direction.""" return self.get_bounding_box_point(direction) def get_center(self) -> Point3D: """Get center coordinates.""" return self.get_bounding_box()[1] def get_center_of_mass(self) -> Point3D: return self.get_all_points().mean(0) def get_boundary_point(self, direction: Vector3DLike) -> Point3D: all_points = self.get_all_points() boundary_directions = all_points - self.get_center() norms = np.linalg.norm(boundary_directions, axis=1) boundary_directions /= np.repeat(norms, 3).reshape((len(norms), 3)) index = np.argmax(np.dot(boundary_directions, direction)) return all_points[index] def get_continuous_bounding_box_point(self, direction: Vector3DLike) -> Point3D: _dl, center, ur = self.get_bounding_box() corner_vect = ur - center np_direction = np.asarray(direction) return center + np_direction / np.max( np.abs( np.true_divide( np_direction, corner_vect, out=np.zeros(len(np_direction)), where=((corner_vect) != 0), ), ), ) def get_top(self) -> Point3D: """Get top coordinates of a box bounding the :class:`~.OpenGLMobject`""" return self.get_edge_center(UP) def get_bottom(self) -> Point3D: """Get bottom coordinates of a box bounding the :class:`~.OpenGLMobject`""" return self.get_edge_center(DOWN) def get_right(self) -> Point3D: """Get right coordinates of a box bounding the :class:`~.OpenGLMobject`""" return self.get_edge_center(RIGHT) def get_left(self) -> Point3D: """Get left coordinates of a box bounding the :class:`~.OpenGLMobject`""" return self.get_edge_center(LEFT) def get_zenith(self) -> Point3D: """Get zenith coordinates of a box bounding a 3D :class:`~.OpenGLMobject`.""" return self.get_edge_center(OUT) def get_nadir(self) -> Point3D: """Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.OpenGLMobject`.""" return self.get_edge_center(IN) def length_over_dim(self, dim: int) -> float: bb = self.get_bounding_box() rv: float = abs((bb[2] - bb[0])[dim]) return rv def get_width(self) -> float: """Returns the width of the mobject.""" return self.length_over_dim(0) def get_height(self) -> float: """Returns the height of the mobject.""" return self.length_over_dim(1) def get_depth(self) -> float: """Returns the depth of the mobject.""" return self.length_over_dim(2) def get_coord(self, dim: int, direction: Vector3DLike = ORIGIN) -> ManimFloat: """Meant to generalize ``get_x``, ``get_y`` and ``get_z``""" return self.get_bounding_box_point(direction)[dim] def get_x(self, direction: Vector3DLike = ORIGIN) -> ManimFloat: """Returns x coordinate of the center of the :class:`~.OpenGLMobject` as ``float``""" return self.get_coord(0, direction) def get_y(self, direction: Vector3DLike = ORIGIN) -> ManimFloat: """Returns y coordinate of the center of the :class:`~.OpenGLMobject` as ``float``""" return self.get_coord(1, direction) def get_z(self, direction: Vector3DLike = ORIGIN) -> ManimFloat: """Returns z coordinate of the center of the :class:`~.OpenGLMobject` as ``float``""" return self.get_coord(2, direction) def get_start(self) -> Point3D: """Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` starts.""" self.throw_error_if_no_points() return np.array(self.points[0]) def get_end(self) -> Point3D: """Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` ends.""" self.throw_error_if_no_points() return np.array(self.points[-1]) def get_start_and_end(self) -> tuple[Point3D, Point3D]: """Returns starting and ending point of a stroke as a ``tuple``.""" return self.get_start(), self.get_end() def point_from_proportion(self, alpha: float) -> Point3D: points = self.points i, subalpha = integer_interpolate(0, len(points) - 1, alpha) return interpolate(points[i], points[i + 1], subalpha) def pfp(self, alpha: float) -> Point3D: """Abbreviation for point_from_proportion""" return self.point_from_proportion(alpha) def get_pieces(self, n_pieces: int) -> OpenGLMobject: template = self.copy() template.submobjects = [] alphas = np.linspace(0, 1, n_pieces + 1) return OpenGLGroup( *( template.copy().pointwise_become_partial(self, a1, a2) for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True) ) ) def get_z_index_reference_point(self) -> Point3D: # TODO, better place to define default z_index_group? z_index_group = getattr(self, "z_index_group", self) return z_index_group.get_center() # Match other mobject properties def match_color(self, mobject: OpenGLMobject) -> Self: """Match the color with the color of another :class:`~.OpenGLMobject`.""" return self.set_color(mobject.get_color()) def match_dim_size( self, mobject: OpenGLMobject, dim: int, **kwargs: Any, ) -> Self: """Match the specified dimension with the dimension of another :class:`~.OpenGLMobject`.""" return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs) def match_width(self, mobject: OpenGLMobject, **kwargs: Any) -> Self: """Match the width with the width of another :class:`~.OpenGLMobject`.""" return self.match_dim_size(mobject, 0, **kwargs) def match_height(self, mobject: OpenGLMobject, **kwargs: Any) -> Self: """Match the height with the height of another :class:`~.OpenGLMobject`.""" return self.match_dim_size(mobject, 1, **kwargs) def match_depth(self, mobject: OpenGLMobject, **kwargs: Any) -> Self: """Match the depth with the depth of another :class:`~.OpenGLMobject`.""" return self.match_dim_size(mobject, 2, **kwargs) def match_coord( self, mobject: OpenGLMobject, dim: int, direction: Vector3DLike = ORIGIN ) -> Self: """Match the coordinates with the coordinates of another :class:`~.OpenGLMobject`.""" return self.set_coord( mobject.get_coord(dim, direction), dim=dim, direction=direction, ) def match_x(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self: """Match x coord. to the x coord. of another :class:`~.OpenGLMobject`.""" return self.match_coord(mobject, 0, direction) def match_y(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self: """Match y coord. to the x coord. of another :class:`~.OpenGLMobject`.""" return self.match_coord(mobject, 1, direction) def match_z(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self: """Match z coord. to the x coord. of another :class:`~.OpenGLMobject`.""" return self.match_coord(mobject, 2, direction) def align_to( self, mobject_or_point: OpenGLMobject | Point3DLike, direction: Vector3DLike = ORIGIN, ) -> Self: """ Examples: mob1.align_to(mob2, UP) moves mob1 vertically so that its top edge lines ups with mob2's top edge. mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1 horizontally so that it's center is directly above/below the center of mob2 """ point: Point3DLike if isinstance(mobject_or_point, OpenGLMobject): point = mobject_or_point.get_bounding_box_point(direction) else: point = mobject_or_point for dim in range(self.dim): if direction[dim] != 0: self.set_coord(point[dim], dim, direction) return self def get_group_class(self) -> type[OpenGLGroup]: return OpenGLGroup @staticmethod def get_mobject_type_class() -> type[OpenGLMobject]: """Return the base class of this mobject type.""" return OpenGLMobject # Alignment def align_data_and_family(self, mobject: OpenGLMobject) -> Self: self.align_family(mobject) self.align_data(mobject) return self def align_data(self, mobject: OpenGLMobject) -> Self: # In case any data arrays get resized when aligned to shader data # self.refresh_shader_data() for mob1, mob2 in zip(self.get_family(), mobject.get_family(), strict=False): # Separate out how points are treated so that subclasses # can handle that case differently if they choose mob1.align_points(mob2) for key in mob1.data.keys() & mob2.data.keys(): if key == "points": continue arr1 = mob1.data[key] arr2 = mob2.data[key] if len(arr2) > len(arr1): mob1.data[key] = resize_preserving_order(arr1, len(arr2)) elif len(arr1) > len(arr2): mob2.data[key] = resize_preserving_order(arr2, len(arr1)) return self def align_points(self, mobject: OpenGLMobject) -> Self: max_len = max(self.get_num_points(), mobject.get_num_points()) for mob in (self, mobject): mob.resize_points(max_len, resize_func=resize_preserving_order) return self def align_family(self, mobject: OpenGLMobject) -> Self: mob1 = self mob2 = mobject n1 = len(mob1) n2 = len(mob2) if n1 != n2: mob1.add_n_more_submobjects(max(0, n2 - n1)) mob2.add_n_more_submobjects(max(0, n1 - n2)) # Recurse for sm1, sm2 in zip(mob1.submobjects, mob2.submobjects, strict=True): sm1.align_family(sm2) return self def push_self_into_submobjects(self) -> Self: copy = self.deepcopy() copy.submobjects = [] self.resize_points(0) self.add(copy) return self def add_n_more_submobjects(self, n: int) -> Self: if n == 0: return self curr = len(self.submobjects) if curr == 0: # If empty, simply add n point mobjects null_mob = self.copy() null_mob.set_points([self.get_center()]) self.submobjects = [null_mob.copy() for k in range(n)] return self target = curr + n repeat_indices = (np.arange(target) * curr) // target split_factors = [(repeat_indices == i).sum() for i in range(curr)] new_submobs = [] for submob, sf in zip(self.submobjects, split_factors, strict=True): new_submobs.append(submob) for _ in range(1, sf): new_submob = submob.copy() # If the submobject is at all transparent, then # make the copy completely transparent if submob.get_opacity() < 1: new_submob.set_opacity(0) new_submobs.append(new_submob) self.submobjects = new_submobs return self # Interpolate def interpolate( self, mobject1: OpenGLMobject, mobject2: OpenGLMobject, alpha: float, path_func: PathFuncType = straight_path(), ) -> Self: """Turns this :class:`~.OpenGLMobject` into an interpolation between ``mobject1`` and ``mobject2``. Examples -------- .. manim:: DotInterpolation :save_last_frame: class DotInterpolation(Scene): def construct(self): dotR = Dot(color=DARK_GREY) dotR.shift(2 * RIGHT) dotL = Dot(color=WHITE) dotL.shift(2 * LEFT) dotMiddle = OpenGLVMobject().interpolate(dotL, dotR, alpha=0.3) self.add(dotL, dotR, dotMiddle) """ for key in self.data: if key in self.locked_data_keys: continue if len(self.data[key]) == 0: continue if key not in mobject1.data or key not in mobject2.data: continue func = path_func if key in ("points", "bounding_box") else interpolate self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha) for key in self.uniforms: if key != "fixed_orientation_center": self.uniforms[key] = interpolate( mobject1.uniforms[key], mobject2.uniforms[key], alpha, ) else: self.uniforms["fixed_orientation_center"] = tuple( interpolate( np.array(mobject1.uniforms["fixed_orientation_center"]), np.array(mobject2.uniforms["fixed_orientation_center"]), alpha, ) ) return self def pointwise_become_partial( self, mobject: OpenGLMobject, a: float, b: float ) -> Self: """ Set points in such a way as to become only part of mobject. Inputs 0 <= a < b <= 1 determine what portion of mobject to become. Returns `self` to allow method chaining. """ return self # To implement in subclass def become( self, mobject: OpenGLMobject, match_height: bool = False, match_width: bool = False, match_depth: bool = False, match_center: bool = False, stretch: bool = False, ) -> Self: """Edit all data and submobjects to be identical to another :class:`~.OpenGLMobject` .. note:: If both match_height and match_width are ``True`` then the transformed :class:`~.OpenGLMobject` will match the height first and then the width Parameters ---------- match_height If ``True``, then the transformed :class:`~.OpenGLMobject` will match the height of the original match_width If ``True``, then the transformed :class:`~.OpenGLMobject` will match the width of the original match_depth If ``True``, then the transformed :class:`~.OpenGLMobject` will match the depth of the original match_center If ``True``, then the transformed :class:`~.OpenGLMobject` will match the center of the original stretch If ``True``, then the transformed :class:`~.OpenGLMobject` will stretch to fit the proportions of the original Examples -------- .. manim:: BecomeScene class BecomeScene(Scene): def construct(self): circ = Circle(fill_color=RED, fill_opacity=0.8) square = Square(fill_color=BLUE, fill_opacity=0.2) self.add(circ) self.wait(0.5) circ.become(square) self.wait(0.5) """ if stretch: mobject.stretch_to_fit_height(self.height) mobject.stretch_to_fit_width(self.width) mobject.stretch_to_fit_depth(self.depth) else: if match_height: mobject.match_height(self) if match_width: mobject.match_width(self) if match_depth: mobject.match_depth(self) if match_center: mobject.move_to(self.get_center()) self.align_family(mobject) for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=True): sm1.set_data(sm2.data) sm1.set_uniforms(sm2.uniforms) self.refresh_bounding_box(recurse_down=True) return self # Locking data def lock_data(self, keys: Iterable[str]) -> None: """ To speed up some animations, particularly transformations, it can be handy to acknowledge which pieces of data won't change during the animation so that calls to interpolate can skip this, and so that it's not read into the shader_wrapper objects needlessly """ if self.has_updaters: return # Be sure shader data has most up to date information self.refresh_shader_data() self.locked_data_keys = set(keys) def lock_matching_data( self, mobject1: OpenGLMobject, mobject2: OpenGLMobject ) -> Self: for sm, sm1, sm2 in zip( self.get_family(), mobject1.get_family(), mobject2.get_family(), strict=False, ): keys = sm.data.keys() & sm1.data.keys() & sm2.data.keys() sm.lock_data( list( filter( lambda key: np.all(sm1.data[key] == sm2.data[key]), keys, ), ), ) return self def unlock_data(self) -> None: for mob in self.get_family(): mob.locked_data_keys = set() # Operations touching shader uniforms @affects_shader_info_id def fix_in_frame(self) -> Self: self.is_fixed_in_frame = 1.0 return self @affects_shader_info_id def fix_orientation(self) -> Self: self.is_fixed_orientation = 1.0 self.fixed_orientation_center = tuple(self.get_center()) self.depth_test = True return self @affects_shader_info_id def unfix_from_frame(self) -> Self: self.is_fixed_in_frame = 0.0 return self @affects_shader_info_id def unfix_orientation(self) -> Self: self.is_fixed_orientation = 0.0 self.fixed_orientation_center = (0, 0, 0) self.depth_test = False return self @affects_shader_info_id def apply_depth_test(self) -> Self: self.depth_test = True return self @affects_shader_info_id def deactivate_depth_test(self) -> Self: self.depth_test = False return self # Shader code manipulation def replace_shader_code(self, old_code: str, new_code: str) -> Self: # TODO, will this work with VMobject structure, given # that it does not simpler return shader_wrappers of # family? for wrapper in self.get_shader_wrapper_list(): wrapper.replace_code(old_code, new_code) return self def set_color_by_code(self, glsl_code: str) -> Self: """ Takes a snippet of code and inserts it into a context which has the following variables: vec4 color, vec3 point, vec3 unit_normal. The code should change the color variable """ self.replace_shader_code("///// INSERT COLOR FUNCTION HERE /////", glsl_code) return self def set_color_by_xyz_func( self, glsl_snippet: str, min_value: float = -5.0, max_value: float = 5.0, colormap: str = "viridis", ) -> Self: """ Pass in a glsl expression in terms of x, y and z which returns a float. """ # TODO, add a version of this which changes the point data instead # of the shader code for char in "xyz": glsl_snippet = glsl_snippet.replace(char, "point." + char) # TODO: get_colormap_list does not exist # See https://github.com/ManimCommunity/manim/issues/4176 rgb_list = get_colormap_list(colormap) # type: ignore[name-defined] self.set_color_by_code( f"color.rgb = float_to_color({glsl_snippet}, {float(min_value)}, {float(max_value)}, {get_colormap_code(rgb_list)});", ) return self # For shader data def refresh_shader_wrapper_id(self) -> Self: self.get_shader_wrapper().refresh_id() return self def get_shader_wrapper(self) -> "ShaderWrapper": # noqa: UP037 from manim.renderer.shader_wrapper import ShaderWrapper # if hasattr(self, "shader_wrapper"): # return self.shader_wrapper self.shader_wrapper: ShaderWrapper = ShaderWrapper( vert_data=self.get_shader_data(), vert_indices=self.get_shader_vert_indices(), uniforms=self.get_shader_uniforms(), depth_test=self.depth_test, texture_paths=self.texture_paths, render_primitive=self.render_primitive, shader_folder=self.__class__.shader_folder, ) return self.shader_wrapper def get_shader_wrapper_list(self) -> Sequence["ShaderWrapper"]: # noqa: UP037 shader_wrappers = it.chain( [self.get_shader_wrapper()], *(sm.get_shader_wrapper_list() for sm in self.submobjects), ) batches = batch_by_property(shader_wrappers, lambda sw: sw.get_id()) result: list["ShaderWrapper"] = [] # noqa: UP037 for wrapper_group, _ in batches: shader_wrapper = wrapper_group[0] if not shader_wrapper.is_valid(): continue shader_wrapper.combine_with(*wrapper_group[1:]) if len(shader_wrapper.vert_data) > 0: result.append(shader_wrapper) return result def check_data_alignment(self, array: _ShaderData, data_key: str) -> Self: # Makes sure that self.data[key] can be broadcast into # the given array, meaning its length has to be either 1 # or the length of the array d_len = len(self.data[data_key]) if d_len != 1 and d_len != len(array): self.data[data_key] = resize_with_interpolation( self.data[data_key], len(array), ) return self def get_resized_shader_data_array(self, length: float) -> _ShaderData: # If possible, try to populate an existing array, rather # than recreating it each frame points = self.points shader_data = cast(_ShaderData, np.zeros(len(points), dtype=self.shader_dtype)) return shader_data def read_data_to_shader( self, shader_data: _ShaderData, # has structured data type, ex. ("point", np.float32, (3,)) shader_data_key: str, data_key: str, ) -> None: if data_key in self.locked_data_keys: return self.check_data_alignment(shader_data, data_key) shader_data[shader_data_key] = self.data[data_key] def get_shader_data(self) -> _ShaderData: shader_data = self.get_resized_shader_data_array(self.get_num_points()) self.read_data_to_shader(shader_data, "point", "points") return shader_data def refresh_shader_data(self) -> None: self.get_shader_data() def get_shader_uniforms(self) -> dict[str, Any]: return self.uniforms def get_shader_vert_indices(self) -> Sequence[int] | None: return self.shader_indices @property def submobjects(self) -> list[OpenGLMobject]: return self._submobjects if hasattr(self, "_submobjects") else [] @submobjects.setter def submobjects(self, submobject_list: Iterable[OpenGLMobject]) -> None: self.remove(*self.submobjects) self.add(*submobject_list) # Errors def throw_error_if_no_points(self) -> None: if not self.has_points(): message = ( "Cannot call OpenGLMobject.{} " + "for a OpenGLMobject with no points" ) caller_name = sys._getframe(1).f_code.co_name raise Exception(message.format(caller_name)) class OpenGLGroup(OpenGLMobject): def __init__(self, *mobjects: OpenGLMobject, **kwargs: Any) -> None: super().__init__(**kwargs) self.add(*mobjects) class OpenGLPoint(OpenGLMobject): def __init__( self, location: Point3DLike = ORIGIN, artificial_width: float = 1e-6, artificial_height: float = 1e-6, **kwargs: Any, ) -> None: self.artificial_width: float = artificial_width self.artificial_height: float = artificial_height super().__init__(**kwargs) self.set_location(location) @override def get_width(self) -> float: return self.artificial_width @override def get_height(self) -> float: return self.artificial_height def get_location(self) -> Point3D: return cast("Point3D", self.points[0]).copy() @override def get_bounding_box_point(self, *args: object, **kwargs: Any) -> Point3D: return self.get_location() def set_location(self, new_loc: Point3DLike) -> None: self.set_points(np.array(new_loc, ndmin=2, dtype=float)) class _AnimationBuilder: def __init__(self, mobject: OpenGLMobject) -> None: self.mobject: OpenGLMobject = mobject self.mobject.generate_target() self.overridden_animation: Animation | None = None self.is_chaining: bool = False self.methods: list[MethodWithArgs] = [] # Whether animation args can be passed self.cannot_pass_args: bool = False self.anim_args: dict[str, object] = {} def __call__(self, **kwargs: Any) -> Self: if self.cannot_pass_args: raise ValueError( "Animation arguments must be passed before accessing methods and can only be passed once", ) self.anim_args = kwargs self.cannot_pass_args = True return self def __getattr__(self, method_name: str) -> Callable[..., Self]: method = getattr(self.mobject.target, method_name) has_overridden_animation = hasattr(method, "_override_animate") if (self.is_chaining and has_overridden_animation) or self.overridden_animation: raise NotImplementedError( "Method chaining is currently not supported for overridden animations", ) # NOTE: using `Self` here should not be a problem, because it's equivalent to a `TypeVar` introduced in `__getattr__`. # For this reason, here it's still in scope and can be used (that's why pyright does not flag this as an error). # However, mypy currently does not seem to understand this: hence the `type: ignore` comment. def update_target(*method_args: object, **method_kwargs: object) -> Self: # type: ignore[type-var, misc] if has_overridden_animation: self.overridden_animation = cast( "Callable[..., Animation]", method._override_animate )( self.mobject, *method_args, anim_args=self.anim_args, **method_kwargs, ) else: self.methods.append(MethodWithArgs(method, method_args, method_kwargs)) method(*method_args, **method_kwargs) return self self.is_chaining = True self.cannot_pass_args = True return update_target def build(self) -> "Animation": # noqa: UP037 from manim.animation.transform import _MethodAnimation # NOTE: To fix this mypy error, we'll need to update `_MethodAnimation` to accept `Mobject | OpenGLMobject` instead of `Mobject`. # Once that is done, the `type: ignore` comment below won't be necessary anymore and mypy will emit a corresponding warning. anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods) # type: ignore[arg-type] for attr, value in self.anim_args.items(): setattr(anim, attr, value) return anim _Decorated = TypeVar("_Decorated", bound=Callable[..., "Animation"]) class _OverrideAnimateDecorator(Protocol): # The slash divider on the next line prevents a mypy error in line 3176. def __call__(self, decorated: _Decorated, /) -> _Decorated: ... def override_animate(method: types.FunctionType) -> _OverrideAnimateDecorator: r"""Decorator for overriding method animations. This allows to specify a method (returning an :class:`~.Animation`) which is called when the decorated method is used with the ``.animate`` syntax for animating the application of a method. .. seealso:: :attr:`OpenGLMobject.animate` .. note:: Overridden methods cannot be combined with normal or other overridden methods using method chaining with the ``.animate`` syntax. Examples -------- .. manim:: AnimationOverrideExample class CircleWithContent(VGroup): def __init__(self, content): super().__init__() self.circle = Circle() self.content = content self.add(self.circle, content) content.move_to(self.circle.get_center()) def clear_content(self): self.remove(self.content) self.content = None @override_animate(clear_content) def _clear_content_animation(self, anim_args=None): if anim_args is None: anim_args = {} anim = Uncreate(self.content, **anim_args) self.clear_content() return anim class AnimationOverrideExample(Scene): def construct(self): t = Text("hello!") my_mobject = CircleWithContent(t) self.play(Create(my_mobject)) self.play(my_mobject.animate.clear_content()) self.wait() """ def decorator(animation_method: _Decorated) -> _Decorated: method._override_animate = animation_method # type: ignore[attr-defined] return animation_method return decorator ================================================ FILE: manim/mobject/opengl/opengl_point_cloud_mobject.py ================================================ from __future__ import annotations __all__ = ["OpenGLPMobject", "OpenGLPGroup", "OpenGLPMPoint"] from typing import TYPE_CHECKING import moderngl import numpy as np from manim.constants import * from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.utils.bezier import interpolate from manim.utils.color import ( BLACK, PURE_YELLOW, WHITE, ParsableManimColor, color_gradient, color_to_rgba, ) from manim.utils.config_ops import _Uniforms from manim.utils.iterables import resize_with_interpolation if TYPE_CHECKING: from typing import Self from manim.typing import ( FloatRGBA_Array, FloatRGBALike_Array, Point3D_Array, Point3DLike_Array, ) __all__ = ["OpenGLPMobject", "OpenGLPGroup", "OpenGLPMPoint"] class OpenGLPMobject(OpenGLMobject): shader_folder = "true_dot" # Scale for consistency with cairo units OPENGL_POINT_RADIUS_SCALE_FACTOR = 0.01 shader_dtype = [ ("point", np.float32, (3,)), ("color", np.float32, (4,)), ] point_radius = _Uniforms() def __init__( self, stroke_width: float = 2.0, color: ParsableManimColor = PURE_YELLOW, render_primitive: int = moderngl.POINTS, **kwargs, ): self.stroke_width = stroke_width super().__init__(color=color, render_primitive=render_primitive, **kwargs) self.point_radius = ( self.stroke_width * OpenGLPMobject.OPENGL_POINT_RADIUS_SCALE_FACTOR ) def reset_points(self) -> Self: self.rgbas: FloatRGBA_Array = np.zeros((1, 4)) self.points: Point3D_Array = np.zeros((0, 3)) return self def get_array_attrs(self): return ["points", "rgbas"] def add_points( self, points: Point3DLike_Array, rgbas: FloatRGBALike_Array | None = None, color: ParsableManimColor | None = None, opacity: float | None = None, ) -> Self: """Add points. Points must be a Nx3 numpy array. Rgbas must be a Nx4 numpy array if it is not None. """ if rgbas is None and color is None: color = PURE_YELLOW self.append_points(points) # rgbas array will have been resized with points if color is not None: if opacity is None: opacity = self.rgbas[-1, 3] new_rgbas = np.repeat([color_to_rgba(color, opacity)], len(points), axis=0) elif rgbas is not None: new_rgbas = rgbas elif len(rgbas) != len(points): raise ValueError("points and rgbas must have same length") self.rgbas = np.append(self.rgbas, new_rgbas, axis=0) return self def thin_out(self, factor=5): """Removes all but every nth point for n = factor""" for mob in self.family_members_with_points(): num_points = mob.get_num_points() def thin_func(num_points=num_points): return np.arange(0, num_points, factor) if len(mob.points) == len(mob.rgbas): mob.set_rgba_array_direct(mob.rgbas[thin_func()]) mob.set_points(mob.points[thin_func()]) return self def set_color_by_gradient(self, *colors): self.rgbas = np.array( list(map(color_to_rgba, color_gradient(*colors, self.get_num_points()))), ) return self def set_colors_by_radial_gradient( self, center=None, radius=1, inner_color=WHITE, outer_color=BLACK, ): start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color])) if center is None: center = self.get_center() for mob in self.family_members_with_points(): distances = np.abs(self.points - center) alphas = np.linalg.norm(distances, axis=1) / radius mob.rgbas = np.array( np.array( [interpolate(start_rgba, end_rgba, alpha) for alpha in alphas], ), ) return self def match_colors(self, pmobject): self.rgbas[:] = resize_with_interpolation(pmobject.rgbas, self.get_num_points()) return self def fade_to(self, color, alpha, family=True): rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha) for mob in self.submobjects: mob.fade_to(color, alpha, family) self.set_rgba_array_direct(rgbas) return self def filter_out(self, condition): for mob in self.family_members_with_points(): to_keep = ~np.apply_along_axis(condition, 1, mob.points) for key in mob.data: mob.data[key] = mob.data[key][to_keep] return self def sort_points(self, function=lambda p: p[0]): """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: mob.data[key] = mob.data[key][indices] return self def ingest_submobjects(self): for key in self.data: self.data[key] = np.vstack([sm.data[key] for sm in self.get_family()]) return self def point_from_proportion(self, alpha): index = alpha * (self.get_num_points() - 1) return self.points[int(index)] def pointwise_become_partial(self, pmobject, a, b): lower_index = int(a * pmobject.get_num_points()) upper_index = int(b * pmobject.get_num_points()) for key in self.data: self.data[key] = pmobject.data[key][lower_index:upper_index] return self def get_shader_data(self): shader_data = np.zeros(len(self.points), dtype=self.shader_dtype) self.read_data_to_shader(shader_data, "point", "points") self.read_data_to_shader(shader_data, "color", "rgbas") return shader_data @staticmethod def get_mobject_type_class(): return OpenGLPMobject class OpenGLPGroup(OpenGLPMobject): def __init__(self, *pmobs, **kwargs): if not all(isinstance(m, OpenGLPMobject) for m in pmobs): raise Exception("All submobjects must be of type OpenglPMObject") super().__init__(**kwargs) self.add(*pmobs) def fade_to(self, color, alpha, family=True): if family: for mob in self.submobjects: mob.fade_to(color, alpha, family) class OpenGLPMPoint(OpenGLPMobject): def __init__(self, location=ORIGIN, stroke_width=4.0, **kwargs): self.location = location super().__init__(stroke_width=stroke_width, **kwargs) def init_points(self): self.points = np.array([self.location], dtype=np.float32) ================================================ FILE: manim/mobject/opengl/opengl_surface.py ================================================ from __future__ import annotations from collections.abc import Iterable from pathlib import Path from typing import TYPE_CHECKING import moderngl import numpy as np from PIL import Image from manim.constants import * from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.utils.bezier import integer_interpolate, interpolate from manim.utils.color import * from manim.utils.config_ops import _Data, _Uniforms from manim.utils.images import change_to_rgba_array, get_full_raster_image_path from manim.utils.iterables import listify from manim.utils.space_ops import normalize_along_axis if TYPE_CHECKING: import numpy.typing as npt from manim.typing import Point3D_Array, Vector3D_Array __all__ = ["OpenGLSurface", "OpenGLTexturedSurface"] class OpenGLSurface(OpenGLMobject): r"""Creates a Surface. Parameters ---------- uv_func The function that defines the surface. u_range The range of the ``u`` variable: ``(u_min, u_max)``. v_range The range of the ``v`` variable: ``(v_min, v_max)``. resolution The number of samples taken of the surface. axes Axes on which the surface is to be drawn. Optional parameter used when coloring a surface by z-value. color Color of the surface. Defaults to grey. colorscale Colors of the surface. Optional parameter used when coloring a surface by values. Passing a list of colors and an axes will color the surface by z-value. Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots where the color transitions. colorscale_axis Defines the axis on which the colorscale is applied (0 = x, 1 = y, 2 = z), default is z-axis (2). opacity Opacity of the surface from 0 being fully transparent to 1 being fully opaque. Defaults to 1. """ shader_dtype = [ ("point", np.float32, (3,)), ("du_point", np.float32, (3,)), ("dv_point", np.float32, (3,)), ("color", np.float32, (4,)), ] shader_folder = "surface" def __init__( self, uv_func=None, u_range=None, v_range=None, # Resolution counts number of points sampled, which for # each coordinate is one more than the the number of # rows/columns of approximating squares resolution=None, axes=None, color=GREY, colorscale=None, colorscale_axis=2, opacity=1.0, gloss=0.3, shadow=0.4, prefered_creation_axis=1, # For du and dv steps. Much smaller and numerical error # can crop up in the shaders. epsilon=1e-5, render_primitive=moderngl.TRIANGLES, depth_test=True, shader_folder=None, **kwargs: Any, ): self.passed_uv_func = uv_func self.u_range = u_range if u_range is not None else (0, 1) self.v_range = v_range if v_range is not None else (0, 1) # Resolution counts number of points sampled, which for # each coordinate is one more than the the number of # rows/columns of approximating squares self.resolution = resolution if resolution is not None else (101, 101) self.axes = axes self.colorscale = colorscale self.colorscale_axis = colorscale_axis self.prefered_creation_axis = prefered_creation_axis # For du and dv steps. Much smaller and numerical error # can crop up in the shaders. self.epsilon = epsilon self.triangle_indices = None super().__init__( color=color, opacity=opacity, gloss=gloss, shadow=shadow, shader_folder=shader_folder if shader_folder is not None else "surface", render_primitive=render_primitive, depth_test=depth_test, **kwargs, ) self.compute_triangle_indices() def uv_func(self, u, v): # To be implemented in subclasses if self.passed_uv_func: return self.passed_uv_func(u, v) return (u, v, 0.0) def init_points(self): dim = self.dim nu, nv = self.resolution u_range = np.linspace(*self.u_range, nu) v_range = np.linspace(*self.v_range, nv) # Get three lists: # - Points generated by pure uv values # - Those generated by values nudged by du # - Those generated by values nudged by dv point_lists = [] for du, dv in [(0, 0), (self.epsilon, 0), (0, self.epsilon)]: uv_grid = np.array([[[u + du, v + dv] for v in v_range] for u in u_range]) point_grid = np.apply_along_axis(lambda p: self.uv_func(*p), 2, uv_grid) point_lists.append(point_grid.reshape((nu * nv, dim))) # Rather than tracking normal vectors, the points list will hold on to the # infinitesimal nudged values alongside the original values. This way, one # can perform all the manipulations they'd like to the surface, and normals # are still easily recoverable. self.set_points(np.vstack(point_lists)) def compute_triangle_indices(self): # TODO, if there is an event which changes # the resolution of the surface, make sure # this is called. nu, nv = self.resolution if nu == 0 or nv == 0: self.triangle_indices = np.zeros(0, dtype=int) return index_grid = np.arange(nu * nv).reshape((nu, nv)) indices = np.zeros(6 * (nu - 1) * (nv - 1), dtype=int) indices[0::6] = index_grid[:-1, :-1].flatten() # Top left indices[1::6] = index_grid[+1:, :-1].flatten() # Bottom left indices[2::6] = index_grid[:-1, +1:].flatten() # Top right indices[3::6] = index_grid[:-1, +1:].flatten() # Top right indices[4::6] = index_grid[+1:, :-1].flatten() # Bottom left indices[5::6] = index_grid[+1:, +1:].flatten() # Bottom right self.triangle_indices = indices def get_triangle_indices(self): return self.triangle_indices def get_surface_points_and_nudged_points( self, ) -> tuple[Point3D_Array, Point3D_Array, Point3D_Array]: points = self.points k = len(points) // 3 return points[:k], points[k : 2 * k], points[2 * k :] def get_unit_normals(self) -> Vector3D_Array: s_points, du_points, dv_points = self.get_surface_points_and_nudged_points() normals = np.cross( (du_points - s_points) / self.epsilon, (dv_points - s_points) / self.epsilon, ) return normalize_along_axis(normals, 1) def pointwise_become_partial(self, smobject, a, b, axis=None): assert isinstance(smobject, OpenGLSurface) if axis is None: axis = self.prefered_creation_axis if a <= 0 and b >= 1: self.match_points(smobject) return self nu, nv = smobject.resolution self.set_points( np.vstack( [ self.get_partial_points_array( arr.copy(), a, b, (nu, nv, 3), axis=axis, ) for arr in smobject.get_surface_points_and_nudged_points() ], ), ) return self def get_partial_points_array(self, points, a, b, resolution, axis): if len(points) == 0: return points nu, nv = resolution[:2] points = points.reshape(resolution) max_index = resolution[axis] - 1 lower_index, lower_residue = integer_interpolate(0, max_index, a) upper_index, upper_residue = integer_interpolate(0, max_index, b) if axis == 0: points[:lower_index] = interpolate( points[lower_index], points[lower_index + 1], lower_residue, ) points[upper_index + 1 :] = interpolate( points[upper_index], points[upper_index + 1], upper_residue, ) else: shape = (nu, 1, resolution[2]) points[:, :lower_index] = interpolate( points[:, lower_index], points[:, lower_index + 1], lower_residue, ).reshape(shape) points[:, upper_index + 1 :] = interpolate( points[:, upper_index], points[:, upper_index + 1], upper_residue, ).reshape(shape) return points.reshape((nu * nv, *resolution[2:])) def sort_faces_back_to_front(self, vect=OUT): tri_is = self.triangle_indices indices = list(range(len(tri_is) // 3)) points = self.points def index_dot(index): return np.dot(points[tri_is[3 * index]], vect) indices.sort(key=index_dot) for k in range(3): tri_is[k::3] = tri_is[k::3][indices] return self # For shaders def get_shader_data(self): """Called by parent Mobject to calculate and return the shader data. Returns ------- shader_dtype An array containing the shader data (vertices and color of each vertex) """ s_points, du_points, dv_points = self.get_surface_points_and_nudged_points() shader_data = np.zeros(len(s_points), dtype=self.shader_dtype) if "points" not in self.locked_data_keys: shader_data["point"] = s_points shader_data["du_point"] = du_points shader_data["dv_point"] = dv_points if self.colorscale: if not hasattr(self, "color_by_val"): self.color_by_val = self._get_color_by_value(s_points) shader_data["color"] = self.color_by_val else: self.fill_in_shader_color_info(shader_data) return shader_data def fill_in_shader_color_info(self, shader_data): """Fills in the shader color data when the surface is all one color. Parameters ---------- shader_data The vertices of the surface. Returns ------- shader_dtype An array containing the shader data (vertices and color of each vertex) """ self.read_data_to_shader(shader_data, "color", "rgbas") return shader_data def _get_color_by_value(self, s_points): """Matches each vertex to a color associated to it's z-value. Parameters ---------- s_points The vertices of the surface. Returns ------- List A list of colors matching the vertex inputs. """ if type(self.colorscale[0]) in (list, tuple): new_colors, pivots = [ [i for i, j in self.colorscale], [j for i, j in self.colorscale], ] else: new_colors = self.colorscale pivot_min = self.axes.z_range[0] pivot_max = self.axes.z_range[1] pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1) pivots = np.arange( start=pivot_min, stop=pivot_max + pivot_frequency, step=pivot_frequency, ) return_colors = [] for point in s_points: axis_value = self.axes.point_to_coords(point)[self.colorscale_axis] if axis_value <= pivots[0]: return_colors.append(color_to_rgba(new_colors[0], self.opacity)) elif axis_value >= pivots[-1]: return_colors.append(color_to_rgba(new_colors[-1], self.opacity)) else: for i, pivot in enumerate(pivots): if pivot > axis_value: color_index = (axis_value - pivots[i - 1]) / ( pivots[i] - pivots[i - 1] ) color_index = max(min(color_index, 1), 0) temp_color = interpolate_color( new_colors[i - 1], new_colors[i], color_index, ) break return_colors.append(color_to_rgba(temp_color, self.opacity)) return return_colors def get_shader_vert_indices(self): return self.get_triangle_indices() class OpenGLSurfaceGroup(OpenGLSurface): def __init__(self, *parametric_surfaces, resolution=None, **kwargs): self.resolution = (0, 0) if resolution is None else resolution super().__init__(uv_func=None, **kwargs) self.add(*parametric_surfaces) def init_points(self): pass # Needed? class OpenGLTexturedSurface(OpenGLSurface): shader_dtype = [ ("point", np.float32, (3,)), ("du_point", np.float32, (3,)), ("dv_point", np.float32, (3,)), ("im_coords", np.float32, (2,)), ("opacity", np.float32, (1,)), ] shader_folder = "textured_surface" im_coords = _Data() opacity = _Data() num_textures = _Uniforms() def __init__( self, uv_surface: OpenGLSurface, image_file: str | Path | npt.NDArray, dark_image_file: str | Path = None, image_mode: str | Iterable[str] = "RGBA", shader_folder: str | Path = None, **kwargs, ): self.uniforms = {} if not isinstance(uv_surface, OpenGLSurface): raise Exception("uv_surface must be of type OpenGLSurface") if isinstance(image_file, np.ndarray): image_file = change_to_rgba_array(image_file) # Set texture information if isinstance(image_mode, (str, Path)): image_mode = [image_mode] * 2 image_mode_light, image_mode_dark = image_mode texture_paths = { "LightTexture": self.get_image_from_file( image_file, image_mode_light, ), "DarkTexture": self.get_image_from_file( dark_image_file or image_file, image_mode_dark, ), } if dark_image_file: self.num_textures = 2 self.uv_surface = uv_surface self.uv_func = uv_surface.uv_func self.u_range = uv_surface.u_range self.v_range = uv_surface.v_range self.resolution = uv_surface.resolution self.gloss = self.uv_surface.gloss super().__init__(texture_paths=texture_paths, **kwargs) def get_image_from_file( self, image_file: str | Path, image_mode: str, ) -> Image.Image: image_file = get_full_raster_image_path(image_file) return Image.open(image_file).convert(image_mode) def init_data(self): super().init_data() self.im_coords = np.zeros((0, 2)) self.opacity = np.zeros((0, 1)) def init_points(self): nu, nv = self.uv_surface.resolution self.set_points(self.uv_surface.points) self.im_coords = np.array( [ [u, v] for u in np.linspace(0, 1, nu) for v in np.linspace(1, 0, nv) # Reverse y-direction ], ) def init_colors(self): self.opacity = np.array([self.uv_surface.rgbas[:, 3]]) def set_opacity(self, opacity, recurse=True): for mob in self.get_family(recurse): mob.opacity = np.array([[o] for o in listify(opacity)]) return self def pointwise_become_partial(self, tsmobject, a, b, axis=1): super().pointwise_become_partial(tsmobject, a, b, axis) im_coords = self.im_coords im_coords[:] = tsmobject.im_coords if a <= 0 and b >= 1: return self nu, nv = tsmobject.resolution im_coords[:] = self.get_partial_points_array(im_coords, a, b, (nu, nv, 2), axis) return self def fill_in_shader_color_info(self, shader_data): self.read_data_to_shader(shader_data, "opacity", "opacity") self.read_data_to_shader(shader_data, "im_coords", "im_coords") return shader_data ================================================ FILE: manim/mobject/opengl/opengl_three_dimensions.py ================================================ from __future__ import annotations from typing import Any import numpy as np from manim.mobject.opengl.opengl_surface import OpenGLSurface from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject __all__ = ["OpenGLSurfaceMesh"] class OpenGLSurfaceMesh(OpenGLVGroup): def __init__( self, uv_surface: OpenGLSurface, resolution: tuple[int, int] | None = None, stroke_width: float = 1, normal_nudge: float = 1e-2, depth_test: bool = True, flat_stroke: bool = False, **kwargs: Any, ): if not isinstance(uv_surface, OpenGLSurface): raise Exception("uv_surface must be of type OpenGLSurface") self.uv_surface = uv_surface self.resolution = resolution if resolution is not None else (21, 21) self.normal_nudge = normal_nudge super().__init__( stroke_width=stroke_width, depth_test=depth_test, flat_stroke=flat_stroke, **kwargs, ) def init_points(self) -> None: uv_surface = self.uv_surface full_nu, full_nv = uv_surface.resolution part_nu, part_nv = self.resolution u_indices = np.linspace(0, full_nu, part_nu).astype(int) v_indices = np.linspace(0, full_nv, part_nv).astype(int) points, du_points, dv_points = uv_surface.get_surface_points_and_nudged_points() normals = uv_surface.get_unit_normals() nudged_points = points + self.normal_nudge * normals for ui in u_indices: path = OpenGLVMobject() full_ui = full_nv * ui path.set_points_smoothly(nudged_points[full_ui : full_ui + full_nv]) self.add(path) for vi in v_indices: path = OpenGLVMobject() path.set_points_smoothly(nudged_points[vi::full_nv]) self.add(path) ================================================ FILE: manim/mobject/opengl/opengl_vectorized_mobject.py ================================================ from __future__ import annotations import itertools as it import operator as op from collections.abc import Callable, Iterable, Sequence from functools import reduce, wraps from typing import Any, Self import moderngl import numpy as np from manim import config from manim.constants import * from manim.mobject.opengl.opengl_mobject import OpenGLMobject, OpenGLPoint from manim.renderer.shader_wrapper import ShaderWrapper from manim.typing import Point3D, Point3DLike, Point3DLike_Array from manim.utils.bezier import ( bezier, bezier_remap, get_quadratic_approximation_of_cubic, get_smooth_cubic_bezier_handle_points, integer_interpolate, interpolate, partial_bezier_points, proportions_along_bezier_curve_for_point, ) from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor from manim.utils.config_ops import _Data from manim.utils.iterables import make_even, resize_with_interpolation, tuplify from manim.utils.space_ops import ( angle_between_vectors, cross2d, earclip_triangulation, get_unit_normal, shoelace_direction, z_to_vector, ) __all__ = [ "triggers_refreshed_triangulation", "OpenGLVMobject", "OpenGLVGroup", "OpenGLVectorizedPoint", "OpenGLCurvesAsSubmobjects", "OpenGLDashedVMobject", ] def triggers_refreshed_triangulation(func): @wraps(func) def wrapper(self, *args, **kwargs): old_points = np.empty((0, 3)) for mob in self.family_members_with_points(): old_points = np.concatenate((old_points, mob.points), axis=0) func(self, *args, **kwargs) new_points = np.empty((0, 3)) for mob in self.family_members_with_points(): new_points = np.concatenate((new_points, mob.points), axis=0) if not np.array_equal(new_points, old_points): self.refresh_triangulation() self.refresh_unit_normal() return self return wrapper class OpenGLVMobject(OpenGLMobject): """A vectorized mobject.""" fill_dtype = [ ("point", np.float32, (3,)), ("unit_normal", np.float32, (3,)), ("color", np.float32, (4,)), ("vert_index", np.float32, (1,)), ] stroke_dtype = [ ("point", np.float32, (3,)), ("prev_point", np.float32, (3,)), ("next_point", np.float32, (3,)), ("unit_normal", np.float32, (3,)), ("stroke_width", np.float32, (1,)), ("color", np.float32, (4,)), ] stroke_shader_folder = "quadratic_bezier_stroke" fill_shader_folder = "quadratic_bezier_fill" # TODO: although these are called "rgba" in singular, they are used as # FloatRGBA_Arrays and should be called instead "rgbas" in plural for consistency. # The same should probably apply for "stroke_width" and "unit_normal". fill_rgba = _Data() stroke_rgba = _Data() stroke_width = _Data() unit_normal = _Data() def __init__( self, fill_color: ParsableManimColor | None = None, fill_opacity: float = 0.0, stroke_color: ParsableManimColor | None = None, stroke_opacity: float = 1.0, stroke_width: float = DEFAULT_STROKE_WIDTH, draw_stroke_behind_fill: bool = False, # Indicates that it will not be displayed, but # that it should count in parent mobject's path pre_function_handle_to_anchor_scale_factor: float = 0.01, make_smooth_after_applying_functions: float = False, background_image_file: str | None = None, # This is within a pixel # TODO, do we care about accounting for # varying zoom levels? tolerance_for_point_equality: float = 1e-8, n_points_per_curve: int = 3, long_lines: bool = False, should_subdivide_sharp_curves: bool = False, should_remove_null_curves: bool = False, # Could also be "bevel", "miter", "round" joint_type: LineJointType | None = None, flat_stroke: bool = True, render_primitive=moderngl.TRIANGLES, triangulation_locked: bool = False, **kwargs, ): self.data = {} self.fill_opacity = fill_opacity self.stroke_opacity = stroke_opacity self.stroke_width = stroke_width self.draw_stroke_behind_fill = draw_stroke_behind_fill # Indicates that it will not be displayed, but # that it should count in parent mobject's path self.pre_function_handle_to_anchor_scale_factor = ( pre_function_handle_to_anchor_scale_factor ) self.make_smooth_after_applying_functions = make_smooth_after_applying_functions self.background_image_file = background_image_file # This is within a pixel # TODO, do we care about accounting for # varying zoom levels? self.tolerance_for_point_equality = tolerance_for_point_equality self.n_points_per_curve = n_points_per_curve self.long_lines = long_lines self.should_subdivide_sharp_curves = should_subdivide_sharp_curves self.should_remove_null_curves = should_remove_null_curves if joint_type is None: joint_type = LineJointType.AUTO self.joint_type = joint_type self.flat_stroke = flat_stroke self.render_primitive = render_primitive self.triangulation_locked = triangulation_locked self.needs_new_triangulation = True self.triangulation = np.zeros(0, dtype="i4") self.orientation = 1 self.fill_data = None self.stroke_data = None self.fill_shader_wrapper = None self.stroke_shader_wrapper = None self.init_shader_data() super().__init__(**kwargs) self.refresh_unit_normal() if fill_color is not None: self.fill_color = ManimColor.parse(fill_color) if stroke_color is not None: self.stroke_color = ManimColor.parse(stroke_color) def _assert_valid_submobjects(self, submobjects: Iterable[OpenGLVMobject]) -> Self: return self._assert_valid_submobjects_internal(submobjects, OpenGLVMobject) def get_group_class(self): return OpenGLVGroup @staticmethod def get_mobject_type_class(): return OpenGLVMobject @property def submobjects(self) -> Sequence[OpenGLVMobject]: return self._submobjects if hasattr(self, "_submobjects") else [] @submobjects.setter def submobjects(self, submobject_list: Iterable[OpenGLVMobject]) -> None: self.remove(*self.submobjects) self.add(*submobject_list) def init_data(self): super().init_data() self.data.pop("rgbas") self.fill_rgba = np.zeros((1, 4)) self.stroke_rgba = np.zeros((1, 4)) self.unit_normal = np.zeros((1, 3)) # stroke_width belongs to self.data, but is defined through init_colors+set_stroke # Colors def init_colors(self): self.set_fill( color=self.fill_color or self.color, opacity=self.fill_opacity, ) self.set_stroke( color=self.stroke_color or self.color, width=self.stroke_width, opacity=self.stroke_opacity, background=self.draw_stroke_behind_fill, ) self.set_gloss(self.gloss) self.set_flat_stroke(self.flat_stroke) return self def set_fill( self, color: ParsableManimColor | None = None, opacity: float | None = None, recurse: bool = True, ) -> OpenGLVMobject: """Set the fill color and fill opacity of a :class:`OpenGLVMobject`. Parameters ---------- color Fill color of the :class:`OpenGLVMobject`. opacity Fill opacity of the :class:`OpenGLVMobject`. recurse If ``True``, the fill color of all submobjects is also set. Returns ------- OpenGLVMobject self. For chaining purposes. Examples -------- .. manim:: SetFill :save_last_frame: class SetFill(Scene): def construct(self): square = Square().scale(2).set_fill(WHITE,1) circle1 = Circle().set_fill(GREEN,0.8) circle2 = Circle().set_fill(YELLOW) # No fill_opacity circle3 = Circle().set_fill(color = '#FF2135', opacity = 0.2) group = Group(circle1,circle2,circle3).arrange() self.add(square) self.add(group) See Also -------- :meth:`~.OpenGLVMobject.set_style` """ if opacity is not None: self.fill_opacity = opacity if recurse: for submobject in self.submobjects: submobject.set_fill(color, opacity, recurse) self.set_rgba_array(color, opacity, "fill_rgba", recurse) return self def set_stroke( self, color=None, width=None, opacity=None, background=None, recurse=True, ): if opacity is not None: self.stroke_opacity = opacity if recurse: for submobject in self.submobjects: submobject.set_stroke( color=color, width=width, opacity=opacity, background=background, recurse=recurse, ) self.set_rgba_array(color, opacity, "stroke_rgba", recurse) if width is not None: for mob in self.get_family(recurse): if isinstance(width, np.ndarray): mob.stroke_width = width else: mob.stroke_width = np.array([[width] for width in tuplify(width)]) if background is not None: for mob in self.get_family(recurse): mob.draw_stroke_behind_fill = background return self def set_style( self, fill_color=None, fill_opacity=None, fill_rgba=None, stroke_color=None, stroke_opacity=None, stroke_rgba=None, stroke_width=None, gloss=None, shadow=None, recurse=True, ): if fill_rgba is not None: self.fill_rgba = resize_with_interpolation(fill_rgba, len(fill_rgba)) else: self.set_fill(color=fill_color, opacity=fill_opacity, recurse=recurse) if stroke_rgba is not None: self.stroke_rgba = resize_with_interpolation(stroke_rgba, len(fill_rgba)) self.set_stroke(width=stroke_width) else: self.set_stroke( color=stroke_color, width=stroke_width, opacity=stroke_opacity, recurse=recurse, ) if gloss is not None: self.set_gloss(gloss, recurse=recurse) if shadow is not None: self.set_shadow(shadow, recurse=recurse) return self def get_style(self): return { "fill_rgba": self.fill_rgba, "stroke_rgba": self.stroke_rgba, "stroke_width": self.stroke_width, "gloss": self.gloss, "shadow": self.shadow, } def match_style(self, vmobject, recurse=True): vmobject_style = vmobject.get_style() if config.renderer == RendererType.OPENGL: vmobject_style["stroke_width"] = vmobject_style["stroke_width"][0][0] vmobject_style["fill_opacity"] = self.get_fill_opacity() self.set_style(**vmobject_style, recurse=False) if recurse: # Does its best to match up submobject lists, and # match styles accordingly submobs1, submobs2 = self.submobjects, vmobject.submobjects if len(submobs1) == 0: return self elif len(submobs2) == 0: submobs2 = [vmobject] for sm1, sm2 in zip(*make_even(submobs1, submobs2), strict=True): sm1.match_style(sm2) return self def set_color(self, color, opacity=None, recurse=True): if opacity is not None: self.opacity = opacity self.set_fill(color, opacity=opacity, recurse=recurse) self.set_stroke(color, opacity=opacity, recurse=recurse) return self def set_opacity(self, opacity, recurse=True): self.set_fill(opacity=opacity, recurse=recurse) self.set_stroke(opacity=opacity, recurse=recurse) return self def fade(self, darkness=0.5, recurse=True): factor = 1.0 - darkness self.set_fill( opacity=factor * self.get_fill_opacity(), recurse=False, ) self.set_stroke( opacity=factor * self.get_stroke_opacity(), recurse=False, ) super().fade(darkness, recurse) return self # Todo im not quite sure why we are doing this def get_fill_colors(self): return [ManimColor.from_rgb(rgba[:3]) for rgba in self.fill_rgba] def get_fill_opacities(self): return self.fill_rgba[:, 3] def get_stroke_colors(self): return [ManimColor.from_rgb(rgba[:3]) for rgba in self.stroke_rgba] def get_stroke_opacities(self): return self.stroke_rgba[:, 3] def get_stroke_widths(self): return self.stroke_width # TODO, it's weird for these to return the first of various lists # rather than the full information def get_fill_color(self): """ If there are multiple colors (for gradient) this returns the first one """ return self.get_fill_colors()[0] def get_fill_opacity(self): """ If there are multiple opacities, this returns the first """ return self.get_fill_opacities()[0] def get_stroke_color(self): return self.get_stroke_colors()[0] def get_stroke_width(self): return self.get_stroke_widths()[0] def get_stroke_opacity(self): return self.get_stroke_opacities()[0] def get_color(self): if not self.has_fill(): return self.get_stroke_color() return self.get_fill_color() def get_colors(self): if self.has_stroke(): return self.get_stroke_colors() return self.get_fill_colors() stroke_color = property(get_stroke_color, set_stroke) color = property(get_color, set_color) fill_color = property(get_fill_color, set_fill) def has_stroke(self): stroke_widths = self.get_stroke_widths() stroke_opacities = self.get_stroke_opacities() return ( stroke_widths is not None and stroke_opacities is not None and any(stroke_widths) and any(stroke_opacities) ) def has_fill(self): fill_opacities = self.get_fill_opacities() return fill_opacities is not None and any(fill_opacities) def get_opacity(self): if self.has_fill(): return self.get_fill_opacity() return self.get_stroke_opacity() def set_flat_stroke(self, flat_stroke=True, recurse=True): for mob in self.get_family(recurse): mob.flat_stroke = flat_stroke return self def get_flat_stroke(self): return self.flat_stroke # Points def set_anchors_and_handles(self, anchors1, handles, anchors2): assert len(anchors1) == len(handles) == len(anchors2) nppc = self.n_points_per_curve new_points = np.zeros((nppc * len(anchors1), self.dim)) arrays = [anchors1, handles, anchors2] for index, array in enumerate(arrays): new_points[index::nppc] = array self.set_points(new_points) return self def start_new_path(self, point): assert self.get_num_points() % self.n_points_per_curve == 0 self.append_points([point]) return self def add_cubic_bezier_curve( self, anchor1: Point3DLike, handle1: Point3DLike, handle2: Point3DLike, anchor2: Point3DLike, ): new_points = get_quadratic_approximation_of_cubic( anchor1, handle1, handle2, anchor2, ) self.append_points(new_points) def add_cubic_bezier_curve_to(self, handle1, handle2, anchor): """Add cubic bezier curve to the path.""" self.throw_error_if_no_points() quadratic_approx = get_quadratic_approximation_of_cubic( self.get_last_point(), handle1, handle2, anchor, ) if self.has_new_path_started(): self.append_points(quadratic_approx[1:]) else: self.append_points(quadratic_approx) def add_quadratic_bezier_curve_to(self, handle, anchor): self.throw_error_if_no_points() if self.has_new_path_started(): self.append_points([handle, anchor]) else: self.append_points([self.get_last_point(), handle, anchor]) def add_line_to(self, point: Sequence[float]) -> OpenGLVMobject: """Add a straight line from the last point of OpenGLVMobject to the given point. Parameters ---------- point end of the straight line. """ end = self.points[-1] alphas = np.linspace(0, 1, self.n_points_per_curve) if self.long_lines: halfway = interpolate(end, point, 0.5) points = [interpolate(end, halfway, a) for a in alphas] + [ interpolate(halfway, point, a) for a in alphas ] else: points = [interpolate(end, point, a) for a in alphas] if self.has_new_path_started(): points = points[1:] self.append_points(points) return self def add_smooth_curve_to(self, point): if self.has_new_path_started(): self.add_line_to(point) else: self.throw_error_if_no_points() new_handle = self.get_reflection_of_last_handle() self.add_quadratic_bezier_curve_to(new_handle, point) return self def add_smooth_cubic_curve_to(self, handle, point): self.throw_error_if_no_points() new_handle = self.get_reflection_of_last_handle() self.add_cubic_bezier_curve_to(new_handle, handle, point) def has_new_path_started(self): return self.get_num_points() % self.n_points_per_curve == 1 def get_last_point(self): return self.points[-1] def get_reflection_of_last_handle(self): points = self.points return 2 * points[-1] - points[-2] def close_path(self): if not self.is_closed(): self.add_line_to(self.get_subpaths()[-1][0]) def is_closed(self): return self.consider_points_equals(self.points[0], self.points[-1]) def subdivide_sharp_curves(self, angle_threshold=30 * DEGREES, recurse=True): vmobs = [vm for vm in self.get_family(recurse) if vm.has_points()] for vmob in vmobs: new_points = [] for tup in vmob.get_bezier_tuples(): angle = angle_between_vectors(tup[1] - tup[0], tup[2] - tup[1]) if angle > angle_threshold: n = int(np.ceil(angle / angle_threshold)) alphas = np.linspace(0, 1, n + 1) new_points.extend( [ partial_bezier_points(tup, a1, a2) for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True) ], ) else: new_points.append(tup) vmob.set_points(np.vstack(new_points)) return self def add_points_as_corners(self, points): for point in points: self.add_line_to(point) return points def set_points_as_corners(self, points: Point3DLike_Array) -> OpenGLVMobject: """Given an array of points, set them as corner of the vmobject. To achieve that, this algorithm sets handles aligned with the anchors such that the resultant bezier curve will be the segment between the two anchors. Parameters ---------- points Array of points that will be set as corners. Returns ------- OpenGLVMobject self. For chaining purposes. """ nppc = self.n_points_per_curve points = np.array(points) self.set_anchors_and_handles( *(interpolate(points[:-1], points[1:], a) for a in np.linspace(0, 1, nppc)) ) return self def set_points_smoothly( self, points: Point3DLike_Array, true_smooth: bool = False ) -> Self: self.set_points_as_corners(points) self.make_smooth() return self def change_anchor_mode(self, mode): """Changes the anchor mode of the bezier curves. This will modify the handles. There can be only three modes, "jagged", "approx_smooth" and "true_smooth". Returns ------- OpenGLVMobject For chaining purposes. """ assert mode in ("jagged", "approx_smooth", "true_smooth") nppc = self.n_points_per_curve for submob in self.family_members_with_points(): subpaths = submob.get_subpaths() submob.clear_points() for subpath in subpaths: anchors = np.vstack([subpath[::nppc], subpath[-1:]]) new_subpath = np.array(subpath) if mode == "approx_smooth": # TODO: get_smooth_quadratic_bezier_handle_points is not defined new_subpath[1::nppc] = get_smooth_quadratic_bezier_handle_points( anchors, ) elif mode == "true_smooth": h1, h2 = get_smooth_cubic_bezier_handle_points(anchors) new_subpath = get_quadratic_approximation_of_cubic( anchors[:-1], h1, h2, anchors[1:], ) elif mode == "jagged": new_subpath[1::nppc] = 0.5 * (anchors[:-1] + anchors[1:]) submob.append_points(new_subpath) submob.refresh_triangulation() return self def make_smooth(self): """ This will double the number of points in the mobject, so should not be called repeatedly. It also means transforming between states before and after calling this might have strange artifacts """ self.change_anchor_mode("true_smooth") return self def make_approximately_smooth(self): """ Unlike make_smooth, this will not change the number of points, but it also does not result in a perfectly smooth curve. It's most useful when the points have been sampled at a not-too-low rate from a continuous function, as in the case of ParametricCurve """ self.change_anchor_mode("approx_smooth") return self def make_jagged(self): self.change_anchor_mode("jagged") return self def add_subpath(self, points): assert len(points) % self.n_points_per_curve == 0 self.append_points(points) return self def append_vectorized_mobject(self, vectorized_mobject): new_points = list(vectorized_mobject.points) if self.has_new_path_started(): # Remove last point, which is starting # a new path self.resize_data(len(self.points - 1)) self.append_points(new_points) return self # def consider_points_equals(self, p0, p1): return np.linalg.norm(p1 - p0) < self.tolerance_for_point_equality # Information about the curve def force_direction(self, target_direction: str): """Makes sure that points are either directed clockwise or counterclockwise. Parameters ---------- target_direction Either ``"CW"`` or ``"CCW"``. """ if target_direction not in ("CW", "CCW"): raise ValueError('Invalid input for force_direction. Use "CW" or "CCW"') if self.get_direction() != target_direction: self.reverse_points() return self def reverse_direction(self): """Reverts the point direction by inverting the point order. Returns ------- :class:`OpenGLVMobject` Returns self. Examples -------- .. manim:: ChangeOfDirection class ChangeOfDirection(Scene): def construct(self): ccw = RegularPolygon(5) ccw.shift(LEFT) cw = RegularPolygon(5) cw.shift(RIGHT).reverse_direction() self.play(Create(ccw), Create(cw), run_time=4) """ self.set_points(self.points[::-1]) return self def get_bezier_tuples_from_points(self, points): nppc = self.n_points_per_curve remainder = len(points) % nppc points = points[: len(points) - remainder] return points.reshape((-1, nppc, 3)) def get_bezier_tuples(self): return self.get_bezier_tuples_from_points(self.points) def get_subpaths_from_points(self, points): nppc = self.n_points_per_curve diffs = points[nppc - 1 : -1 : nppc] - points[nppc::nppc] splits = (diffs * diffs).sum(1) > self.tolerance_for_point_equality split_indices = np.arange(nppc, len(points), nppc, dtype=int)[splits] # split_indices = filter( # lambda n: not self.consider_points_equals(points[n - 1], points[n]), # range(nppc, len(points), nppc) # ) split_indices = [0, *split_indices, len(points)] return [ points[i1:i2] for i1, i2 in zip(split_indices[:-1], split_indices[1:], strict=True) if (i2 - i1) >= nppc ] def get_subpaths(self): """Returns subpaths formed by the curves of the OpenGLVMobject. Subpaths are ranges of curves with each pair of consecutive curves having their end/start points coincident. Returns ------- Tuple subpaths. """ return self.get_subpaths_from_points(self.points) def get_nth_curve_points(self, n: int) -> np.ndarray: """Returns the points defining the nth curve of the vmobject. Parameters ---------- n index of the desired bezier curve. Returns ------- np.ndarray points defininf the nth bezier curve (anchors, handles) """ assert n < self.get_num_curves() nppc = self.n_points_per_curve return self.points[nppc * n : nppc * (n + 1)] def get_nth_curve_function(self, n: int) -> Callable[[float], np.ndarray]: """Returns the expression of the nth curve. Parameters ---------- n index of the desired curve. Returns ------- typing.Callable[float] expression of the nth bezier curve. """ return bezier(self.get_nth_curve_points(n)) def get_nth_curve_function_with_length( self, n: int, sample_points: int | None = None, ) -> tuple[Callable[[float], np.ndarray], float]: """Returns the expression of the nth curve along with its (approximate) length. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- curve : Callable[[float], np.ndarray] The function for the nth curve. length : :class:`float` The length of the nth curve. """ if sample_points is None: sample_points = 10 curve = self.get_nth_curve_function(n) norms = self.get_nth_curve_length_pieces(n, sample_points) length = np.sum(norms) return curve, length def get_num_curves(self) -> int: """Returns the number of curves of the vmobject. Returns ------- int number of curves. of the vmobject. """ return self.get_num_points() // self.n_points_per_curve def get_nth_curve_length( self, n: int, sample_points: int | None = None, ) -> float: """Returns the (approximate) length of the nth curve. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- length : :class:`float` The length of the nth curve. """ _, length = self.get_nth_curve_function_with_length(n, sample_points) return length def get_curve_functions( self, ) -> Iterable[Callable[[float], np.ndarray]]: """Gets the functions for the curves of the mobject. Returns ------- Iterable[Callable[[float], np.ndarray]] The functions for the curves. """ num_curves = self.get_num_curves() for n in range(num_curves): yield self.get_nth_curve_function(n) def get_nth_curve_length_pieces( self, n: int, sample_points: int | None = None, ) -> np.ndarray: """Returns the array of short line lengths used for length approximation. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- np.ndarray The short length-pieces of the nth curve. """ if sample_points is None: sample_points = 10 curve = self.get_nth_curve_function(n) points = np.array([curve(a) for a in np.linspace(0, 1, sample_points)]) diffs = points[1:] - points[:-1] norms = np.apply_along_axis(np.linalg.norm, 1, diffs) return norms def get_curve_functions_with_lengths( self, **kwargs ) -> Iterable[tuple[Callable[[float], np.ndarray], float]]: """Gets the functions and lengths of the curves for the mobject. Parameters ---------- **kwargs The keyword arguments passed to :meth:`get_nth_curve_function_with_length` Returns ------- 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): yield self.get_nth_curve_function_with_length(n, **kwargs) def point_from_proportion(self, alpha: float) -> Point3D: """Gets the point at a proportion along the path of the :class:`OpenGLVMobject`. Parameters ---------- alpha The proportion along the the path of the :class:`OpenGLVMobject`. Returns ------- :class:`Point3D` The point on the :class:`OpenGLVMobject`. Raises ------ :exc:`ValueError` If ``alpha`` is not between 0 and 1. :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.") self.throw_error_if_no_points() if alpha == 1: return self.points[-1] curves_and_lengths = tuple(self.get_curve_functions_with_lengths()) target_length = alpha * np.sum( np.fromiter((length for _, length in curves_and_lengths), dtype=np.float64) ) current_length = 0 for curve, length in curves_and_lengths: if current_length + length >= target_length: if length != 0: residue = (target_length - current_length) / length else: residue = 0 return curve(residue) current_length += length def proportion_from_point( self, point: Point3DLike, ) -> float: """Returns the proportion along the path of the :class:`OpenGLVMobject` a particular given point is at. Parameters ---------- point The Cartesian coordinates of the point which may or may not lie on the :class:`OpenGLVMobject` Returns ------- float The proportion along the path of the :class:`OpenGLVMobject`. Raises ------ :exc:`ValueError` If ``point`` does not lie on the curve. :exc:`Exception` If the :class:`OpenGLVMobject` has no points. """ self.throw_error_if_no_points() # Iterate over each bezier curve that the ``VMobject`` is composed of, checking # if the point lies on that curve. If it does not lie on that curve, add # the whole length of the curve to ``target_length`` and move onto the next # curve. If the point does lie on the curve, add how far along the curve # the point is to ``target_length``. # Then, divide ``target_length`` by the total arc length of the shape to get # the proportion along the ``VMobject`` the point is at. num_curves = self.get_num_curves() total_length = self.get_arc_length() target_length = 0 for n in range(num_curves): control_points = self.get_nth_curve_points(n) length = self.get_nth_curve_length(n) proportions_along_bezier = proportions_along_bezier_curve_for_point( point, control_points, ) if len(proportions_along_bezier) > 0: proportion_along_nth_curve = max(proportions_along_bezier) target_length += length * proportion_along_nth_curve break target_length += length else: raise ValueError(f"Point {point} does not lie on this curve.") alpha = target_length / total_length return alpha def get_anchors_and_handles(self) -> Iterable[np.ndarray]: """ Returns anchors1, handles, anchors2, where (anchors1[i], handles[i], anchors2[i]) will be three points defining a quadratic bezier curve for any i in range(0, len(anchors1)) """ nppc = self.n_points_per_curve points = self.points return [points[i::nppc] for i in range(nppc)] def get_start_anchors(self) -> np.ndarray: """Returns the start anchors of the bezier curves. Returns ------- np.ndarray Starting anchors """ return self.points[0 :: self.n_points_per_curve] def get_end_anchors(self) -> np.ndarray: """Return the starting anchors of the bezier curves. Returns ------- np.ndarray Starting anchors """ nppc = self.n_points_per_curve return self.points[nppc - 1 :: nppc] def get_anchors(self) -> Iterable[np.ndarray]: """Returns the anchors of the curves forming the OpenGLVMobject. Returns ------- Iterable[np.ndarray] The anchors. """ points = self.points if len(points) == 1: return points s = self.get_start_anchors() e = self.get_end_anchors() return list(it.chain.from_iterable(zip(s, e, strict=True))) def get_points_without_null_curves(self, atol=1e-9): nppc = self.n_points_per_curve points = self.points distinct_curves = reduce( op.or_, [ (abs(points[i::nppc] - points[0::nppc]) > atol).any(1) for i in range(1, nppc) ], ) return points[distinct_curves.repeat(nppc)] def get_arc_length(self, sample_points_per_curve: int | None = None) -> float: """Return the approximated length of the whole curve. Parameters ---------- sample_points_per_curve Number of sample points per curve used to approximate the length. More points result in a better approximation. Returns ------- float The length of the :class:`OpenGLVMobject`. """ return np.sum( length for _, length in self.get_curve_functions_with_lengths( sample_points=sample_points_per_curve, ) ) def get_area_vector(self): # Returns a vector whose length is the area bound by # the polygon formed by the anchor points, pointing # in a direction perpendicular to the polygon according # to the right hand rule. if not self.has_points(): return np.zeros(3) nppc = self.n_points_per_curve points = self.points p0 = points[0::nppc] p1 = points[nppc - 1 :: nppc] # Each term goes through all edges [(x1, y1, z1), (x2, y2, z2)] return 0.5 * np.array( [ sum( (p0[:, 1] + p1[:, 1]) * (p1[:, 2] - p0[:, 2]), ), # Add up (y1 + y2)*(z2 - z1) sum( (p0[:, 2] + p1[:, 2]) * (p1[:, 0] - p0[:, 0]), ), # Add up (z1 + z2)*(x2 - x1) sum( (p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1]), ), # Add up (x1 + x2)*(y2 - y1) ], ) def get_direction(self): """Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise. Examples -------- The default direction of a :class:`~.Circle` is counterclockwise:: >>> from manim import Circle >>> Circle().get_direction() 'CCW' Returns ------- :class:`str` Either ``"CW"`` or ``"CCW"``. """ return shoelace_direction(self.get_start_anchors()) def get_unit_normal(self, recompute=False): if not recompute: return self.unit_normal[0] if len(self.points) < 3: return OUT area_vect = self.get_area_vector() area = np.linalg.norm(area_vect) if area > 0: return area_vect / area else: points = self.points return get_unit_normal( points[1] - points[0], points[2] - points[1], ) def refresh_unit_normal(self): for mob in self.get_family(): mob.unit_normal[:] = mob.get_unit_normal(recompute=True) return self # Alignment def align_points(self, vmobject): # TODO: This shortcut can be a bit over eager. What if they have the same length, but different subpath lengths? if self.get_num_points() == len(vmobject.points): return for mob in self, vmobject: # If there are no points, add one to # where the "center" is if not mob.has_points(): mob.start_new_path(mob.get_center()) # If there's only one point, turn it into # a null curve if mob.has_new_path_started(): mob.add_line_to(mob.points[0]) # Figure out what the subpaths are, and align subpaths1 = self.get_subpaths() subpaths2 = vmobject.get_subpaths() n_subpaths = max(len(subpaths1), len(subpaths2)) # Start building new ones new_subpaths1 = [] new_subpaths2 = [] nppc = self.n_points_per_curve def get_nth_subpath(path_list, n): if n >= len(path_list): # Create a null path at the very end if len(path_list) == 0: return np.tile(np.zeros(3), (nppc, 1)) return np.tile(path_list[-1][-1], (nppc, 1)) path = path_list[n] # Check for useless points at the end of the path and remove them # https://github.com/ManimCommunity/manim/issues/1959 while len(path) > nppc: # If the last nppc points are all equal to the preceding point if self.consider_points_equals(path[-nppc:], path[-nppc - 1]): path = path[:-nppc] else: break return path for n in range(n_subpaths): sp1 = np.asarray(get_nth_subpath(subpaths1, n)) sp2 = np.asarray(get_nth_subpath(subpaths2, n)) diff1 = max(0, (len(sp2) - len(sp1)) // nppc) diff2 = max(0, (len(sp1) - len(sp2)) // nppc) sp1 = self.insert_n_curves_to_point_list(diff1, sp1) sp2 = self.insert_n_curves_to_point_list(diff2, sp2) new_subpaths1.append(sp1) new_subpaths2.append(sp2) self.set_points(np.vstack(new_subpaths1)) vmobject.set_points(np.vstack(new_subpaths2)) return self def insert_n_curves(self, n: int, recurse=True) -> OpenGLVMobject: """Inserts n curves to the bezier curves of the vmobject. Parameters ---------- n Number of curves to insert. Returns ------- OpenGLVMobject for chaining. """ for mob in self.get_family(recurse): if mob.get_num_curves() > 0: new_points = mob.insert_n_curves_to_point_list(n, mob.points) # TODO, this should happen in insert_n_curves_to_point_list if mob.has_new_path_started(): new_points = np.vstack([new_points, mob.get_last_point()]) mob.set_points(new_points) return self def insert_n_curves_to_point_list(self, n: int, points: np.ndarray) -> np.ndarray: """Given an array of k points defining a bezier curves (anchors and handles), returns points defining exactly k + n bezier curves. Parameters ---------- n Number of desired curves. points Starting points. Returns ------- np.ndarray Points generated. """ nppc = self.n_points_per_curve if len(points) == 1: return np.repeat(points, nppc * n, 0) bezier_tuples = self.get_bezier_tuples_from_points(points) current_number_of_curves = len(bezier_tuples) new_number_of_curves = current_number_of_curves + n new_bezier_tuples = bezier_remap(bezier_tuples, new_number_of_curves) new_points = new_bezier_tuples.reshape(-1, 3) return new_points def interpolate(self, mobject1, mobject2, alpha, *args, **kwargs): super().interpolate(mobject1, mobject2, alpha, *args, **kwargs) if config["use_projection_fill_shaders"]: self.refresh_triangulation() else: if self.has_fill(): tri1 = mobject1.get_triangulation() tri2 = mobject2.get_triangulation() if len(tri1) != len(tri2) or not np.all(tri1 == tri2): self.refresh_triangulation() return self def pointwise_become_partial( self, vmobject: OpenGLVMobject, a: float, b: float, remap: bool = True ) -> OpenGLVMobject: """Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles) Parameters ---------- vmobject The vmobject that will serve as a model. a upper-bound. b lower-bound remap if the point amount should be kept the same (True) This option should be manually set to False if keeping the number of points is not needed """ assert isinstance(vmobject, OpenGLVMobject) # Partial curve includes three portions: # - A middle section, which matches the curve exactly # - A start, which is some ending portion of an inner cubic # - An end, which is the starting portion of a later inner cubic if a <= 0 and b >= 1: self.set_points(vmobject.points) return self bezier_triplets = vmobject.get_bezier_tuples() num_quadratics = len(bezier_triplets) # The following two lines will compute which bezier curves of the given mobject need to be processed. # The residue basically indicates the proportion of the selected Bèzier curve. # Ex: if lower_index is 3, and lower_residue is 0.4, then the algorithm will append to the points 0.4 of the third bezier curve lower_index, lower_residue = integer_interpolate(0, num_quadratics, a) upper_index, upper_residue = integer_interpolate(0, num_quadratics, b) self.clear_points() if num_quadratics == 0: return self if lower_index == upper_index: self.append_points( partial_bezier_points( bezier_triplets[lower_index], lower_residue, upper_residue, ), ) else: self.append_points( partial_bezier_points(bezier_triplets[lower_index], lower_residue, 1), ) inner_points = bezier_triplets[lower_index + 1 : upper_index] if len(inner_points) > 0: if remap: new_triplets = bezier_remap(inner_points, num_quadratics - 2) else: new_triplets = bezier_triplets self.append_points(np.asarray(new_triplets).reshape(-1, 3)) self.append_points( partial_bezier_points(bezier_triplets[upper_index], 0, upper_residue), ) return self def get_subcurve(self, a: float, b: float) -> OpenGLVMobject: """Returns the subcurve of the OpenGLVMobject between the interval [a, b]. The curve is a OpenGLVMobject itself. Parameters ---------- a The lower bound. b The upper bound. Returns ------- OpenGLVMobject The subcurve between of [a, b] """ vmob = self.copy() vmob.pointwise_become_partial(self, a, b) return vmob # Related to triangulation def refresh_triangulation(self) -> Self: for mob in self.get_family(): mob.needs_new_triangulation = True return self def get_triangulation(self, normal_vector=None): # Figure out how to triangulate the interior to know # how to send the points as to the vertex shader. # First triangles come directly from the points if normal_vector is None: normal_vector = self.get_unit_normal() if not self.needs_new_triangulation: return self.triangulation points = self.points if len(points) <= 1: self.triangulation = np.zeros(0, dtype="i4") self.needs_new_triangulation = False return self.triangulation if not np.isclose(normal_vector, OUT).all(): # Rotate points such that unit normal vector is OUT points = np.dot(points, z_to_vector(normal_vector)) indices = np.arange(len(points), dtype=int) b0s = points[0::3] b1s = points[1::3] b2s = points[2::3] v01s = b1s - b0s v12s = b2s - b1s crosses = cross2d(v01s, v12s) convexities = np.sign(crosses) atol = self.tolerance_for_point_equality end_of_loop = np.zeros(len(b0s), dtype=bool) end_of_loop[:-1] = (np.abs(b2s[:-1] - b0s[1:]) > atol).any(1) end_of_loop[-1] = True concave_parts = convexities < 0 # These are the vertices to which we'll apply a polygon triangulation inner_vert_indices = np.hstack( [ indices[0::3], indices[1::3][concave_parts], indices[2::3][end_of_loop], ], ) inner_vert_indices.sort() rings = np.arange(1, len(inner_vert_indices) + 1)[inner_vert_indices % 3 == 2] # Triangulate inner_verts = points[inner_vert_indices] inner_tri_indices = inner_vert_indices[ earclip_triangulation(inner_verts, rings) ] tri_indices = np.hstack([indices, inner_tri_indices]) self.triangulation = tri_indices self.needs_new_triangulation = False return tri_indices @triggers_refreshed_triangulation def set_points(self, points): super().set_points(points) return self @triggers_refreshed_triangulation def set_data(self, data): super().set_data(data) return self # TODO, how to be smart about tangents here? @triggers_refreshed_triangulation def apply_function(self, function, make_smooth=False, **kwargs): super().apply_function(function, **kwargs) if self.make_smooth_after_applying_functions or make_smooth: self.make_approximately_smooth() return self @triggers_refreshed_triangulation def apply_points_function(self, *args, **kwargs): super().apply_points_function(*args, **kwargs) return self @triggers_refreshed_triangulation def flip(self, *args, **kwargs): super().flip(*args, **kwargs) return self # For shaders def init_shader_data(self): self.fill_data = np.zeros(0, dtype=self.fill_dtype) self.stroke_data = np.zeros(0, dtype=self.stroke_dtype) self.fill_shader_wrapper = ShaderWrapper( vert_data=self.fill_data, vert_indices=np.zeros(0, dtype="i4"), shader_folder=self.fill_shader_folder, render_primitive=self.render_primitive, ) self.stroke_shader_wrapper = ShaderWrapper( vert_data=self.stroke_data, shader_folder=self.stroke_shader_folder, render_primitive=self.render_primitive, ) def refresh_shader_wrapper_id(self): for wrapper in [self.fill_shader_wrapper, self.stroke_shader_wrapper]: wrapper.refresh_id() return self def get_fill_shader_wrapper(self): self.update_fill_shader_wrapper() return self.fill_shader_wrapper def update_fill_shader_wrapper(self): self.fill_shader_wrapper.vert_data = self.get_fill_shader_data() self.fill_shader_wrapper.vert_indices = self.get_triangulation() self.fill_shader_wrapper.uniforms = self.get_fill_uniforms() self.fill_shader_wrapper.depth_test = self.depth_test def get_stroke_shader_wrapper(self): self.update_stroke_shader_wrapper() return self.stroke_shader_wrapper def update_stroke_shader_wrapper(self): self.stroke_shader_wrapper.vert_data = self.get_stroke_shader_data() self.stroke_shader_wrapper.uniforms = self.get_stroke_uniforms() self.stroke_shader_wrapper.depth_test = self.depth_test def get_shader_wrapper_list(self): # Build up data lists fill_shader_wrappers = [] stroke_shader_wrappers = [] back_stroke_shader_wrappers = [] for submob in self.family_members_with_points(): if submob.has_fill() and not config["use_projection_fill_shaders"]: fill_shader_wrappers.append(submob.get_fill_shader_wrapper()) if submob.has_stroke() and not config["use_projection_stroke_shaders"]: ssw = submob.get_stroke_shader_wrapper() if submob.draw_stroke_behind_fill: back_stroke_shader_wrappers.append(ssw) else: stroke_shader_wrappers.append(ssw) # Combine data lists wrapper_lists = [ back_stroke_shader_wrappers, fill_shader_wrappers, stroke_shader_wrappers, ] result = [] for wlist in wrapper_lists: if wlist: wrapper = wlist[0] wrapper.combine_with(*wlist[1:]) result.append(wrapper) return result def get_stroke_uniforms(self): result = dict(super().get_shader_uniforms()) result["joint_type"] = self.joint_type.value result["flat_stroke"] = float(self.flat_stroke) return result def get_fill_uniforms(self): return { "is_fixed_in_frame": float(self.is_fixed_in_frame), "is_fixed_orientation": float(self.is_fixed_orientation), "fixed_orientation_center": self.fixed_orientation_center, "gloss": self.gloss, "shadow": self.shadow, } def get_stroke_shader_data(self): points = self.points if len(self.stroke_data) != len(points): self.stroke_data = np.zeros(len(points), dtype=OpenGLVMobject.stroke_dtype) if "points" not in self.locked_data_keys: nppc = self.n_points_per_curve self.stroke_data["point"] = points self.stroke_data["prev_point"][:nppc] = points[-nppc:] self.stroke_data["prev_point"][nppc:] = points[:-nppc] self.stroke_data["next_point"][:-nppc] = points[nppc:] self.stroke_data["next_point"][-nppc:] = points[:nppc] self.read_data_to_shader(self.stroke_data, "color", "stroke_rgba") self.read_data_to_shader(self.stroke_data, "stroke_width", "stroke_width") self.read_data_to_shader(self.stroke_data, "unit_normal", "unit_normal") return self.stroke_data def get_fill_shader_data(self): points = self.points if len(self.fill_data) != len(points): self.fill_data = np.zeros(len(points), dtype=OpenGLVMobject.fill_dtype) self.fill_data["vert_index"][:, 0] = range(len(points)) self.read_data_to_shader(self.fill_data, "point", "points") self.read_data_to_shader(self.fill_data, "color", "fill_rgba") self.read_data_to_shader(self.fill_data, "unit_normal", "unit_normal") return self.fill_data def refresh_shader_data(self): self.get_fill_shader_data() self.get_stroke_shader_data() def get_fill_shader_vert_indices(self): return self.get_triangulation() class OpenGLVGroup(OpenGLVMobject): """A group of vectorized mobjects. This can be used to group multiple :class:`~.OpenGLVMobject` instances together in order to scale, move, ... them together. Examples -------- To add :class:`~.OpenGLVMobject`s to a :class:`~.OpenGLVGroup`, you can either use the :meth:`~.OpenGLVGroup.add` method, or use the `+` and `+=` operators. Similarly, you can subtract elements of a OpenGLVGroup via :meth:`~.OpenGLVGroup.remove` method, or `-` and `-=` operators: .. doctest:: >>> from manim import config >>> original_renderer = config.renderer >>> config.renderer = "opengl" >>> from manim import Triangle, Square >>> from manim.opengl import OpenGLVGroup >>> config.renderer >>> vg = OpenGLVGroup() >>> triangle, square = Triangle(), Square() >>> vg.add(triangle) OpenGLVGroup(Triangle) >>> vg + square # a new OpenGLVGroup is constructed OpenGLVGroup(Triangle, Square) >>> vg # not modified OpenGLVGroup(Triangle) >>> vg += square # modifies vg >>> vg OpenGLVGroup(Triangle, Square) >>> vg.remove(triangle) OpenGLVGroup(Square) >>> vg - square # a new OpenGLVGroup is constructed OpenGLVGroup() >>> vg # not modified OpenGLVGroup(Square) >>> vg -= square # modifies vg >>> vg OpenGLVGroup() >>> config.renderer = original_renderer .. manim:: ArcShapeIris :save_last_frame: class ArcShapeIris(Scene): def construct(self): colors = [DARK_BROWN, BLUE_E, BLUE_D, BLUE_A, TEAL_B, GREEN_B, YELLOW_E] radius = [1 + rad * 0.1 for rad in range(len(colors))] circles_group = OpenGLVGroup() # zip(radius, color) makes the iterator [(radius[i], color[i]) for i in range(radius)] circles_group.add(*[Circle(radius=rad, stroke_width=10, color=col) for rad, col in zip(radius, colors)]) self.add(circles_group) """ def __init__(self, *vmobjects: OpenGLVMobject, **kwargs: Any): super().__init__(**kwargs) self.add(*vmobjects) def __repr__(self): return ( self.__class__.__name__ + "(" + ", ".join(str(mob) for mob in self.submobjects) + ")" ) def __str__(self): return ( f"{self.__class__.__name__} of {len(self.submobjects)} " f"submobject{'s' if len(self.submobjects) > 0 else ''}" ) def add(self, *vmobjects: OpenGLVMobject): """Checks if all passed elements are an instance of OpenGLVMobject and then add them to submobjects Parameters ---------- vmobjects List of OpenGLVMobject to add Returns ------- :class:`OpenGLVGroup` Raises ------ TypeError If one element of the list is not an instance of OpenGLVMobject Examples -------- .. manim:: AddToOpenGLVGroup class AddToOpenGLVGroup(Scene): def construct(self): circle_red = Circle(color=RED) circle_green = Circle(color=GREEN) circle_blue = Circle(color=BLUE) circle_red.shift(LEFT) circle_blue.shift(RIGHT) gr = OpenGLVGroup(circle_red, circle_green) gr2 = OpenGLVGroup(circle_blue) # Constructor uses add directly self.add(gr,gr2) self.wait() gr += gr2 # Add group to another self.play( gr.animate.shift(DOWN), ) gr -= gr2 # Remove group self.play( # Animate groups separately gr.animate.shift(LEFT), gr2.animate.shift(UP), ) self.play( #Animate groups without modification (gr+gr2).animate.shift(RIGHT) ) self.play( # Animate group without component (gr-circle_red).animate.shift(RIGHT) ) """ return super().add(*vmobjects) def __add__(self, vmobject): return OpenGLVGroup(*self.submobjects, vmobject) def __iadd__(self, vmobject): return self.add(vmobject) def __sub__(self, vmobject): copy = OpenGLVGroup(*self.submobjects) copy.remove(vmobject) return copy def __isub__(self, vmobject): return self.remove(vmobject) def __setitem__(self, key: int, value: OpenGLVMobject | Sequence[OpenGLVMobject]): """Override the [] operator for item assignment. Parameters ---------- key The index of the submobject to be assigned value The vmobject value to assign to the key Returns ------- None Tests ----- .. doctest:: >>> from manim import config >>> original_renderer = config.renderer >>> config.renderer = "opengl" >>> vgroup = OpenGLVGroup(OpenGLVMobject()) >>> new_obj = OpenGLVMobject() >>> vgroup[0] = new_obj >>> config.renderer = original_renderer """ self._assert_valid_submobjects(tuplify(value)) self.submobjects[key] = value class OpenGLVectorizedPoint(OpenGLPoint, OpenGLVMobject): def __init__( self, location=ORIGIN, color=BLACK, fill_opacity=0, stroke_width=0, artificial_width=0.01, artificial_height=0.01, **kwargs, ): self.artificial_width = artificial_width self.artificial_height = artificial_height super().__init__( color=color, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs ) self.set_points(np.array([location])) class OpenGLCurvesAsSubmobjects(OpenGLVGroup): """Convert a curve's elements to submobjects. Examples -------- .. manim:: LineGradientExample :save_last_frame: class LineGradientExample(Scene): def construct(self): curve = ParametricFunction(lambda t: [t, np.sin(t), 0], t_range=[-PI, PI, 0.01], stroke_width=10) new_curve = CurvesAsSubmobjects(curve) new_curve.set_color_by_gradient(BLUE, RED) self.add(new_curve.shift(UP), curve) """ def __init__(self, vmobject, **kwargs): super().__init__(**kwargs) for tup in vmobject.get_bezier_tuples(): part = OpenGLVMobject() part.set_points(tup) part.match_style(vmobject) self.add(part) class OpenGLDashedVMobject(OpenGLVMobject): """A :class:`OpenGLVMobject` composed of dashes instead of lines. Examples -------- .. manim:: DashedVMobjectExample :save_last_frame: class DashedVMobjectExample(Scene): def construct(self): r = 0.5 top_row = OpenGLVGroup() # Increasing num_dashes for dashes in range(2, 12): circ = DashedVMobject(Circle(radius=r, color=WHITE), num_dashes=dashes) top_row.add(circ) middle_row = OpenGLVGroup() # Increasing dashed_ratio for ratio in np.arange(1 / 11, 1, 1 / 11): circ = DashedVMobject( Circle(radius=r, color=WHITE), dashed_ratio=ratio ) middle_row.add(circ) sq = DashedVMobject(Square(1.5, color=RED)) penta = DashedVMobject(RegularPolygon(5, color=BLUE)) bottom_row = OpenGLVGroup(sq, penta) top_row.arrange(buff=0.4) middle_row.arrange() bottom_row.arrange(buff=1) everything = OpenGLVGroup(top_row, middle_row, bottom_row).arrange(DOWN, buff=1) self.add(everything) """ def __init__( self, vmobject: OpenGLVMobject, num_dashes: int = 15, dashed_ratio: float = 0.5, color: ParsableManimColor = WHITE, **kwargs, ): self.dashed_ratio = dashed_ratio self.num_dashes = num_dashes super().__init__(color=color, **kwargs) r = self.dashed_ratio n = self.num_dashes if num_dashes > 0: # Assuming total length is 1 dash_len = r / n void_len = (1 - r) / n if vmobject.is_closed() else (1 - r) / (n - 1) self.add( *( vmobject.get_subcurve( i * (dash_len + void_len), i * (dash_len + void_len) + dash_len, ) for i in range(n) ) ) # Family is already taken care of by get_subcurve # implementation self.match_style(vmobject, recurse=False) ================================================ FILE: manim/mobject/svg/__init__.py ================================================ """Mobjects related to SVG images. Modules ======= .. autosummary:: :toctree: ../reference ~brace ~svg_mobject """ ================================================ FILE: manim/mobject/svg/brace.py ================================================ """Mobject representing curly braces.""" from __future__ import annotations __all__ = ["Brace", "BraceLabel", "ArcBrace", "BraceText", "BraceBetweenPoints"] from typing import TYPE_CHECKING, Any, Self import numpy as np import svgelements as se from manim._config import config from manim.mobject.geometry.arc import Arc from manim.mobject.geometry.line import Line from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.text.tex_mobject import MathTex, SingleStringMathTex, Tex from manim.mobject.text.text_mobject import Text from ...animation.animation import Animation from ...animation.composition import AnimationGroup from ...animation.fading import FadeIn from ...animation.growing import GrowFromCenter from ...constants import * from ...mobject.types.vectorized_mobject import VMobject from ...utils.color import BLACK from ..svg.svg_mobject import VMobjectFromSVGPath if TYPE_CHECKING: from manim.typing import Point3D, Point3DLike, Vector3D, Vector3DLike from manim.utils.color.core import ParsableManimColor class Brace(VMobjectFromSVGPath): """Takes a mobject and draws a brace adjacent to it. Passing a direction vector determines the direction from which the brace is drawn. By default it is drawn from below. Parameters ---------- mobject The mobject adjacent to which the brace is placed. direction : The direction from which the brace faces the mobject. See Also -------- :class:`BraceBetweenPoints` Examples -------- .. manim:: BraceExample :save_last_frame: class BraceExample(Scene): def construct(self): s = Square() self.add(s) for i in np.linspace(0.1,1.0,4): br = Brace(s, sharpness=i) t = Text(f"sharpness= {i}").next_to(br, RIGHT) self.add(t) self.add(br) VGroup(*self.mobjects).arrange(DOWN, buff=0.2) """ def __init__( self, mobject: Mobject, direction: Vector3DLike = DOWN, buff: float = 0.2, sharpness: float = 2, stroke_width: float = 0, fill_opacity: float = 1.0, background_stroke_width: float = 0, background_stroke_color: ParsableManimColor = BLACK, **kwargs: Any, ): path_string_template = ( "m0.01216 0c-0.01152 0-0.01216 6.103e-4 -0.01216 0.01311v0.007762c0.06776 " "0.122 0.1799 0.1455 0.2307 0.1455h{0}c0.03046 3.899e-4 0.07964 0.00449 " "0.1246 0.02636 0.0537 0.02695 0.07418 0.05816 0.08648 0.07769 0.001562 " "0.002538 0.004539 0.002563 0.01098 0.002563 0.006444-2e-8 0.009421-2.47e-" "5 0.01098-0.002563 0.0123-0.01953 0.03278-0.05074 0.08648-0.07769 0.04491" "-0.02187 0.09409-0.02597 0.1246-0.02636h{0}c0.05077 0 0.1629-0.02346 " "0.2307-0.1455v-0.007762c-1.78e-6 -0.0125-6.365e-4 -0.01311-0.01216-0.0131" "1-0.006444-3.919e-8 -0.009348 2.448e-5 -0.01091 0.002563-0.0123 0.01953-" "0.03278 0.05074-0.08648 0.07769-0.04491 0.02187-0.09416 0.02597-0.1246 " "0.02636h{1}c-0.04786 0-0.1502 0.02094-0.2185 0.1256-0.06833-0.1046-0.1706" "-0.1256-0.2185-0.1256h{1}c-0.03046-3.899e-4 -0.07972-0.004491-0.1246-0.02" "636-0.0537-0.02695-0.07418-0.05816-0.08648-0.07769-0.001562-0.002538-" "0.004467-0.002563-0.01091-0.002563z" ) default_min_width = 0.90552 self.buff = buff angle = -np.arctan2(*direction[:2]) + np.pi mobject.rotate(-angle, about_point=ORIGIN) left = mobject.get_corner(DOWN + LEFT) right = mobject.get_corner(DOWN + RIGHT) target_width = right[0] - left[0] linear_section_length = max( 0, (target_width * sharpness - default_min_width) / 2, ) path = se.Path( path_string_template.format( linear_section_length, -linear_section_length, ) ) super().__init__( path_obj=path, stroke_width=stroke_width, fill_opacity=fill_opacity, background_stroke_width=background_stroke_width, background_stroke_color=background_stroke_color, **kwargs, ) self.flip(RIGHT) self.stretch_to_fit_width(target_width) self.shift(left - self.get_corner(UP + LEFT) + self.buff * DOWN) for mob in mobject, self: mob.rotate(angle, about_point=ORIGIN) def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs: Any) -> Self: """Puts the given mobject at the brace tip. Parameters ---------- mob The mobject to be placed at the tip. use_next_to If true, then :meth:`next_to` is used to place the mobject at the tip. kwargs Any additional keyword arguments are passed to :meth:`next_to` which is used to put the mobject next to the brace tip. """ if use_next_to: mob.next_to(self.get_tip(), np.round(self.get_direction()), **kwargs) else: mob.move_to(self.get_tip()) buff = kwargs.get("buff", DEFAULT_MOBJECT_TO_MOBJECT_BUFFER) shift_distance = mob.width / 2.0 + buff mob.shift(self.get_direction() * shift_distance) return self def get_text(self, *text: str, **kwargs: Any) -> Tex: """Places the text at the brace tip. Parameters ---------- text The text to be placed at the brace tip. kwargs Any additional keyword arguments are passed to :meth:`.put_at_tip` which is used to position the text at the brace tip. Returns ------- :class:`~.Tex` """ text_mob = Tex(*text) self.put_at_tip(text_mob, **kwargs) return text_mob def get_tex(self, *tex: str, **kwargs: Any) -> MathTex: """Places the tex at the brace tip. Parameters ---------- tex The tex to be placed at the brace tip. kwargs Any further keyword arguments are passed to :meth:`.put_at_tip` which is used to position the tex at the brace tip. Returns ------- :class:`~.MathTex` """ tex_mob = MathTex(*tex) self.put_at_tip(tex_mob, **kwargs) return tex_mob def get_tip(self) -> Point3D: """Returns the point at the brace tip.""" # Returns the position of the seventh point in the path, which is the tip. if config["renderer"] == "opengl": return self.points[34] return self.points[28] # = 7*4 def get_direction(self) -> Vector3D: """Returns the direction from the center to the brace tip.""" vect = self.get_tip() - self.get_center() return vect / np.linalg.norm(vect) class BraceLabel(VMobject, metaclass=ConvertToOpenGL): """Create a brace with a label attached. Parameters ---------- obj The mobject adjacent to which the brace is placed. text The label text. brace_direction The direction of the brace. By default ``DOWN``. label_constructor A class or function used to construct a mobject representing the label. By default :class:`~.MathTex`. font_size The font size of the label, passed to the ``label_constructor``. buff The buffer between the mobject and the brace. brace_config Arguments to be passed to :class:`.Brace`. kwargs Additional arguments to be passed to :class:`~.VMobject`. """ def __init__( self, obj: Mobject, text: str, brace_direction: Vector3DLike = DOWN, label_constructor: type[SingleStringMathTex | Text] = MathTex, font_size: float = DEFAULT_FONT_SIZE, buff: float = 0.2, brace_config: dict[str, Any] | None = None, **kwargs: Any, ): self.label_constructor = label_constructor super().__init__(**kwargs) self.brace_direction = brace_direction if brace_config is None: brace_config = {} self.brace = Brace(obj, brace_direction, buff, **brace_config) if isinstance(text, (tuple, list)): self.label: VMobject = self.label_constructor( *text, font_size=font_size, **kwargs ) else: self.label = self.label_constructor(str(text), font_size=font_size) self.brace.put_at_tip(self.label) self.add(self.brace, self.label) def creation_anim( self, label_anim: type[Animation] = FadeIn, brace_anim: type[Animation] = GrowFromCenter, ) -> AnimationGroup: return AnimationGroup(brace_anim(self.brace), label_anim(self.label)) def shift_brace(self, obj: Mobject, **kwargs: Any) -> Self: if isinstance(obj, list): obj = self.get_group_class()(*obj) self.brace = Brace(obj, self.brace_direction, **kwargs) self.brace.put_at_tip(self.label) return self def change_label(self, *text: str, **kwargs: Any) -> Self: self.remove(self.label) self.label = self.label_constructor(*text, **kwargs) # type: ignore[arg-type] self.brace.put_at_tip(self.label) self.add(self.label) return self def change_brace_label(self, obj: Mobject, *text: str, **kwargs: Any) -> Self: self.shift_brace(obj) self.change_label(*text, **kwargs) return self class BraceText(BraceLabel): """Create a brace with a text label attached. Parameters ---------- obj The mobject adjacent to which the brace is placed. text The label text. brace_direction The direction of the brace. By default ``DOWN``. label_constructor A class or function used to construct a mobject representing the label. By default :class:`~.Text`. font_size The font size of the label, passed to the ``label_constructor``. buff The buffer between the mobject and the brace. brace_config Arguments to be passed to :class:`.Brace`. kwargs Additional arguments to be passed to :class:`~.VMobject`. Examples -------- .. manim:: BraceTextExample :save_last_frame: class BraceTextExample(Scene): def construct(self): s1 = Square().move_to(2*LEFT) self.add(s1) br1 = BraceText(s1, "Label") self.add(br1) s2 = Square().move_to(2*RIGHT) self.add(s2) br2 = BraceText(s2, "Label") br2.change_label("new") self.add(br2) self.wait(0.1) """ def __init__( self, obj: Mobject, text: str, label_constructor: type[SingleStringMathTex | Text] = Text, **kwargs: Any, ): super().__init__(obj, text, label_constructor=label_constructor, **kwargs) class BraceBetweenPoints(Brace): """Similar to Brace, but instead of taking a mobject it uses 2 points to place the brace. A fitting direction for the brace is computed, but it still can be manually overridden. If the points go from left to right, the brace is drawn from below. Swapping the points places the brace on the opposite side. Parameters ---------- point_1 : The first point. point_2 : The second point. direction : The direction from which the brace faces towards the points. Examples -------- .. manim:: BraceBPExample class BraceBPExample(Scene): def construct(self): p1 = [0,0,0] p2 = [1,2,0] brace = BraceBetweenPoints(p1,p2) self.play(Create(NumberPlane())) self.play(Create(brace)) self.wait(2) """ def __init__( self, point_1: Point3DLike, point_2: Point3DLike, direction: Vector3DLike = ORIGIN, **kwargs: Any, ): if all(direction == ORIGIN): line_vector = np.array(point_2) - np.array(point_1) direction = np.array([line_vector[1], -line_vector[0], 0]) super().__init__(Line(point_1, point_2), direction=direction, **kwargs) class ArcBrace(Brace): """Creates a :class:`~Brace` that wraps around an :class:`~.Arc`. The direction parameter allows the brace to be applied from outside or inside the arc. .. warning:: The :class:`ArcBrace` is smaller for arcs with smaller radii. .. note:: The :class:`ArcBrace` is initially a vertical :class:`Brace` defined by the length of the :class:`~.Arc`, but is scaled down to match the start and end angles. An exponential function is then applied after it is shifted based on the radius of the arc. The scaling effect is not applied for arcs with radii smaller than 1 to prevent over-scaling. Parameters ---------- arc The :class:`~.Arc` that wraps around the :class:`Brace` mobject. direction The direction from which the brace faces the arc. ``LEFT`` for inside the arc, and ``RIGHT`` for the outside. Example ------- .. manim:: ArcBraceExample :save_last_frame: :ref_classes: Arc class ArcBraceExample(Scene): def construct(self): arc_1 = Arc(radius=1.5,start_angle=0,angle=2*PI/3).set_color(RED) brace_1 = ArcBrace(arc_1,LEFT) group_1 = VGroup(arc_1,brace_1) arc_2 = Arc(radius=3,start_angle=0,angle=5*PI/6).set_color(YELLOW) brace_2 = ArcBrace(arc_2) group_2 = VGroup(arc_2,brace_2) arc_3 = Arc(radius=0.5,start_angle=-0,angle=PI).set_color(BLUE) brace_3 = ArcBrace(arc_3) group_3 = VGroup(arc_3,brace_3) arc_4 = Arc(radius=0.2,start_angle=0,angle=3*PI/2).set_color(GREEN) brace_4 = ArcBrace(arc_4) group_4 = VGroup(arc_4,brace_4) arc_group = VGroup(group_1, group_2, group_3, group_4).arrange_in_grid(buff=1.5) self.add(arc_group.center()) """ def __init__( self, arc: Arc | None = None, direction: Vector3DLike = RIGHT, **kwargs: Any, ): if arc is None: arc = Arc(start_angle=-1, angle=2, radius=1) arc_end_angle = arc.start_angle + arc.angle line = Line(UP * arc.start_angle, UP * arc_end_angle) scale_shift = RIGHT * np.log(arc.radius) if arc.radius >= 1: line.scale(arc.radius, about_point=ORIGIN) super().__init__(line, direction=direction, **kwargs) self.scale(1 / (arc.radius), about_point=ORIGIN) else: super().__init__(line, direction=direction, **kwargs) if arc.radius >= 0.3: self.shift(scale_shift) else: self.shift(RIGHT * np.log(0.3)) self.apply_complex_function(np.exp) self.shift(arc.get_arc_center()) ================================================ FILE: manim/mobject/svg/svg_mobject.py ================================================ """Mobjects generated from an SVG file.""" from __future__ import annotations import os from pathlib import Path from typing import Any from xml.etree import ElementTree as ET import numpy as np import svgelements as se from manim import config, logger from manim.utils.color import ManimColor, ParsableManimColor from ...constants import RIGHT from ...utils.bezier import get_quadratic_approximation_of_cubic from ...utils.images import get_full_vector_image_path from ...utils.iterables import hash_obj from ..geometry.arc import Circle from ..geometry.line import Line from ..geometry.polygram import Polygon, Rectangle, RoundedRectangle from ..opengl.opengl_compatibility import ConvertToOpenGL from ..types.vectorized_mobject import VGroup, VMobject __all__ = ["SVGMobject", "VMobjectFromSVGPath"] SVG_HASH_TO_MOB_MAP: dict[int, SVGMobject] = {} def _convert_point_to_3d(x: float, y: float) -> np.ndarray: return np.array([x, y, 0.0]) class SVGMobject(VMobject, metaclass=ConvertToOpenGL): """A vectorized mobject created from importing an SVG file. Parameters ---------- file_name The path to the SVG file. should_center Whether or not the mobject should be centered after being imported. height The target height of the mobject, set to 2 Manim units by default. If the height and width are both set to ``None``, the mobject is imported without being scaled. width The target width of the mobject, set to ``None`` by default. If the height and the width are both set to ``None``, the mobject is imported without being scaled. color The color (both fill and stroke color) of the mobject. If ``None`` (the default), the colors set in the SVG file are used. opacity The opacity (both fill and stroke opacity) of the mobject. If ``None`` (the default), the opacity set in the SVG file is used. fill_color The fill color of the mobject. If ``None`` (the default), the fill colors set in the SVG file are used. fill_opacity The fill opacity of the mobject. If ``None`` (the default), the fill opacities set in the SVG file are used. stroke_color The stroke color of the mobject. If ``None`` (the default), the stroke colors set in the SVG file are used. stroke_opacity The stroke opacity of the mobject. If ``None`` (the default), the stroke opacities set in the SVG file are used. stroke_width The stroke width of the mobject. If ``None`` (the default), the stroke width values set in the SVG file are used. svg_default A dictionary in which fallback values for unspecified properties of elements in the SVG file are defined. If ``None`` (the default), ``color``, ``opacity``, ``fill_color`` ``fill_opacity``, ``stroke_color``, and ``stroke_opacity`` are set to ``None``, and ``stroke_width`` is set to 0. path_string_config A dictionary with keyword arguments passed to :class:`.VMobjectFromSVGPath` used for importing path elements. If ``None`` (the default), no additional arguments are passed. use_svg_cache If True (default), the svg inputs (e.g. file_name, settings) will be used as a key and a copy of the created mobject will be saved using that key to be quickly retrieved if the same inputs need be processed later. For large SVGs which are used only once, this can be omitted to improve performance. kwargs Further arguments passed to the parent class. """ def __init__( self, file_name: str | os.PathLike | None = None, should_center: bool = True, height: float | None = 2, width: float | None = None, color: ParsableManimColor | None = None, opacity: float | None = None, fill_color: ParsableManimColor | None = None, fill_opacity: float | None = None, stroke_color: ParsableManimColor | None = None, stroke_opacity: float | None = None, stroke_width: float | None = None, svg_default: dict | None = None, path_string_config: dict | None = None, use_svg_cache: bool = True, **kwargs: Any, ): super().__init__(color=None, stroke_color=None, fill_color=None, **kwargs) # process keyword arguments self.file_name = Path(file_name) if file_name is not None else None self.should_center = should_center self.svg_height = height self.svg_width = width self.color = ManimColor(color) self.opacity = opacity self.fill_color = fill_color self.fill_opacity = fill_opacity # type: ignore[assignment] self.stroke_color = stroke_color self.stroke_opacity = stroke_opacity # type: ignore[assignment] self.stroke_width = stroke_width # type: ignore[assignment] self.id_to_vgroup_dict: dict[str, VGroup] = {} if self.stroke_width is None: self.stroke_width = 0 if svg_default is None: svg_default = { "color": None, "opacity": None, "fill_color": None, "fill_opacity": None, "stroke_width": 0, "stroke_color": None, "stroke_opacity": None, } self.svg_default = svg_default if path_string_config is None: path_string_config = {} self.path_string_config = path_string_config self.init_svg_mobject(use_svg_cache=use_svg_cache) self.set_style( fill_color=fill_color, fill_opacity=fill_opacity, stroke_color=stroke_color, stroke_opacity=stroke_opacity, stroke_width=stroke_width, ) self.move_into_position() def init_svg_mobject(self, use_svg_cache: bool) -> None: """Checks whether the SVG has already been imported and generates it if not. See also -------- :meth:`.SVGMobject.generate_mobject` """ if use_svg_cache: hash_val = hash_obj(self.hash_seed) if hash_val in SVG_HASH_TO_MOB_MAP: mob = SVG_HASH_TO_MOB_MAP[hash_val].copy() self.add(*mob) self.id_to_vgroup_dict = mob.id_to_vgroup_dict return self.generate_mobject() if use_svg_cache: SVG_HASH_TO_MOB_MAP[hash_val] = self.copy() @property def hash_seed(self) -> tuple: """A unique hash representing the result of the generated mobject points. Used as keys in the ``SVG_HASH_TO_MOB_MAP`` caching dictionary. """ return ( self.__class__.__name__, self.svg_default, self.path_string_config, self.file_name, config.renderer, ) def generate_mobject(self) -> None: """Parse the SVG and translate its elements to submobjects.""" file_path = self.get_file_path() element_tree = ET.parse(file_path) new_tree = self.modify_xml_tree(element_tree) # type: ignore[arg-type] # Create a temporary svg file to dump modified svg to be parsed modified_file_path = file_path.with_name(f"{file_path.stem}_{file_path.suffix}") new_tree.write(modified_file_path) svg = se.SVG.parse(modified_file_path) modified_file_path.unlink() mobjects, mobject_dict = self.get_mobjects_from(svg) self.add(*mobjects) self.id_to_vgroup_dict = mobject_dict self.flip(RIGHT) # Flip y def get_file_path(self) -> Path: """Search for an existing file based on the specified file name.""" if self.file_name is None: raise ValueError("Must specify file for SVGMobject") return get_full_vector_image_path(self.file_name) def modify_xml_tree(self, element_tree: ET.ElementTree) -> ET.ElementTree: """Modifies the SVG element tree to include default style information. Parameters ---------- element_tree The parsed element tree from the SVG file. """ config_style_dict = self.generate_config_style_dict() style_keys = ( "fill", "fill-opacity", "stroke", "stroke-opacity", "stroke-width", "style", ) root = element_tree.getroot() root_style_dict = {k: v for k, v in root.attrib.items() if k in style_keys} # type: ignore[union-attr] new_root = ET.Element("svg", {}) config_style_node = ET.SubElement(new_root, "g", config_style_dict) root_style_node = ET.SubElement(config_style_node, "g", root_style_dict) root_style_node.extend(root) # type: ignore[arg-type] return ET.ElementTree(new_root) def generate_config_style_dict(self) -> dict[str, str]: """Generate a dictionary holding the default style information.""" keys_converting_dict = { "fill": ("color", "fill_color"), "fill-opacity": ("opacity", "fill_opacity"), "stroke": ("color", "stroke_color"), "stroke-opacity": ("opacity", "stroke_opacity"), "stroke-width": ("stroke_width",), } svg_default_dict = self.svg_default result = {} for svg_key, style_keys in keys_converting_dict.items(): for style_key in style_keys: if svg_default_dict[style_key] is None: continue result[svg_key] = str(svg_default_dict[style_key]) return result def get_mobjects_from( self, svg: se.SVG ) -> tuple[list[VMobject], dict[str, VGroup]]: """Convert the elements of the SVG to a list of mobjects. Parameters ---------- svg The parsed SVG file. """ result: list[VMobject] = [] stack: list[tuple[se.SVGElement, int]] = [] stack.append((svg, 1)) group_id_number = 0 vgroup_stack: list[str] = ["root"] vgroup_names: list[str] = ["root"] vgroups: dict[str, VGroup] = {"root": VGroup()} while len(stack) > 0: element, depth = stack.pop() # Reduce stack heights vgroup_stack = vgroup_stack[0:(depth)] try: group_name = str(element.values["id"]) except Exception: group_name = f"numbered_group_{group_id_number}" group_id_number += 1 vg = VGroup() vgroup_names.append(group_name) vgroup_stack.append(group_name) vgroups[group_name] = vg if isinstance(element, (se.Group, se.Use)): stack.extend((subelement, depth + 1) for subelement in element[::-1]) # Add element to the parent vgroup try: if isinstance( element, ( se.Path, se.SimpleLine, se.Rect, se.Circle, se.Ellipse, se.Polygon, se.Polyline, se.Text, ), ): mob = self.get_mob_from_shape_element(element) if mob is not None: result.append(mob) for parent_name in vgroup_stack[:-1]: vgroups[parent_name].add(mob) except Exception as e: logger.error(f"Exception occurred in 'get_mobjects_from'. Details: {e}") return result, vgroups def get_mob_from_shape_element(self, shape: se.SVGElement) -> VMobject | None: if isinstance(shape, se.Path): mob: VMobject | None = self.path_to_mobject(shape) elif isinstance(shape, se.SimpleLine): mob = self.line_to_mobject(shape) elif isinstance(shape, se.Rect): mob = self.rect_to_mobject(shape) elif isinstance(shape, (se.Circle, se.Ellipse)): mob = self.ellipse_to_mobject(shape) elif isinstance(shape, se.Polygon): mob = self.polygon_to_mobject(shape) elif isinstance(shape, se.Polyline): mob = self.polyline_to_mobject(shape) elif isinstance(shape, se.Text): mob = self.text_to_mobject(shape) else: logger.warning(f"Unsupported element type: {type(shape)}") mob = None if mob is None or not mob.has_points(): return mob self.apply_style_to_mobject(mob, shape) if isinstance(shape, se.Transformable) and shape.apply: self.handle_transform(mob, shape.transform) return mob @staticmethod def handle_transform(mob: VMobject, matrix: se.Matrix) -> VMobject: """Apply SVG transformations to the converted mobject. Parameters ---------- mob The converted mobject. matrix The transformation matrix determined from the SVG transformation. """ mat = np.array([[matrix.a, matrix.c], [matrix.b, matrix.d]]) vec = np.array([matrix.e, matrix.f, 0.0]) mob.apply_matrix(mat) mob.shift(vec) return mob @staticmethod def apply_style_to_mobject(mob: VMobject, shape: se.GraphicObject) -> VMobject: """Apply SVG style information to the converted mobject. Parameters ---------- mob The converted mobject. shape The parsed SVG element. """ mob.set_style( stroke_width=shape.stroke_width, stroke_color=shape.stroke.hexrgb, stroke_opacity=shape.stroke.opacity, fill_color=shape.fill.hexrgb, fill_opacity=shape.fill.opacity, ) return mob def path_to_mobject(self, path: se.Path) -> VMobjectFromSVGPath: """Convert a path element to a vectorized mobject. Parameters ---------- path The parsed SVG path. """ return VMobjectFromSVGPath(path, **self.path_string_config) @staticmethod def line_to_mobject(line: se.Line) -> Line: """Convert a line element to a vectorized mobject. Parameters ---------- line The parsed SVG line. """ return Line( start=_convert_point_to_3d(line.x1, line.y1), end=_convert_point_to_3d(line.x2, line.y2), ) @staticmethod def rect_to_mobject(rect: se.Rect) -> Rectangle: """Convert a rectangle element to a vectorized mobject. Parameters ---------- rect The parsed SVG rectangle. """ if rect.rx == 0 or rect.ry == 0: mob = Rectangle( width=rect.width, height=rect.height, ) else: mob = RoundedRectangle( width=rect.width, height=rect.height * rect.rx / rect.ry, corner_radius=rect.rx, ) mob.stretch_to_fit_height(rect.height) mob.shift( _convert_point_to_3d(rect.x + rect.width / 2, rect.y + rect.height / 2) ) return mob @staticmethod def ellipse_to_mobject(ellipse: se.Ellipse | se.Circle) -> Circle: """Convert an ellipse or circle element to a vectorized mobject. Parameters ---------- ellipse The parsed SVG ellipse or circle. """ mob = Circle(radius=ellipse.rx) if ellipse.rx != ellipse.ry: mob.stretch_to_fit_height(2 * ellipse.ry) mob.shift(_convert_point_to_3d(ellipse.cx, ellipse.cy)) return mob @staticmethod def polygon_to_mobject(polygon: se.Polygon) -> Polygon: """Convert a polygon element to a vectorized mobject. Parameters ---------- polygon The parsed SVG polygon. """ points = [_convert_point_to_3d(*point) for point in polygon] return Polygon(*points) def polyline_to_mobject(self, polyline: se.Polyline) -> VMobject: """Convert a polyline element to a vectorized mobject. Parameters ---------- polyline The parsed SVG polyline. """ points = [_convert_point_to_3d(*point) for point in polyline] vmobject_class = self.get_mobject_type_class() return vmobject_class().set_points_as_corners(points) @staticmethod def text_to_mobject(text: se.Text) -> VMobject: """Convert a text element to a vectorized mobject. .. warning:: Not yet implemented. Parameters ---------- text The parsed SVG text. """ logger.warning(f"Unsupported element type: {type(text)}") return # type: ignore[return-value] def move_into_position(self) -> None: """Scale and move the generated mobject into position.""" if self.should_center: self.center() if self.svg_height is not None: self.set(height=self.svg_height) if self.svg_width is not None: self.set(width=self.svg_width) class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL): """A vectorized mobject representing an SVG path. .. note:: The ``long_lines``, ``should_subdivide_sharp_curves``, and ``should_remove_null_curves`` keyword arguments are only respected with the OpenGL renderer. Parameters ---------- path_obj A parsed SVG path object. long_lines Whether or not straight lines in the vectorized mobject are drawn in one or two segments. should_subdivide_sharp_curves Whether or not to subdivide subcurves further in case two segments meet at an angle that is sharper than a given threshold. should_remove_null_curves Whether or not to remove subcurves of length 0. kwargs Further keyword arguments are passed to the parent class. """ def __init__( self, path_obj: se.Path, long_lines: bool = False, should_subdivide_sharp_curves: bool = False, should_remove_null_curves: bool = False, **kwargs: Any, ): # Get rid of arcs path_obj.approximate_arcs_with_quads() self.path_obj = path_obj self.long_lines = long_lines self.should_subdivide_sharp_curves = should_subdivide_sharp_curves self.should_remove_null_curves = should_remove_null_curves super().__init__(**kwargs) def generate_points(self) -> None: # TODO: cache mobject in a re-importable way self.handle_commands() if config.renderer == "opengl": if self.should_subdivide_sharp_curves: # For a healthy triangulation later self.subdivide_sharp_curves() if self.should_remove_null_curves: # Get rid of any null curves self.set_points(self.get_points_without_null_curves()) def init_points(self) -> None: self.generate_points() def handle_commands(self) -> None: all_points: list[np.ndarray] = [] last_move: np.ndarray = None curve_start = None last_true_move = None def move_pen(pt: np.ndarray, *, true_move: bool = False) -> None: nonlocal last_move, curve_start, last_true_move last_move = pt if curve_start is None: curve_start = last_move if true_move: last_true_move = last_move if self.n_points_per_curve == 4: def add_cubic( start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray ) -> None: nonlocal all_points assert len(all_points) % 4 == 0, len(all_points) all_points += [start, cp1, cp2, end] move_pen(end) def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None: add_cubic(start, (start + cp + cp) / 3, (cp + cp + end) / 3, end) move_pen(end) def add_line(start: np.ndarray, end: np.ndarray) -> None: add_cubic( start, (start + start + end) / 3, (start + end + end) / 3, end ) move_pen(end) else: def add_cubic( start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray ) -> None: nonlocal all_points assert len(all_points) % 3 == 0, len(all_points) two_quads = get_quadratic_approximation_of_cubic( start, cp1, cp2, end, ) all_points += two_quads[:3].tolist() all_points += two_quads[3:].tolist() move_pen(end) def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None: nonlocal all_points assert len(all_points) % 3 == 0, len(all_points) all_points += [start, cp, end] move_pen(end) def add_line(start: np.ndarray, end: np.ndarray) -> None: add_quad(start, (start + end) / 2, end) move_pen(end) for segment in self.path_obj: segment_class = segment.__class__ if segment_class == se.Move: move_pen(_convert_point_to_3d(*segment.end), true_move=True) elif segment_class == se.Line: add_line(last_move, _convert_point_to_3d(*segment.end)) elif segment_class == se.QuadraticBezier: add_quad( last_move, _convert_point_to_3d(*segment.control), _convert_point_to_3d(*segment.end), ) elif segment_class == se.CubicBezier: add_cubic( last_move, _convert_point_to_3d(*segment.control1), _convert_point_to_3d(*segment.control2), _convert_point_to_3d(*segment.end), ) elif segment_class == se.Close: # If the SVG path naturally ends at the beginning of the curve, # we do *not* need to draw a closing line. To account for floating # point precision, we use a small value to compare the two points. if abs(np.linalg.norm(last_move - last_true_move)) > 0.0001: add_line(last_move, last_true_move) curve_start = None else: raise AssertionError(f"Not implemented: {segment_class}") self.points = np.array(all_points, ndmin=2, dtype="float64") # If we have no points, make sure the array is shaped properly # (0 rows tall by 3 columns wide) so future operations can # add or remove points correctly. if len(all_points) == 0: self.points = np.reshape(self.points, (0, 3)) ================================================ FILE: manim/mobject/table.py ================================================ r"""Mobjects representing tables. Examples -------- .. manim:: TableExamples :save_last_frame: class TableExamples(Scene): def construct(self): t0 = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")], top_left_entry=Text("TOP")) t0.add_highlighted_cell((2,2), color=GREEN) x_vals = np.linspace(-2,2,5) y_vals = np.exp(x_vals) t1 = DecimalTable( [x_vals, y_vals], row_labels=[MathTex("x"), MathTex("f(x)")], include_outer_lines=True) t1.add(t1.get_cell((2,2), color=RED)) t2 = MathTable( [["+", 0, 5, 10], [0, 0, 5, 10], [2, 2, 7, 12], [4, 4, 9, 14]], include_outer_lines=True) t2.get_horizontal_lines()[:3].set_color(BLUE) t2.get_vertical_lines()[:3].set_color(BLUE) t2.get_horizontal_lines()[:3].set_z_index(1) cross = VGroup( Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT)) a = Circle().set_color(RED).scale(0.5) b = cross.set_color(BLUE).scale(0.5) t3 = MobjectTable( [[a.copy(),b.copy(),a.copy()], [b.copy(),a.copy(),a.copy()], [a.copy(),b.copy(),b.copy()]]) t3.add(Line( t3.get_corner(DL), t3.get_corner(UR) ).set_color(RED)) vals = np.arange(1,21).reshape(5,4) t4 = IntegerTable( vals, include_outer_lines=True ) g1 = Group(t0, t1).scale(0.5).arrange(buff=1).to_edge(UP, buff=1) g2 = Group(t2, t3, t4).scale(0.5).arrange(buff=1).to_edge(DOWN, buff=1) self.add(g1, g2) """ from __future__ import annotations __all__ = [ "Table", "MathTable", "MobjectTable", "IntegerTable", "DecimalTable", ] import itertools as it from collections.abc import Callable, Iterable, Sequence from manim.mobject.geometry.line import Line from manim.mobject.geometry.polygram import Polygon from manim.mobject.geometry.shape_matchers import BackgroundRectangle from manim.mobject.text.numbers import DecimalNumber, Integer from manim.mobject.text.tex_mobject import MathTex from manim.mobject.text.text_mobject import Paragraph from ..animation.animation import Animation from ..animation.composition import AnimationGroup from ..animation.creation import Create, Write from ..animation.fading import FadeIn from ..mobject.types.vectorized_mobject import VGroup, VMobject from ..utils.color import BLACK, PURE_YELLOW, ManimColor, ParsableManimColor from .utils import get_vectorized_mobject_class class Table(VGroup): r"""A mobject that displays a table on the screen. Parameters ---------- table A 2D array or list of lists. Content of the table has to be a valid input for the callable set in ``element_to_mobject``. row_labels List of :class:`~.VMobject` representing the labels of each row. col_labels List of :class:`~.VMobject` representing the labels of each column. top_left_entry The top-left entry of the table, can only be specified if row and column labels are given. v_buff Vertical buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 0.8. h_buff Horizontal buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 1.3. include_outer_lines ``True`` if the table should include outer lines, by default False. add_background_rectangles_to_entries ``True`` if background rectangles should be added to entries, by default ``False``. entries_background_color Background color of entries if ``add_background_rectangles_to_entries`` is ``True``. include_background_rectangle ``True`` if the table should have a background rectangle, by default ``False``. background_rectangle_color Background color of table if ``include_background_rectangle`` is ``True``. element_to_mobject The :class:`~.Mobject` class applied to the table entries. by default :class:`~.Paragraph`. For common choices, see :mod:`~.text_mobject`/:mod:`~.tex_mobject`. element_to_mobject_config Custom configuration passed to :attr:`element_to_mobject`, by default {}. arrange_in_grid_config Dict passed to :meth:`~.Mobject.arrange_in_grid`, customizes the arrangement of the table. line_config Dict passed to :class:`~.Line`, customizes the lines of the table. kwargs Additional arguments to be passed to :class:`~.VGroup`. Examples -------- .. manim:: TableExamples :save_last_frame: class TableExamples(Scene): def construct(self): t0 = Table( [["This", "is a"], ["simple", "Table in \\n Manim."]]) t1 = Table( [["This", "is a"], ["simple", "Table."]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) t1.add_highlighted_cell((2,2), color=YELLOW) t2 = Table( [["This", "is a"], ["simple", "Table."]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")], top_left_entry=Star().scale(0.3), include_outer_lines=True, arrange_in_grid_config={"cell_alignment": RIGHT}) t2.add(t2.get_cell((2,2), color=RED)) t3 = Table( [["This", "is a"], ["simple", "Table."]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")], top_left_entry=Star().scale(0.3), include_outer_lines=True, line_config={"stroke_width": 1, "color": YELLOW}) t3.remove(*t3.get_vertical_lines()) g = Group( t0,t1,t2,t3 ).scale(0.7).arrange_in_grid(buff=1) self.add(g) .. manim:: BackgroundRectanglesExample :save_last_frame: class BackgroundRectanglesExample(Scene): def construct(self): background = Rectangle(height=6.5, width=13) background.set_fill(opacity=.5) background.set_color([TEAL, RED, YELLOW]) self.add(background) t0 = Table( [["This", "is a"], ["simple", "Table."]], add_background_rectangles_to_entries=True) t1 = Table( [["This", "is a"], ["simple", "Table."]], include_background_rectangle=True) g = Group(t0, t1).scale(0.7).arrange(buff=0.5) self.add(g) """ def __init__( self, table: Iterable[Iterable[float | str | VMobject]], row_labels: Iterable[VMobject] | None = None, col_labels: Iterable[VMobject] | None = None, top_left_entry: VMobject | None = None, v_buff: float = 0.8, h_buff: float = 1.3, include_outer_lines: bool = False, add_background_rectangles_to_entries: bool = False, entries_background_color: ParsableManimColor = BLACK, include_background_rectangle: bool = False, background_rectangle_color: ParsableManimColor = BLACK, element_to_mobject: Callable[ [float | str | VMobject], VMobject, ] = Paragraph, element_to_mobject_config: dict = {}, arrange_in_grid_config: dict = {}, line_config: dict = {}, **kwargs, ): self.row_labels = row_labels self.col_labels = col_labels self.top_left_entry = top_left_entry self.row_dim = len(table) self.col_dim = len(table[0]) self.v_buff = v_buff self.h_buff = h_buff self.include_outer_lines = include_outer_lines self.add_background_rectangles_to_entries = add_background_rectangles_to_entries self.entries_background_color = ManimColor(entries_background_color) self.include_background_rectangle = include_background_rectangle self.background_rectangle_color = ManimColor(background_rectangle_color) self.element_to_mobject = element_to_mobject self.element_to_mobject_config = element_to_mobject_config self.arrange_in_grid_config = arrange_in_grid_config self.line_config = line_config for row in table: if len(row) == len(table[0]): pass else: raise ValueError("Not all rows in table have the same length.") super().__init__(**kwargs) mob_table = self._table_to_mob_table(table) self.elements_without_labels = VGroup(*it.chain(*mob_table)) mob_table = self._add_labels(mob_table) self._organize_mob_table(mob_table) self.elements = VGroup(*it.chain(*mob_table)) if len(self.elements[0].get_all_points()) == 0: self.elements.remove(self.elements[0]) self.add(self.elements) self.center() self.mob_table = mob_table self._add_horizontal_lines() self._add_vertical_lines() if self.add_background_rectangles_to_entries: self.add_background_to_entries(color=self.entries_background_color) if self.include_background_rectangle: self.add_background_rectangle(color=self.background_rectangle_color) def _table_to_mob_table( self, table: Iterable[Iterable[float | str | VMobject]], ) -> list: """Initializes the entries of ``table`` as :class:`~.VMobject`. Parameters ---------- table A 2D array or list of lists. Content of the table has to be a valid input for the callable set in ``element_to_mobject``. Returns -------- List List of :class:`~.VMobject` from the entries of ``table``. """ return [ [ self.element_to_mobject(item, **self.element_to_mobject_config) for item in row ] for row in table ] def _organize_mob_table(self, table: Iterable[Iterable[VMobject]]) -> VGroup: """Arranges the :class:`~.VMobject` of ``table`` in a grid. Parameters ---------- table A 2D iterable object with :class:`~.VMobject` entries. Returns -------- :class:`~.VGroup` The :class:`~.VMobject` of the ``table`` in a :class:`~.VGroup` already arranged in a table-like grid. """ help_table = VGroup() for i, row in enumerate(table): for j, _ in enumerate(row): help_table.add(table[i][j]) help_table.arrange_in_grid( rows=len(table), cols=len(table[0]), buff=(self.h_buff, self.v_buff), **self.arrange_in_grid_config, ) return help_table def _add_labels(self, mob_table: VGroup) -> VGroup: """Adds labels to an in a grid arranged :class:`~.VGroup`. Parameters ---------- mob_table An in a grid organized class:`~.VGroup`. Returns -------- :class:`~.VGroup` Returns the ``mob_table`` with added labels. """ if self.row_labels is not None: for k in range(len(self.row_labels)): mob_table[k] = [self.row_labels[k]] + mob_table[k] if self.col_labels is not None: if self.row_labels is not None: if self.top_left_entry is not None: col_labels = [self.top_left_entry] + self.col_labels mob_table.insert(0, col_labels) else: # Placeholder to use arrange_in_grid if top_left_entry is not set. # Import OpenGLVMobject to work with --renderer=opengl dummy_mobject = get_vectorized_mobject_class()() col_labels = [dummy_mobject] + self.col_labels mob_table.insert(0, col_labels) else: mob_table.insert(0, self.col_labels) return mob_table def _add_horizontal_lines(self) -> Table: """Adds the horizontal lines to the table.""" anchor_left = self.get_left()[0] - 0.5 * self.h_buff anchor_right = self.get_right()[0] + 0.5 * self.h_buff line_group = VGroup() if self.include_outer_lines: anchor = self.get_rows()[0].get_top()[1] + 0.5 * self.v_buff line = Line( [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config ) line_group.add(line) self.add(line) anchor = self.get_rows()[-1].get_bottom()[1] - 0.5 * self.v_buff line = Line( [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config ) line_group.add(line) self.add(line) for k in range(len(self.mob_table) - 1): anchor = self.get_rows()[k + 1].get_top()[1] + 0.5 * ( self.get_rows()[k].get_bottom()[1] - self.get_rows()[k + 1].get_top()[1] ) line = Line( [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config ) line_group.add(line) self.add(line) self.horizontal_lines = line_group return self def _add_vertical_lines(self) -> Table: """Adds the vertical lines to the table""" anchor_top = self.get_rows().get_top()[1] + 0.5 * self.v_buff anchor_bottom = self.get_rows().get_bottom()[1] - 0.5 * self.v_buff line_group = VGroup() if self.include_outer_lines: anchor = self.get_columns()[0].get_left()[0] - 0.5 * self.h_buff line = Line( [anchor, anchor_top, 0], [anchor, anchor_bottom, 0], **self.line_config ) line_group.add(line) self.add(line) anchor = self.get_columns()[-1].get_right()[0] + 0.5 * self.h_buff line = Line( [anchor, anchor_top, 0], [anchor, anchor_bottom, 0], **self.line_config ) line_group.add(line) self.add(line) for k in range(len(self.mob_table[0]) - 1): anchor = self.get_columns()[k + 1].get_left()[0] + 0.5 * ( self.get_columns()[k].get_right()[0] - self.get_columns()[k + 1].get_left()[0] ) line = Line( [anchor, anchor_bottom, 0], [anchor, anchor_top, 0], **self.line_config ) line_group.add(line) self.add(line) self.vertical_lines = line_group return self def get_horizontal_lines(self) -> VGroup: """Return the horizontal lines of the table. Returns -------- :class:`~.VGroup` :class:`~.VGroup` containing all the horizontal lines of the table. Examples -------- .. manim:: GetHorizontalLinesExample :save_last_frame: class GetHorizontalLinesExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) table.get_horizontal_lines().set_color(RED) self.add(table) """ return self.horizontal_lines def get_vertical_lines(self) -> VGroup: """Return the vertical lines of the table. Returns -------- :class:`~.VGroup` :class:`~.VGroup` containing all the vertical lines of the table. Examples -------- .. manim:: GetVerticalLinesExample :save_last_frame: class GetVerticalLinesExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) table.get_vertical_lines()[0].set_color(RED) self.add(table) """ return self.vertical_lines def get_columns(self) -> VGroup: """Return columns of the table as a :class:`~.VGroup` of :class:`~.VGroup`. Returns -------- :class:`~.VGroup` :class:`~.VGroup` containing each column in a :class:`~.VGroup`. Examples -------- .. manim:: GetColumnsExample :save_last_frame: class GetColumnsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) table.add(SurroundingRectangle(table.get_columns()[1])) self.add(table) """ return VGroup( *( VGroup(*(row[i] for row in self.mob_table)) for i in range(len(self.mob_table[0])) ) ) def get_rows(self) -> VGroup: """Return the rows of the table as a :class:`~.VGroup` of :class:`~.VGroup`. Returns -------- :class:`~.VGroup` :class:`~.VGroup` containing each row in a :class:`~.VGroup`. Examples -------- .. manim:: GetRowsExample :save_last_frame: class GetRowsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) table.add(SurroundingRectangle(table.get_rows()[1])) self.add(table) """ return VGroup(*(VGroup(*row) for row in self.mob_table)) def set_column_colors(self, *colors: Iterable[ParsableManimColor]) -> Table: """Set individual colors for each column of the table. Parameters ---------- colors An iterable of colors; each color corresponds to a column. Examples -------- .. manim:: SetColumnColorsExample :save_last_frame: class SetColumnColorsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")] ).set_column_colors([RED,BLUE], GREEN) self.add(table) """ columns = self.get_columns() for color, column in zip(colors, columns, strict=False): column.set_color(color) return self def set_row_colors(self, *colors: Iterable[ParsableManimColor]) -> Table: """Set individual colors for each row of the table. Parameters ---------- colors An iterable of colors; each color corresponds to a row. Examples -------- .. manim:: SetRowColorsExample :save_last_frame: class SetRowColorsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")] ).set_row_colors([RED,BLUE], GREEN) self.add(table) """ rows = self.get_rows() for color, row in zip(colors, rows, strict=False): row.set_color(color) return self def get_entries( self, pos: Sequence[int] | None = None, ) -> VMobject | VGroup: """Return the individual entries of the table (including labels) or one specific entry if the parameter, ``pos``, is set. Parameters ---------- pos The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table. Returns ------- Union[:class:`~.VMobject`, :class:`~.VGroup`] :class:`~.VGroup` containing all entries of the table (including labels) or the :class:`~.VMobject` at the given position if ``pos`` is set. Examples -------- .. manim:: GetEntriesExample :save_last_frame: class GetEntriesExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) ent = table.get_entries() for item in ent: item.set_color(random_bright_color()) table.get_entries((2,2)).rotate(PI) self.add(table) """ if pos is not None: if ( self.row_labels is not None and self.col_labels is not None and self.top_left_entry is None ): index = len(self.mob_table[0]) * (pos[0] - 1) + pos[1] - 2 return self.elements[index] else: index = len(self.mob_table[0]) * (pos[0] - 1) + pos[1] - 1 return self.elements[index] else: return self.elements def get_entries_without_labels( self, pos: Sequence[int] | None = None, ) -> VMobject | VGroup: """Return the individual entries of the table (without labels) or one specific entry if the parameter, ``pos``, is set. Parameters ---------- pos The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table (without labels). Returns ------- Union[:class:`~.VMobject`, :class:`~.VGroup`] :class:`~.VGroup` containing all entries of the table (without labels) or the :class:`~.VMobject` at the given position if ``pos`` is set. Examples -------- .. manim:: GetEntriesWithoutLabelsExample :save_last_frame: class GetEntriesWithoutLabelsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) ent = table.get_entries_without_labels() colors = [BLUE, GREEN, YELLOW, RED] for k in range(len(colors)): ent[k].set_color(colors[k]) table.get_entries_without_labels((2,2)).rotate(PI) self.add(table) """ if pos is not None: index = self.col_dim * (pos[0] - 1) + pos[1] - 1 return self.elements_without_labels[index] else: return self.elements_without_labels def get_row_labels(self) -> VGroup: """Return the row labels of the table. Returns ------- :class:`~.VGroup` :class:`~.VGroup` containing the row labels of the table. Examples -------- .. manim:: GetRowLabelsExample :save_last_frame: class GetRowLabelsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) lab = table.get_row_labels() for item in lab: item.set_color(random_bright_color()) self.add(table) """ return VGroup(*self.row_labels) def get_col_labels(self) -> VGroup: """Return the column labels of the table. Returns -------- :class:`~.VGroup` VGroup containing the column labels of the table. Examples -------- .. manim:: GetColLabelsExample :save_last_frame: class GetColLabelsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) lab = table.get_col_labels() for item in lab: item.set_color(random_bright_color()) self.add(table) """ return VGroup(*self.col_labels) def get_labels(self) -> VGroup: """Returns the labels of the table. Returns -------- :class:`~.VGroup` :class:`~.VGroup` containing all the labels of the table. Examples -------- .. manim:: GetLabelsExample :save_last_frame: class GetLabelsExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) lab = table.get_labels() colors = [BLUE, GREEN, YELLOW, RED] for k in range(len(colors)): lab[k].set_color(colors[k]) self.add(table) """ label_group = VGroup() if self.top_left_entry is not None: label_group.add(self.top_left_entry) for label in (self.col_labels, self.row_labels): if label is not None: label_group.add(*label) return label_group def add_background_to_entries(self, color: ParsableManimColor = BLACK) -> Table: """Adds a black :class:`~.BackgroundRectangle` to each entry of the table.""" for mob in self.get_entries(): mob.add_background_rectangle(color=ManimColor(color)) return self def get_cell(self, pos: Sequence[int] = (1, 1), **kwargs) -> Polygon: """Returns one specific cell as a rectangular :class:`~.Polygon` without the entry. Parameters ---------- pos The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table. kwargs Additional arguments to be passed to :class:`~.Polygon`. Returns ------- :class:`~.Polygon` Polygon mimicking one specific cell of the Table. Examples -------- .. manim:: GetCellExample :save_last_frame: class GetCellExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) cell = table.get_cell((2,2), color=RED) self.add(table, cell) """ row = self.get_rows()[pos[0] - 1] col = self.get_columns()[pos[1] - 1] edge_UL = [ col.get_left()[0] - self.h_buff / 2, row.get_top()[1] + self.v_buff / 2, 0, ] edge_UR = [ col.get_right()[0] + self.h_buff / 2, row.get_top()[1] + self.v_buff / 2, 0, ] edge_DL = [ col.get_left()[0] - self.h_buff / 2, row.get_bottom()[1] - self.v_buff / 2, 0, ] edge_DR = [ col.get_right()[0] + self.h_buff / 2, row.get_bottom()[1] - self.v_buff / 2, 0, ] rec = Polygon(edge_UL, edge_UR, edge_DR, edge_DL, **kwargs) return rec def get_highlighted_cell( self, pos: Sequence[int] = (1, 1), color: ParsableManimColor = PURE_YELLOW, **kwargs, ) -> BackgroundRectangle: """Returns a :class:`~.BackgroundRectangle` of the cell at the given position. Parameters ---------- pos The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table. color The color used to highlight the cell. kwargs Additional arguments to be passed to :class:`~.BackgroundRectangle`. Examples -------- .. manim:: GetHighlightedCellExample :save_last_frame: class GetHighlightedCellExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) highlight = table.get_highlighted_cell((2,2), color=GREEN) table.add_to_back(highlight) self.add(table) """ cell = self.get_cell(pos) bg_cell = BackgroundRectangle(cell, color=ManimColor(color), **kwargs) return bg_cell def add_highlighted_cell( self, pos: Sequence[int] = (1, 1), color: ParsableManimColor = PURE_YELLOW, **kwargs, ) -> Table: """Highlights one cell at a specific position on the table by adding a :class:`~.BackgroundRectangle`. Parameters ---------- pos The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table. color The color used to highlight the cell. kwargs Additional arguments to be passed to :class:`~.BackgroundRectangle`. Examples -------- .. manim:: AddHighlightedCellExample :save_last_frame: class AddHighlightedCellExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")]) table.add_highlighted_cell((2,2), color=GREEN) self.add(table) """ bg_cell = self.get_highlighted_cell(pos, color=ManimColor(color), **kwargs) self.add_to_back(bg_cell) entry = self.get_entries(pos) entry.background_rectangle = bg_cell return self def create( self, lag_ratio: float = 1, line_animation: Callable[[VMobject | VGroup], Animation] = Create, label_animation: Callable[[VMobject | VGroup], Animation] = Write, element_animation: Callable[[VMobject | VGroup], Animation] = Create, entry_animation: Callable[[VMobject | VGroup], Animation] = FadeIn, **kwargs, ) -> AnimationGroup: """Customized create-type function for tables. Parameters ---------- lag_ratio The lag ratio of the animation. line_animation The animation style of the table lines, see :mod:`~.creation` for examples. label_animation The animation style of the table labels, see :mod:`~.creation` for examples. element_animation The animation style of the table elements, see :mod:`~.creation` for examples. entry_animation The entry animation of the table background, see :mod:`~.creation` for examples. kwargs Further arguments passed to the creation animations. Returns ------- :class:`~.AnimationGroup` AnimationGroup containing creation of the lines and of the elements. Examples -------- .. manim:: CreateTableExample class CreateTableExample(Scene): def construct(self): table = Table( [["First", "Second"], ["Third","Fourth"]], row_labels=[Text("R1"), Text("R2")], col_labels=[Text("C1"), Text("C2")], include_outer_lines=True) self.play(table.create()) self.wait() """ animations: Sequence[Animation] = [ line_animation( VGroup(self.vertical_lines, self.horizontal_lines), **kwargs, ), element_animation(self.elements_without_labels.set_z_index(2), **kwargs), ] if self.get_labels(): animations += [ label_animation(self.get_labels(), **kwargs), ] if self.get_entries(): for entry in self.elements_without_labels: try: animations += [ entry_animation( entry.background_rectangle, **kwargs, ) ] except AttributeError: continue return AnimationGroup(*animations, lag_ratio=lag_ratio) def scale(self, scale_factor: float, **kwargs): # h_buff and v_buff must be adjusted so that Table.get_cell # can construct an accurate polygon for a cell. self.h_buff *= scale_factor self.v_buff *= scale_factor super().scale(scale_factor, **kwargs) return self class MathTable(Table): """A specialized :class:`~.Table` mobject for use with LaTeX. Examples -------- .. manim:: MathTableExample :save_last_frame: class MathTableExample(Scene): def construct(self): t0 = MathTable( [["+", 0, 5, 10], [0, 0, 5, 10], [2, 2, 7, 12], [4, 4, 9, 14]], include_outer_lines=True) self.add(t0) """ def __init__( self, table: Iterable[Iterable[float | str]], element_to_mobject: Callable[[float | str], VMobject] = MathTex, **kwargs, ): """ Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.MathTex`. Every entry in `table` is set in a Latex `align` environment. Parameters ---------- table A 2d array or list of lists. Content of the table have to be valid input for :class:`~.MathTex`. element_to_mobject The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.MathTex`. kwargs Additional arguments to be passed to :class:`~.Table`. """ super().__init__( table, element_to_mobject=element_to_mobject, **kwargs, ) class MobjectTable(Table): """A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`. Examples -------- .. manim:: MobjectTableExample :save_last_frame: class MobjectTableExample(Scene): def construct(self): cross = VGroup( Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT), ) a = Circle().set_color(RED).scale(0.5) b = cross.set_color(BLUE).scale(0.5) t0 = MobjectTable( [[a.copy(),b.copy(),a.copy()], [b.copy(),a.copy(),a.copy()], [a.copy(),b.copy(),b.copy()]] ) line = Line( t0.get_corner(DL), t0.get_corner(UR) ).set_color(RED) self.add(t0, line) """ def __init__( self, table: Iterable[Iterable[VMobject]], element_to_mobject: Callable[[VMobject], VMobject] = lambda m: m, **kwargs, ): """ Special case of :class:`~.Table` with ``element_to_mobject`` set to an identity function. Here, every item in ``table`` must already be of type :class:`~.Mobject`. Parameters ---------- table A 2D array or list of lists. Content of the table must be of type :class:`~.Mobject`. element_to_mobject The :class:`~.Mobject` class applied to the table entries. Set as ``lambda m : m`` to return itself. kwargs Additional arguments to be passed to :class:`~.Table`. """ super().__init__(table, element_to_mobject=element_to_mobject, **kwargs) class IntegerTable(Table): r"""A specialized :class:`~.Table` mobject for use with :class:`~.Integer`. Examples -------- .. manim:: IntegerTableExample :save_last_frame: class IntegerTableExample(Scene): def construct(self): t0 = IntegerTable( [[0,30,45,60,90], [90,60,45,30,0]], col_labels=[ 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": r"^{\circ}"}) self.add(t0) """ def __init__( self, table: Iterable[Iterable[float | str]], element_to_mobject: Callable[[float | str], VMobject] = Integer, **kwargs, ): """ Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.Integer`. Will round if there are decimal entries in the table. Parameters ---------- table A 2d array or list of lists. Content of the table has to be valid input for :class:`~.Integer`. element_to_mobject The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.Integer`. kwargs Additional arguments to be passed to :class:`~.Table`. """ super().__init__(table, element_to_mobject=element_to_mobject, **kwargs) class DecimalTable(Table): """A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries. Examples -------- .. manim:: DecimalTableExample :save_last_frame: class DecimalTableExample(Scene): def construct(self): x_vals = [-2,-1,0,1,2] y_vals = np.exp(x_vals) t0 = DecimalTable( [x_vals, y_vals], row_labels=[MathTex("x"), MathTex("f(x)=e^{x}")], h_buff=1, element_to_mobject_config={"num_decimal_places": 2}) self.add(t0) """ def __init__( self, table: Iterable[Iterable[float | str]], element_to_mobject: Callable[[float | str], VMobject] = DecimalNumber, element_to_mobject_config: dict = {"num_decimal_places": 1}, **kwargs, ): """ Special case of :class:`~.Table` with ``element_to_mobject`` set to :class:`~.DecimalNumber`. By default, ``num_decimal_places`` is set to 1. Will round/truncate the decimal places based on the provided ``element_to_mobject_config``. Parameters ---------- table A 2D array, or a list of lists. Content of the table must be valid input for :class:`~.DecimalNumber`. element_to_mobject The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.DecimalNumber`. element_to_mobject_config Element to mobject config, here set as {"num_decimal_places": 1}. kwargs Additional arguments to be passed to :class:`~.Table`. """ super().__init__( table, element_to_mobject=element_to_mobject, element_to_mobject_config=element_to_mobject_config, **kwargs, ) ================================================ FILE: manim/mobject/text/__init__.py ================================================ """Mobjects used to display Text using Pango or LaTeX. Modules ======= .. autosummary:: :toctree: ../reference ~code_mobject ~numbers ~tex_mobject ~text_mobject """ ================================================ FILE: manim/mobject/text/code_mobject.py ================================================ """Mobject representing highlighted source code listings.""" from __future__ import annotations __all__ = [ "Code", ] import re from pathlib import Path from typing import Any, Literal from bs4 import BeautifulSoup, Tag from pygments import highlight from pygments.formatters.html import HtmlFormatter from pygments.lexers import get_lexer_by_name, guess_lexer, guess_lexer_for_filename from pygments.styles import get_all_styles from manim.constants import * from manim.mobject.geometry.arc import Dot from manim.mobject.geometry.shape_matchers import SurroundingRectangle from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.typing import StrPath from manim.utils.color import WHITE, ManimColor class Code(VMobject, metaclass=ConvertToOpenGL): """A highlighted source code listing. Examples -------- Normal usage:: listing = Code( "helloworldcpp.cpp", tab_width=4, formatter_style="emacs", background="window", language="cpp", background_config={"stroke_color": WHITE}, paragraph_config={"font": "Noto Sans Mono"}, ) We can also render code passed as a string. As the automatic language detection can be a bit flaky, it is recommended to specify the language explicitly: .. manim:: CodeFromString :save_last_frame: class CodeFromString(Scene): def construct(self): code = '''from manim import Scene, Square class FadeInSquare(Scene): def construct(self): s = Square() self.play(FadeIn(s)) self.play(s.animate.scale(2)) self.wait()''' rendered_code = Code( code_string=code, language="python", background="window", background_config={"stroke_color": "maroon"}, ) self.add(rendered_code) Parameters ---------- code_file The path to the code file to display. code_string Alternatively, the code string to display. language The programming language of the code. If not specified, it will be guessed from the file extension or the code itself. formatter_style The style to use for the code highlighting. Defaults to ``"vim"``. A list of all available styles can be obtained by calling :meth:`.Code.get_styles_list`. tab_width The width of a tab character in spaces. Defaults to 4. add_line_numbers Whether to display line numbers. Defaults to ``True``. line_numbers_from The first line number to display. Defaults to 1. background The type of background to use. Can be either ``"rectangle"`` (the default) or ``"window"``. background_config Keyword arguments passed to the background constructor. Default settings are stored in the class attribute :attr:`.default_background_config` (which can also be modified directly). paragraph_config Keyword arguments passed to the constructor of the :class:`.Paragraph` objects holding the code, and the line numbers. Default settings are stored in the class attribute :attr:`.default_paragraph_config` (which can also be modified directly). """ _styles_list_cache: list[str] | None = None default_background_config: dict[str, Any] = { "buff": 0.3, "fill_color": ManimColor("#222"), "stroke_color": WHITE, "corner_radius": 0.2, "stroke_width": 1, "fill_opacity": 1, } default_paragraph_config: dict[str, Any] = { "font": "Monospace", "font_size": 24, "line_spacing": 0.5, "disable_ligatures": True, } code: VMobject def __init__( self, code_file: StrPath | None = None, code_string: str | None = None, language: str | None = None, formatter_style: str = "vim", tab_width: int = 4, add_line_numbers: bool = True, line_numbers_from: int = 1, background: Literal["rectangle", "window"] = "rectangle", background_config: dict[str, Any] | None = None, paragraph_config: dict[str, Any] | None = None, ): super().__init__() if code_file is not None: code_file = Path(code_file) code_string = code_file.read_text(encoding="utf-8") lexer = guess_lexer_for_filename(code_file.name, code_string) elif code_string is not None: if language is not None: lexer = get_lexer_by_name(language) else: lexer = guess_lexer(code_string) else: raise ValueError("Either a code file or a code string must be specified.") code_string = code_string.expandtabs(tabsize=tab_width) formatter = HtmlFormatter( style=formatter_style, noclasses=True, cssclasses="", ) soup = BeautifulSoup( highlight(code_string, lexer, formatter), features="html.parser" ) self._code_html = soup.find("pre") assert isinstance(self._code_html, Tag) # as we are using Paragraph to render the text, we need to find the character indices # of the segments of changed color in the HTML code color_ranges = [] current_line_color_ranges = [] current_line_char_index = 0 for child in self._code_html.children: if child.name == "span": try: child_style = child["style"] match_ = re.match( r"color: (#[A-Fa-f0-9]{6}|#[A-Fa-f0-9]{3})", child_style ) color = None if match_ is None else match_.group(1) except KeyError: color = None current_line_color_ranges.append( ( current_line_char_index, current_line_char_index + len(child.text), color, ) ) current_line_char_index += len(child.text) else: for char in child.text: if char == "\n": color_ranges.append(current_line_color_ranges) current_line_color_ranges = [] current_line_char_index = 0 else: current_line_char_index += 1 color_ranges.append(current_line_color_ranges) code_lines = self._code_html.get_text().removesuffix("\n").split("\n") if paragraph_config is None: paragraph_config = {} base_paragraph_config = self.default_paragraph_config.copy() base_paragraph_config.update(paragraph_config) from manim.mobject.text.text_mobject import Paragraph self.code_lines = Paragraph( *code_lines, **base_paragraph_config, ) for line, color_range in zip(self.code_lines, color_ranges, strict=False): for start, end, color in color_range: line[start:end].set_color(color) if add_line_numbers: base_paragraph_config.update({"alignment": "right"}) self.line_numbers = Paragraph( *[ str(i) for i in range( line_numbers_from, line_numbers_from + len(self.code_lines) ) ], **base_paragraph_config, ) self.line_numbers.next_to(self.code_lines, direction=LEFT).align_to( self.code_lines, UP ) self.add(self.line_numbers) for line in self.code_lines: line.submobjects = [c for c in line if not isinstance(c, Dot)] self.add(self.code_lines) if background_config is None: background_config = {} background_config_base = self.default_background_config.copy() background_config_base.update(background_config) if background == "rectangle": self.background = SurroundingRectangle( self, **background_config_base, ) elif background == "window": buttons = VGroup( Dot(radius=0.1, stroke_width=0, color=button_color) for button_color in ["#ff5f56", "#ffbd2e", "#27c93f"] ).arrange(RIGHT, buff=0.1) buttons.next_to(self, UP, buff=0.1).align_to(self, LEFT).shift(LEFT * 0.1) self.background = SurroundingRectangle( VGroup(self, buttons), **background_config_base, ) buttons.shift(UP * 0.1 + LEFT * 0.1) self.background.add(buttons) else: raise ValueError(f"Unknown background type: {background}") self.add_to_back(self.background) @classmethod def get_styles_list(cls) -> list[str]: """Get the list of all available formatter styles.""" if cls._styles_list_cache is None: cls._styles_list_cache = list(get_all_styles()) return cls._styles_list_cache ================================================ FILE: manim/mobject/text/numbers.py ================================================ """Mobjects representing numbers.""" from __future__ import annotations __all__ = ["DecimalNumber", "Integer", "Variable"] from typing import Any, Self import numpy as np from manim import config from manim.constants import * from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.text.tex_mobject import MathTex, SingleStringMathTex, Tex from manim.mobject.text.text_mobject import Text from manim.mobject.types.vectorized_mobject import VMobject from manim.mobject.value_tracker import ValueTracker from manim.typing import Vector3DLike string_to_mob_map: dict[str, SingleStringMathTex] = {} class DecimalNumber(VMobject, metaclass=ConvertToOpenGL): r"""An mobject representing a decimal number. Parameters ---------- number The numeric value to be displayed. It can later be modified using :meth:`.set_value`. num_decimal_places The number of decimal places after the decimal separator. Values are automatically rounded. mob_class The class for rendering digits and units, by default :class:`.MathTex`. include_sign Set to ``True`` to include a sign for positive numbers and zero. group_with_commas When ``True`` thousands groups are separated by commas for readability. digit_buff_per_font_unit Additional spacing between digits. Scales with font size. show_ellipsis When a number has been truncated by rounding, indicate with an ellipsis (``...``). unit A unit string which can be placed to the right of the numerical values. unit_buff_per_font_unit An additional spacing between the numerical values and the unit. A value of ``unit_buff_per_font_unit=0.003`` gives a decent spacing. Scales with font size. include_background_rectangle Adds a background rectangle to increase contrast on busy scenes. edge_to_fix Assuring right- or left-alignment of the full object. font_size Size of the font. Examples -------- .. manim:: MovingSquareWithUpdaters class MovingSquareWithUpdaters(Scene): def construct(self): decimal = DecimalNumber( 0, show_ellipsis=True, num_decimal_places=3, include_sign=True, unit=r"\text{M-Units}", unit_buff_per_font_unit=0.003 ) square = Square().to_edge(UP) decimal.add_updater(lambda d: d.next_to(square, RIGHT)) decimal.add_updater(lambda d: d.set_value(square.get_center()[1])) self.add(square, decimal) self.play( square.animate.to_edge(DOWN), rate_func=there_and_back, run_time=5, ) self.wait() """ def __init__( self, number: float = 0, num_decimal_places: int = 2, mob_class: type[SingleStringMathTex] = MathTex, include_sign: bool = False, group_with_commas: bool = True, digit_buff_per_font_unit: float = 0.001, show_ellipsis: bool = False, unit: str | None = None, # Aligned to bottom unless it starts with "^" unit_buff_per_font_unit: float = 0, include_background_rectangle: bool = False, edge_to_fix: Vector3DLike = LEFT, font_size: float = DEFAULT_FONT_SIZE, stroke_width: float = 0, fill_opacity: float = 1.0, **kwargs: Any, ): super().__init__(**kwargs, fill_opacity=fill_opacity, stroke_width=stroke_width) self.number = number self.num_decimal_places = num_decimal_places self.include_sign = include_sign self.mob_class = mob_class self.group_with_commas = group_with_commas self.digit_buff_per_font_unit = digit_buff_per_font_unit self.show_ellipsis = show_ellipsis self.unit = unit self.unit_buff_per_font_unit = unit_buff_per_font_unit self.include_background_rectangle = include_background_rectangle self.edge_to_fix = edge_to_fix self._font_size = font_size self.fill_opacity = fill_opacity self.initial_config = kwargs.copy() self.initial_config.update( { "num_decimal_places": num_decimal_places, "include_sign": include_sign, "group_with_commas": group_with_commas, "digit_buff_per_font_unit": digit_buff_per_font_unit, "show_ellipsis": show_ellipsis, "unit": unit, "unit_buff_per_font_unit": unit_buff_per_font_unit, "include_background_rectangle": include_background_rectangle, "edge_to_fix": edge_to_fix, "font_size": font_size, "stroke_width": stroke_width, "fill_opacity": fill_opacity, }, ) self._set_submobjects_from_number(number) self.init_colors() @property def font_size(self) -> float: """The font size of the tex mobject.""" return_value: float = self.height / self.initial_height * self._font_size return return_value @font_size.setter def font_size(self, font_val: float) -> None: if font_val <= 0: raise ValueError("font_size must be greater than 0.") elif self.height > 0: # sometimes manim generates a SingleStringMathex mobject with 0 height. # can't be scaled regardless and will error without the elif. # scale to a factor of the initial height so that setting # font_size does not depend on current size. self.scale(font_val / self.font_size) def _set_submobjects_from_number(self, number: float) -> None: self.number = number self.submobjects = [] num_string = self._get_num_string(number) self.add(*(map(self._string_to_mob, num_string))) # Add non-numerical bits if self.show_ellipsis: self.add( self._string_to_mob("\\dots", SingleStringMathTex, color=self.color), ) self.arrange( buff=self.digit_buff_per_font_unit * self._font_size, aligned_edge=DOWN, ) if self.unit is not None: self.unit_sign = self._string_to_mob(self.unit, SingleStringMathTex) self.add( self.unit_sign.next_to( self, direction=RIGHT, buff=(self.unit_buff_per_font_unit + self.digit_buff_per_font_unit) * self._font_size, aligned_edge=DOWN, ) ) self.move_to(ORIGIN) # Handle alignment of parts that should be aligned # to the bottom for i, c in enumerate(num_string): if c == "-" and len(num_string) > i + 1: self[i].align_to(self[i + 1], UP) self[i].shift(self[i + 1].height * DOWN / 2) elif c == ",": self[i].shift(self[i].height * DOWN / 2) if self.unit and self.unit.startswith("^"): self.unit_sign.align_to(self, UP) # track the initial height to enable scaling via font_size self.initial_height: float = self.height if self.include_background_rectangle: self.add_background_rectangle() def _get_num_string(self, number: float | complex) -> str: if isinstance(number, complex): formatter = self._get_complex_formatter() else: formatter = self._get_formatter() num_string = formatter.format(number) rounded_num = np.round(number, self.num_decimal_places) if num_string.startswith("-") and rounded_num == 0: num_string = "+" + num_string[1:] if self.include_sign else num_string[1:] return num_string def _string_to_mob( self, string: str, mob_class: type[SingleStringMathTex] | None = None, **kwargs: Any, ) -> VMobject: if mob_class is None: mob_class = self.mob_class if string not in string_to_mob_map: string_to_mob_map[string] = mob_class(string, **kwargs) mob = string_to_mob_map[string].copy() mob.font_size = self._font_size return mob def _get_formatter(self, **kwargs: Any) -> str: """ Configuration is based first off instance attributes, but overwritten by any kew word argument. Relevant key words: - include_sign - group_with_commas - num_decimal_places - field_name (e.g. 0 or 0.real) """ config = { attr: getattr(self, attr) for attr in [ "include_sign", "group_with_commas", "num_decimal_places", ] } config.update(kwargs) return "".join( [ "{", config.get("field_name", ""), ":", "+" if config["include_sign"] else "", "," if config["group_with_commas"] else "", ".", str(config["num_decimal_places"]), "f", "}", ], ) def _get_complex_formatter(self) -> str: return "".join( [ self._get_formatter(field_name="0.real"), self._get_formatter(field_name="0.imag", include_sign=True), "i", ], ) def set_value(self, number: float) -> Self: """Set the value of the :class:`~.DecimalNumber` to a new number. Parameters ---------- number The value that will overwrite the current number of the :class:`~.DecimalNumber`. """ # creates a new number mob via `set_submobjects_from_number` # then matches the properties (color, font_size, etc...) # of the previous mobject to the new one # old_family needed with cairo old_family = self.get_family() old_font_size = self.font_size move_to_point = self.get_edge_center(self.edge_to_fix) old_submobjects = self.submobjects self._set_submobjects_from_number(number) self.font_size = old_font_size self.move_to(move_to_point, self.edge_to_fix) for sm1, sm2 in zip(self.submobjects, old_submobjects, strict=False): sm1.match_style(sm2) if config.renderer == RendererType.CAIRO: for mob in old_family: # Dumb hack...due to how scene handles families # of animated mobjects # for compatibility with updaters to not leave first number in place while updating, # not needed with opengl renderer mob.points[:] = 0 self.init_colors() return self def get_value(self) -> float: return self.number def increment_value(self, delta_t: float = 1) -> None: self.set_value(self.get_value() + delta_t) class Integer(DecimalNumber): """A class for displaying Integers. Examples -------- .. manim:: IntegerExample :save_last_frame: class IntegerExample(Scene): def construct(self): self.add(Integer(number=2.5).set_color(ORANGE).scale(2.5).set_x(-0.5).set_y(0.8)) self.add(Integer(number=3.14159, show_ellipsis=True).set_x(3).set_y(3.3).scale(3.14159)) self.add(Integer(number=42).set_x(2.5).set_y(-2.3).set_color_by_gradient(BLUE, TEAL).scale(1.7)) self.add(Integer(number=6.28).set_x(-1.5).set_y(-2).set_color(YELLOW).scale(1.4)) """ def __init__( self, number: float = 0, num_decimal_places: int = 0, **kwargs: Any ) -> None: super().__init__(number=number, num_decimal_places=num_decimal_places, **kwargs) def get_value(self) -> int: return int(np.round(super().get_value())) class Variable(VMobject, metaclass=ConvertToOpenGL): """A class for displaying text that shows "label = value" with the value continuously updated from a :class:`~.ValueTracker`. Parameters ---------- var The initial value you need to keep track of and display. label The label for your variable. Raw strings are convertex to :class:`~.MathTex` objects. var_type The class used for displaying the number. Defaults to :class:`DecimalNumber`. num_decimal_places The number of decimal places to display in your variable. Defaults to 2. If `var_type` is an :class:`Integer`, this parameter is ignored. kwargs Other arguments to be passed to `~.Mobject`. Attributes ---------- label : Union[:class:`str`, :class:`~.Tex`, :class:`~.MathTex`, :class:`~.Text`, :class:`~.SingleStringMathTex`] The label for your variable, for example ``x = ...``. tracker : :class:`~.ValueTracker` Useful in updating the value of your variable on-screen. value : Union[:class:`DecimalNumber`, :class:`Integer`] The tex for the value of your variable. Examples -------- Normal usage:: # DecimalNumber type var = 0.5 on_screen_var = Variable(var, Text("var"), num_decimal_places=3) # Integer type int_var = 0 on_screen_int_var = Variable(int_var, Text("int_var"), var_type=Integer) # Using math mode for the label on_screen_int_var = Variable(int_var, "{a}_{i}", var_type=Integer) .. manim:: VariablesWithValueTracker class VariablesWithValueTracker(Scene): def construct(self): var = 0.5 on_screen_var = Variable(var, Text("var"), num_decimal_places=3) # You can also change the colours for the label and value on_screen_var.label.set_color(RED) on_screen_var.value.set_color(GREEN) self.play(Write(on_screen_var)) # The above line will just display the variable with # its initial value on the screen. If you also wish to # update it, you can do so by accessing the `tracker` attribute self.wait() var_tracker = on_screen_var.tracker var = 10.5 self.play(var_tracker.animate.set_value(var)) self.wait() int_var = 0 on_screen_int_var = Variable( int_var, Text("int_var"), var_type=Integer ).next_to(on_screen_var, DOWN) on_screen_int_var.label.set_color(RED) on_screen_int_var.value.set_color(GREEN) self.play(Write(on_screen_int_var)) self.wait() var_tracker = on_screen_int_var.tracker var = 10.5 self.play(var_tracker.animate.set_value(var)) self.wait() # If you wish to have a somewhat more complicated label for your # variable with subscripts, superscripts, etc. the default class # for the label is MathTex subscript_label_var = 10 on_screen_subscript_var = Variable(subscript_label_var, "{a}_{i}").next_to( on_screen_int_var, DOWN ) self.play(Write(on_screen_subscript_var)) self.wait() .. manim:: VariableExample class VariableExample(Scene): def construct(self): start = 2.0 x_var = Variable(start, 'x', num_decimal_places=3) sqr_var = Variable(start**2, 'x^2', num_decimal_places=3) Group(x_var, sqr_var).arrange(DOWN) sqr_var.add_updater(lambda v: v.tracker.set_value(x_var.tracker.get_value()**2)) self.add(x_var, sqr_var) self.play(x_var.tracker.animate.set_value(5), run_time=2, rate_func=linear) self.wait(0.1) """ def __init__( self, var: float, label: str | Tex | MathTex | Text | SingleStringMathTex, var_type: type[DecimalNumber | Integer] = DecimalNumber, num_decimal_places: int = 2, **kwargs: Any, ): self.label = MathTex(label) if isinstance(label, str) else label equals = MathTex("=").next_to(self.label, RIGHT) self.label.add(equals) self.tracker = ValueTracker(var) if var_type == DecimalNumber: self.value = DecimalNumber( self.tracker.get_value(), num_decimal_places=num_decimal_places, ) elif var_type == Integer: self.value = Integer(self.tracker.get_value()) self.value.add_updater(lambda v: v.set_value(self.tracker.get_value())).next_to( self.label, RIGHT, ) super().__init__(**kwargs) self.add(self.label, self.value) ================================================ FILE: manim/mobject/text/tex_mobject.py ================================================ r"""Mobjects representing text rendered using LaTeX. .. important:: See the corresponding tutorial :ref:`rendering-with-latex` .. note:: Just as you can use :class:`~.Text` (from the module :mod:`~.text_mobject`) to add text to your videos, you can use :class:`~.Tex` and :class:`~.MathTex` to insert LaTeX. """ from __future__ import annotations from manim.utils.color import BLACK, ParsableManimColor __all__ = [ "SingleStringMathTex", "MathTex", "Tex", "BulletedList", "Title", ] import operator as op import re from collections.abc import Iterable from functools import reduce from textwrap import dedent from typing import Any, Self from manim import config, logger from manim.constants import * from manim.mobject.geometry.line import Line from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.tex import TexTemplate from manim.utils.tex_file_writing import tex_to_svg_file from ..opengl.opengl_compatibility import ConvertToOpenGL MATHTEX_SUBSTRING = "substring" class SingleStringMathTex(SVGMobject): """Elementary building block for rendering text with LaTeX. Tests ----- Check that creating a :class:`~.SingleStringMathTex` object works:: >>> SingleStringMathTex('Test') # doctest: +SKIP SingleStringMathTex('Test') """ def __init__( self, tex_string: str, stroke_width: float = 0, should_center: bool = True, height: float | None = None, organize_left_to_right: bool = False, tex_environment: str | None = "align*", tex_template: TexTemplate | None = None, font_size: float = DEFAULT_FONT_SIZE, color: ParsableManimColor | None = None, **kwargs: Any, ): if color is None: color = VMobject().color self._font_size = font_size self.organize_left_to_right = organize_left_to_right self.tex_environment = tex_environment if tex_template is None: tex_template = config["tex_template"] self.tex_template: TexTemplate = tex_template self.tex_string = tex_string file_name = tex_to_svg_file( self._get_modified_expression(tex_string), environment=self.tex_environment, tex_template=self.tex_template, ) super().__init__( file_name=file_name, 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, }, **kwargs, ) self.init_colors() # used for scaling via font_size.setter self.initial_height = self.height if height is None: self.font_size = self._font_size if self.organize_left_to_right: self._organize_submobjects_left_to_right() def __repr__(self) -> str: return f"{type(self).__name__}({repr(self.tex_string)})" @property def font_size(self) -> float: """The font size of the tex mobject.""" return self.height / self.initial_height / SCALE_FACTOR_PER_FONT_POINT @font_size.setter def font_size(self, font_val: float) -> None: if font_val <= 0: raise ValueError("font_size must be greater than 0.") elif self.height > 0: # sometimes manim generates a SingleStringMathex mobject with 0 height. # can't be scaled regardless and will error without the elif. # scale to a factor of the initial height so that setting # font_size does not depend on current size. self.scale(font_val / self.font_size) def _get_modified_expression(self, tex_string: str) -> str: result = tex_string result = result.strip() result = self._modify_special_strings(result) return result def _modify_special_strings(self, tex: str) -> str: tex = tex.strip() should_add_filler = reduce( op.or_, [ # Fraction line needs something to be over tex == "\\over", tex == "\\overline", # Make sure sqrt has overbar tex == "\\sqrt", tex == "\\sqrt{", # Need to add blank subscript or superscript tex.endswith("_"), tex.endswith("^"), tex.endswith("dot"), ], ) if should_add_filler: filler = "{\\quad}" tex += filler if tex == "\\substack": tex = "\\quad" if tex == "": tex = "\\quad" # To keep files from starting with a line break if tex.startswith("\\\\"): tex = tex.replace("\\\\", "\\quad\\\\") # Handle imbalanced \left and \right num_lefts, num_rights = ( len([s for s in tex.split(substr)[1:] if s and s[0] in "(){}[]|.\\"]) for substr in ("\\left", "\\right") ) if num_lefts != num_rights: tex = tex.replace("\\left", "\\big") tex = tex.replace("\\right", "\\big") tex = self._remove_stray_braces(tex) for context in ["array"]: begin_in = ("\\begin{%s}" % context) in tex # noqa: UP031 end_in = ("\\end{%s}" % context) in tex # noqa: UP031 if begin_in ^ end_in: # Just turn this into a blank string, # which means caller should leave a # stray \\begin{...} with other symbols tex = "" return tex def _remove_stray_braces(self, tex: str) -> str: r""" Makes :class:`~.MathTex` resilient to unmatched braces. 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("\\\\}") while num_rights > num_lefts: tex = "{" + tex num_lefts += 1 while num_lefts > num_rights: tex = tex + "}" num_rights += 1 return tex def _organize_submobjects_left_to_right(self) -> Self: self.sort(lambda p: p[0]) return self def get_tex_string(self) -> str: return self.tex_string def init_colors(self, propagate_colors: bool = True) -> Self: 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. Examples -------- .. manim:: Formula :save_last_frame: class Formula(Scene): def construct(self): t = MathTex(r"\int_a^b f'(x) dx = f(b)- f(a)") self.add(t) Notes ----- Double-brace notation ``{{ ... }}`` can be used to split a single string argument into multiple submobjects without having to pass separate strings:: MathTex(r"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}") Each ``{{ ... }}`` group and every piece of text between groups becomes its own submobject, which is useful for :class:`~.TransformMatchingTex` animations. For ``{{`` to be recognised as a group opener it must appear either at the very start of the string or be immediately preceded by a whitespace character. ``{{`` that follows non-whitespace — such as in ``\frac{{{n}}}{k}`` or ``a^{{2}}`` — is left untouched, so ordinary nested-brace LaTeX is not accidentally split. To prevent an unintentional split, insert a space between the two braces: ``{{ ... }}`` → ``{ { ... } }``. Tests ----- Check that creating a :class:`~.MathTex` works:: >>> MathTex('a^2 + b^2 = c^2') # doctest: +SKIP MathTex('a^2 + b^2 = c^2') Check that double brace group splitting works correctly:: >>> t1 = MathTex('{{ a }} + {{ b }} = {{ c }}') # doctest: +SKIP >>> len(t1.submobjects) # doctest: +SKIP 5 >>> t2 = MathTex(r"\frac{1}{a+b\sqrt{2}}") # doctest: +SKIP >>> len(t2.submobjects) # doctest: +SKIP 1 """ def __init__( self, *tex_strings: str, arg_separator: str = " ", substrings_to_isolate: Iterable[str] | None = None, tex_to_color_map: dict[str, ParsableManimColor] | None = None, tex_environment: str | None = "align*", **kwargs: Any, ): self.tex_template = kwargs.pop("tex_template", config["tex_template"]) self.arg_separator = arg_separator self.substrings_to_isolate = ( [] if substrings_to_isolate is None else list(substrings_to_isolate) ) if tex_to_color_map is None: self.tex_to_color_map: dict[str, ParsableManimColor] = {} else: self.tex_to_color_map = tex_to_color_map self.substrings_to_isolate.extend(self.tex_to_color_map.keys()) self.tex_environment = tex_environment self.brace_notation_split_occurred = False self.tex_strings = self._prepare_tex_strings(tex_strings) self.matched_strings_and_ids: list[tuple[str, str]] = [] try: joined_string = self._join_tex_strings_with_unique_deliminters( self.tex_strings, self.substrings_to_isolate ) super().__init__( joined_string, tex_environment=self.tex_environment, tex_template=self.tex_template, **kwargs, ) # Save the original tex_string self.tex_string = self.arg_separator.join(self.tex_strings) self._break_up_by_substrings() except ValueError as compilation_error: if self.brace_notation_split_occurred: logger.error( dedent( """\ A group of double braces, {{ ... }}, was detected in your string. Manim splits TeX strings at the double braces, which might have caused the current compilation error. If you didn't use the double brace split intentionally, add spaces between the braces to avoid the automatic splitting: {{ ... }} --> { { ... } }. """, ), ) raise compilation_error self.set_color_by_tex_to_color_map(self.tex_to_color_map) if self.organize_left_to_right: self._organize_submobjects_left_to_right() def _prepare_tex_strings(self, tex_strings: Iterable[str]) -> list[str]: # Deal with the case where tex_strings contains integers instead # of strings. tex_strings_validated = [ string if isinstance(string, str) else str(string) for string in tex_strings ] # Locate double curly bracers and split on them. tex_strings_validated_two = [] for tex_string in tex_strings_validated: split = self._split_double_braces(tex_string) tex_strings_validated_two.extend(split) if len(tex_strings_validated_two) > len(tex_strings_validated): self.brace_notation_split_occurred = True return [string for string in tex_strings_validated_two if len(string) > 0] @staticmethod def _split_double_braces(tex_string: str) -> list[str]: r"""Split *tex_string* on Manim's ``{{ ... }}`` double-brace notation. Rules that avoid false positives on ordinary LaTeX source: * ``{{`` is only treated as a group opener when it appears at the very start of the string or is immediately preceded by a whitespace character. Naturally-occurring ``{{`` in LaTeX is usually preceded by non-whitespace (e.g. ``\frac{{{n}}}{k}`` or ``a^{{2}}``), so the whitespace guard eliminates the most common false positives without any brace-depth bookkeeping on the outer string. * Inside an open group the depth of *real* LaTeX braces is tracked. ``}}`` only closes the Manim group when the inner depth is zero, so ``{{ a^{b^{c}} }}`` is handled correctly. * Escape sequences are consumed as two-character units in priority order: ``\\`` first (escaped backslash), then ``\{`` / ``\}`` (escaped braces). This ensures e.g. ``\\}}`` is read as an escaped backslash followed by a real ``}}`` rather than as ``\`` + ``\}`` + lone ``}``. """ segments: list[str] = [] current = "" i = 0 inside_manim = False inner_depth = 0 while i < len(tex_string): # --- consume escape sequences as atomic units --- if tex_string[i] == "\\" and i + 1 < len(tex_string): next_ch = tex_string[i + 1] if next_ch == "\\" or next_ch in "{}": # \\ (escaped backslash) checked before \{ / \} so that # the second \ in \\ is never mistaken for an escape prefix. current += tex_string[i : i + 2] i += 2 continue if not inside_manim: # {{ opens a Manim group only at start-of-string or after whitespace. if tex_string[i : i + 2] == "{{" and ( i == 0 or tex_string[i - 1].isspace() ): segments.append(current) current = "" inside_manim = True inner_depth = 0 i += 2 else: current += tex_string[i] i += 1 else: if tex_string[i] == "{": inner_depth += 1 current += tex_string[i] i += 1 elif ( tex_string[i] == "}" and inner_depth == 0 and tex_string[i : i + 2] == "}}" ): # }} at inner depth 0 closes the Manim group. segments.append(current) current = "" inside_manim = False i += 2 elif tex_string[i] == "}": inner_depth -= 1 current += tex_string[i] i += 1 else: current += tex_string[i] i += 1 segments.append(current) return segments def _join_tex_strings_with_unique_deliminters( self, tex_strings: list[str], substrings_to_isolate: Iterable[str] ) -> str: joined_string = "" ssIdx = 0 for idx, tex_string in enumerate(tex_strings): string_part = rf"\special{{dvisvgm:raw }}" self.matched_strings_and_ids.append((tex_string, f"unique{idx:03d}")) # Try to match with all substrings_to_isolate and apply the first match # then match again (on the rest of the string) and continue until no # characters are left in the string unprocessed_string = str(tex_string) processed_string = "" while len(unprocessed_string) > 0: first_match = self._locate_first_match( substrings_to_isolate, unprocessed_string ) if first_match: processed, unprocessed_string = self._handle_match( ssIdx, first_match ) processed_string = processed_string + processed ssIdx += 1 else: processed_string = processed_string + unprocessed_string unprocessed_string = "" string_part += processed_string if idx < len(tex_strings) - 1: string_part += self.arg_separator string_part += r"\special{dvisvgm:raw }" joined_string = joined_string + string_part return joined_string def _locate_first_match( self, substrings_to_isolate: Iterable[str], unprocessed_string: str ) -> re.Match | None: first_match_start = len(unprocessed_string) first_match_length = 0 first_match = None for substring in substrings_to_isolate: match = re.match(f"(.*?)({re.escape(substring)})(.*)", unprocessed_string) if match and len(match.group(1)) < first_match_start: first_match = match first_match_start = len(match.group(1)) first_match_length = len(match.group(2)) elif match and len(match.group(1)) == first_match_start: # Break ties by looking at length of matches. if first_match_length < len(match.group(2)): first_match = match first_match_start = len(match.group(1)) first_match_length = len(match.group(2)) return first_match def _handle_match(self, ssIdx: int, first_match: re.Match) -> tuple[str, str]: pre_match = first_match.group(1) matched_string = first_match.group(2) post_match = first_match.group(3) pre_string = ( rf"\special{{dvisvgm:raw }}" ) post_string = r"\special{dvisvgm:raw }" self.matched_strings_and_ids.append( (matched_string, f"unique{ssIdx:03d}{MATHTEX_SUBSTRING}") ) processed_string = pre_match + pre_string + matched_string + post_string unprocessed_string = post_match return processed_string, unprocessed_string @property def _substring_matches(self) -> list[tuple[str, str]]: """Return only the 'ss' (substring_to_isolate) matches.""" return [ (tex, id_) for tex, id_ in self.matched_strings_and_ids if id_.endswith(MATHTEX_SUBSTRING) ] @property def _main_matches(self) -> list[tuple[str, str]]: """Return only the main tex_string matches.""" return [ (tex, id_) for tex, id_ in self.matched_strings_and_ids if not id_.endswith(MATHTEX_SUBSTRING) ] def _break_up_by_substrings(self) -> Self: """ Reorganize existing submobjects one layer deeper based on the structure of tex_strings (as a list of tex_strings) """ new_submobjects: list[VMobject] = [] try: for tex_string, tex_string_id in self._main_matches: mtp = MathTexPart() mtp.tex_string = tex_string mtp.add(*self.id_to_vgroup_dict[tex_string_id].submobjects) new_submobjects.append(mtp) except KeyError: logger.error( f"MathTex: Could not find SVG group for tex part '{tex_string}' (id: {tex_string_id}). Using fallback to root group." ) new_submobjects.append(self.id_to_vgroup_dict["root"]) self.submobjects = new_submobjects return self def get_part_by_tex(self, tex: str, **kwargs: Any) -> VGroup | None: for tex_str, match_id in self.matched_strings_and_ids: if tex_str == tex: return self.id_to_vgroup_dict[match_id] return None def set_color_by_tex( self, tex: str, color: ParsableManimColor, **kwargs: Any ) -> Self: for tex_str, match_id in self.matched_strings_and_ids: if tex_str == tex: self.id_to_vgroup_dict[match_id].set_color(color) return self def set_opacity_by_tex( self, tex: str, opacity: float = 0.5, remaining_opacity: float | None = None, **kwargs: Any, ) -> Self: """ Sets the opacity of the tex specified. If 'remaining_opacity' is specified, then the remaining tex will be set to that opacity. Parameters ---------- tex The tex to set the opacity of. opacity Default 0.5. The opacity to set the tex to remaining_opacity Default None. The opacity to set the remaining tex to. If None, then the remaining tex will not be changed """ if remaining_opacity is not None: self.set_opacity(opacity=remaining_opacity) for tex_str, match_id in self.matched_strings_and_ids: if tex_str == tex: self.id_to_vgroup_dict[match_id].set_opacity(opacity) return self def set_color_by_tex_to_color_map( self, texs_to_color_map: dict[str, ParsableManimColor], **kwargs: Any ) -> Self: for texs, color in list(texs_to_color_map.items()): for match in self.matched_strings_and_ids: if match[0] == texs: self.id_to_vgroup_dict[match[1]].set_color(color) return self def index_of_part(self, part: VMobject) -> int: split_self = self.split() if part not in split_self: raise ValueError("Trying to get index of part not in MathTex") return split_self.index(part) def sort_alphabetically(self) -> None: self.submobjects.sort(key=lambda m: m.get_tex_string()) class MathTexPart(VMobject, metaclass=ConvertToOpenGL): tex_string: str def __repr__(self) -> str: return f"{type(self).__name__}({repr(self.tex_string)})" 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 ----- Check whether writing a LaTeX string works:: >>> Tex('The horse does not eat cucumber salad.') # doctest: +SKIP Tex('The horse does not eat cucumber salad.') """ def __init__( self, *tex_strings: str, arg_separator: str = "", tex_environment: str | None = "center", **kwargs: Any, ): super().__init__( *tex_strings, arg_separator=arg_separator, tex_environment=tex_environment, **kwargs, ) class BulletedList(Tex): """A bulleted list. Examples -------- .. manim:: BulletedListExample :save_last_frame: class BulletedListExample(Scene): def construct(self): blist = BulletedList("Item 1", "Item 2", "Item 3", height=2, width=2) blist.set_color_by_tex("Item 1", RED) blist.set_color_by_tex("Item 2", GREEN) blist.set_color_by_tex("Item 3", BLUE) self.add(blist) """ def __init__( self, *items: str, buff: float = MED_LARGE_BUFF, dot_scale_factor: float = 2, tex_environment: str | None = None, **kwargs: Any, ): self.buff = buff self.dot_scale_factor = dot_scale_factor self.tex_environment = tex_environment line_separated_items = [s + "\\\\" for s in items] super().__init__( *line_separated_items, tex_environment=tex_environment, **kwargs, ) for part in self: dot = MathTex("\\cdot").scale(self.dot_scale_factor) dot.next_to(part[0], LEFT, SMALL_BUFF) part.add_to_back(dot) self.arrange(DOWN, aligned_edge=LEFT, buff=self.buff) def fade_all_but(self, index_or_string: int | str, opacity: float = 0.5) -> None: arg = index_or_string if isinstance(arg, str): part: VGroup | VMobject | None = self.get_part_by_tex(arg) if part is None: raise Exception( f"Could not locate part by provided tex string '{arg}'." ) elif isinstance(arg, int): part = self.submobjects[arg] else: raise TypeError(f"Expected int or string, got {arg}") for other_part in self.submobjects: if other_part is part: other_part.set_fill(opacity=1) else: other_part.set_fill(opacity=opacity) class Title(Tex): """A mobject representing an underlined title. Examples -------- .. manim:: TitleExample :save_last_frame: import manim class TitleExample(Scene): def construct(self): banner = ManimBanner() title = Title(f"Manim version {manim.__version__}") self.add(banner, title) """ def __init__( self, *text_parts: str, include_underline: bool = True, match_underline_width_to_text: bool = False, underline_buff: float = MED_SMALL_BUFF, **kwargs: Any, ): self.include_underline = include_underline self.match_underline_width_to_text = match_underline_width_to_text self.underline_buff = underline_buff super().__init__(*text_parts, **kwargs) self.to_edge(UP) if self.include_underline: underline_width = config["frame_width"] - 2 underline = Line(LEFT, RIGHT) underline.next_to(self, DOWN, buff=self.underline_buff) if self.match_underline_width_to_text: underline.match_width(self) else: underline.width = underline_width self.add(underline) self.underline = underline ================================================ FILE: manim/mobject/text/text_mobject.py ================================================ """Mobjects used for displaying (non-LaTeX) text. .. note:: Just as you can use :class:`~.Tex` and :class:`~.MathTex` (from the module :mod:`~.tex_mobject`) to insert LaTeX to your videos, you can use :class:`~.Text` to to add normal text. .. important:: See the corresponding tutorial :ref:`using-text-objects`, especially for information about fonts. The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the Pango library to render text. With Pango, you are also able to render non-English alphabets like `你好` or `こんにちは` or `안녕하세요` or `مرحبا بالعالم`. Examples -------- .. manim:: HelloWorld :save_last_frame: class HelloWorld(Scene): def construct(self): text = Text('Hello world').scale(3) self.add(text) .. manim:: TextAlignment :save_last_frame: class TextAlignment(Scene): def construct(self): title = Text("K-means clustering and Logistic Regression", color=WHITE) title.scale(0.75) self.add(title.to_edge(UP)) t1 = Text("1. Measuring").set_color(WHITE) t2 = Text("2. Clustering").set_color(WHITE) t3 = Text("3. Regression").set_color(WHITE) t4 = Text("4. Prediction").set_color(WHITE) x = VGroup(t1, t2, t3, t4).arrange(direction=DOWN, aligned_edge=LEFT).scale(0.7).next_to(ORIGIN,DR) x.set_opacity(0.5) x.submobjects[1].set_opacity(1) self.add(x) """ from __future__ import annotations import functools __all__ = ["Text", "Paragraph", "MarkupText", "register_font"] import copy import hashlib import re from collections.abc import Iterable, Iterator, Sequence from contextlib import contextmanager from itertools import chain from pathlib import Path from typing import TYPE_CHECKING, Any import manimpango import numpy as np from manimpango import MarkupUtils, PangoUtils, TextSetting from manim import config, logger from manim.constants import * from manim.mobject.geometry.arc import Dot from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.typing import Point3D from manim.utils.color import ManimColor, ParsableManimColor, color_gradient if TYPE_CHECKING: from typing import Self from manim.typing import Point3D TEXT_MOB_SCALE_FACTOR = 0.05 DEFAULT_LINE_SPACING_SCALE = 0.3 TEXT2SVG_ADJUSTMENT_FACTOR = 4.8 __all__ = ["Text", "Paragraph", "MarkupText", "register_font"] def remove_invisible_chars(mobject: VMobject) -> VMobject: """Function to remove unwanted invisible characters from some mobjects. Parameters ---------- mobject Any SVGMobject from which we want to remove unwanted invisible characters. Returns ------- :class:`~.SVGMobject` The SVGMobject without unwanted invisible characters. """ mobject_without_dots = VGroup() if isinstance(mobject[0], VGroup): for submob in mobject: mobject_without_dots.add( VGroup(k for k in submob if not isinstance(k, Dot)) ) else: mobject_without_dots.add(*(k for k in mobject if not isinstance(k, Dot))) return mobject_without_dots class Paragraph(VGroup): r"""Display a paragraph of text. For a given :class:`.Paragraph` ``par``, the attribute ``par.chars`` is a :class:`.VGroup` containing all the lines. In this context, every line is constructed as a :class:`.VGroup` of characters contained in the line. Parameters ---------- line_spacing Represents the spacing between lines. Defaults to -1, which means auto. alignment Defines the alignment of paragraph. Defaults to None. Possible values are "left", "right" or "center". Examples -------- Normal usage:: paragraph = Paragraph( "this is a awesome", "paragraph", "With \nNewlines", "\tWith Tabs", " With Spaces", "With Alignments", "center", "left", "right", ) Remove unwanted invisible characters:: self.play(Transform(remove_invisible_chars(paragraph.chars[0:2]), remove_invisible_chars(paragraph.chars[3][0:3])) """ def __init__( self, *text: str, line_spacing: float = -1, alignment: str | None = None, **kwargs: Any, ): self.line_spacing = line_spacing self.alignment = alignment self.consider_spaces_as_chars = kwargs.get("disable_ligatures", False) super().__init__() lines_str = "\n".join(list(text)) self.lines_text = Text(lines_str, line_spacing=line_spacing, **kwargs) lines_str_list = lines_str.split("\n") self.chars = self._gen_chars(lines_str_list) # TODO: If possible get rid of self.lines_chars, as it seems to be a # listified duplicate of self.chars. self.lines_chars = list(self.chars) self.lines_alignments = [self.alignment] * len(self.chars) self.lines_initial_positions = [line.get_center() for line in self.lines_chars] self.add(*self.lines_chars) self.move_to(np.array([0, 0, 0])) if self.alignment: self._set_all_lines_alignments(self.alignment) def _gen_chars(self, lines_str_list: list) -> VGroup: """Function to convert a list of plain strings to a VGroup of VGroups of chars. Parameters ---------- lines_str_list List of plain text strings. Returns ------- :class:`~.VGroup` The generated 2d-VGroup of chars. """ char_index_counter = 0 chars = self.get_group_class()() for line_no in range(len(lines_str_list)): line_str = lines_str_list[line_no] # Count all the characters in line_str # Spaces may or may not count as characters if self.consider_spaces_as_chars: char_count = len(line_str) else: char_count = 0 for char in line_str: if not char.isspace(): char_count += 1 chars.add(self.get_group_class()()) chars[line_no].add( *self.lines_text.chars[ char_index_counter : char_index_counter + char_count ] ) char_index_counter += char_count if self.consider_spaces_as_chars: # If spaces count as characters, count the extra \n character # which separates Paragraph's lines to avoid issues char_index_counter += 1 return chars def _set_all_lines_alignments(self, alignment: str) -> Paragraph: """Function to set all line's alignment to a specific value. Parameters ---------- alignment Defines the alignment of paragraph. Possible values are "left", "right", "center". """ for line_no in range(len(self.lines_chars)): self._change_alignment_for_a_line(alignment, line_no) return self def _set_line_alignment(self, alignment: str, line_no: int) -> Paragraph: """Function to set one line's alignment to a specific value. Parameters ---------- alignment Defines the alignment of paragraph. Possible values are "left", "right", "center". line_no Defines the line number for which we want to set given alignment. """ self._change_alignment_for_a_line(alignment, line_no) return self def _set_all_lines_to_initial_positions(self) -> Paragraph: """Set all lines to their initial positions.""" self.lines_alignments = [None] * len(self.lines_chars) for line_no in range(len(self.lines_chars)): self[line_no].move_to( self.get_center() + self.lines_initial_positions[line_no], ) return self def _set_line_to_initial_position(self, line_no: int) -> Paragraph: """Function to set one line to initial positions. Parameters ---------- line_no Defines the line number for which we want to set given alignment. """ self.lines_alignments[line_no] = None self[line_no].move_to(self.get_center() + self.lines_initial_positions[line_no]) return self def _change_alignment_for_a_line(self, alignment: str, line_no: int) -> None: """Function to change one line's alignment to a specific value. Parameters ---------- alignment Defines the alignment of paragraph. Possible values are "left", "right", "center". line_no Defines the line number for which we want to set given alignment. """ self.lines_alignments[line_no] = alignment if self.lines_alignments[line_no] == "center": self[line_no].move_to( np.array([self.get_center()[0], self[line_no].get_center()[1], 0]), ) elif self.lines_alignments[line_no] == "right": self[line_no].move_to( np.array( [ self.get_right()[0] - self[line_no].width / 2, self[line_no].get_center()[1], 0, ], ), ) elif self.lines_alignments[line_no] == "left": self[line_no].move_to( np.array( [ self.get_left()[0] + self[line_no].width / 2, self[line_no].get_center()[1], 0, ], ), ) class Text(SVGMobject): r"""Display (non-LaTeX) text rendered using `Pango `_. Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible. Parameters ---------- text The text that needs to be created as a mobject. font The font family to be used to render the text. This is either a system font or one loaded with `register_font()`. Note that font family names may be different across operating systems. warn_missing_font If True (default), Manim will issue a warning if the font does not exist in the (case-sensitive) list of fonts returned from `manimpango.list_fonts()`. Returns ------- :class:`Text` The mobject-like :class:`.VGroup`. Examples --------- .. manim:: Example1Text :save_last_frame: class Example1Text(Scene): def construct(self): text = Text('Hello world').scale(3) self.add(text) .. manim:: TextColorExample :save_last_frame: class TextColorExample(Scene): def construct(self): text1 = Text('Hello world', color=BLUE).scale(3) text2 = Text('Hello world', gradient=(BLUE, GREEN)).scale(3).next_to(text1, DOWN) self.add(text1, text2) .. manim:: TextItalicAndBoldExample :save_last_frame: class TextItalicAndBoldExample(Scene): def construct(self): text1 = Text("Hello world", slant=ITALIC) text2 = Text("Hello world", t2s={'world':ITALIC}) text3 = Text("Hello world", weight=BOLD) text4 = Text("Hello world", t2w={'world':BOLD}) text5 = Text("Hello world", t2c={'o':YELLOW}, disable_ligatures=True) text6 = Text( "Visit us at docs.manim.community", t2c={"docs.manim.community": YELLOW}, disable_ligatures=True, ) text6.scale(1.3).shift(DOWN) self.add(text1, text2, text3, text4, text5 , text6) Group(*self.mobjects).arrange(DOWN, buff=.8).set(height=config.frame_height-LARGE_BUFF) .. manim:: TextMoreCustomization :save_last_frame: class TextMoreCustomization(Scene): def construct(self): text1 = Text( 'Google', t2c={'[:1]': '#3174f0', '[1:2]': '#e53125', '[2:3]': '#fbb003', '[3:4]': '#3174f0', '[4:5]': '#269a43', '[5:]': '#e53125'}, font_size=58).scale(3) self.add(text1) As :class:`Text` uses Pango to render text, rendering non-English characters is easily possible: .. manim:: MultipleFonts :save_last_frame: class MultipleFonts(Scene): def construct(self): morning = Text("வணக்கம்", font="sans-serif") japanese = Text( "日本へようこそ", t2c={"日本": BLUE} ) # works same as ``Text``. mess = Text("Multi-Language", weight=BOLD) russ = Text("Здравствуйте मस नम म ", font="sans-serif") hin = Text("नमस्ते", font="sans-serif") arb = Text( "صباح الخير \n تشرفت بمقابلتك", font="sans-serif" ) # don't mix RTL and LTR languages nothing shows up then ;-) chinese = Text("臂猿「黛比」帶著孩子", font="sans-serif") self.add(morning, japanese, mess, russ, hin, arb, chinese) for i,mobj in enumerate(self.mobjects): mobj.shift(DOWN*(i-3)) .. manim:: PangoRender :quality: low class PangoRender(Scene): def construct(self): morning = Text("வணக்கம்", font="sans-serif") self.play(Write(morning)) self.wait(2) Tests ----- Check that the creation of :class:`~.Text` works:: >>> Text('The horse does not eat cucumber salad.') Text('The horse does not eat cucumber salad.') """ @staticmethod @functools.cache def font_list() -> list[str]: value: list[str] = manimpango.list_fonts() return value def __init__( self, text: str, fill_opacity: float = 1.0, stroke_width: float = 0, color: ParsableManimColor | None = None, font_size: float = DEFAULT_FONT_SIZE, line_spacing: float = -1, font: str = "", slant: str = NORMAL, weight: str = NORMAL, t2c: dict[str, str] | None = None, t2f: dict[str, str] | None = None, t2g: dict[str, Iterable[ParsableManimColor]] | None = None, t2s: dict[str, str] | None = None, t2w: dict[str, str] | None = None, gradient: Iterable[ParsableManimColor] | None = None, tab_width: int = 4, warn_missing_font: bool = True, # Mobject height: float | None = None, width: float | None = None, should_center: bool = True, disable_ligatures: bool = False, use_svg_cache: bool = False, **kwargs: Any, ): self.line_spacing = line_spacing if font and warn_missing_font: fonts_list = Text.font_list() # handle special case of sans/sans-serif if font.lower() == "sans-serif": font = "sans" if font not in fonts_list: # check if the capitalized version is in the supported fonts if font.capitalize() in fonts_list: font = font.capitalize() elif font.lower() in fonts_list: font = font.lower() elif font.title() in fonts_list: font = font.title() else: logger.warning(f"Font {font} not in {fonts_list}.") self.font = font self._font_size = float(font_size) # needs to be a float or else size is inflated when font_size = 24 # (unknown cause) self.slant = slant self.weight = weight self.gradient = gradient self.tab_width = tab_width if t2c is None: t2c = {} if t2f is None: t2f = {} if t2g is None: t2g = {} if t2s is None: t2s = {} if t2w is None: t2w = {} # If long form arguments are present, they take precedence t2c = kwargs.pop("text2color", t2c) t2f = kwargs.pop("text2font", t2f) t2g = kwargs.pop("text2gradient", t2g) t2s = kwargs.pop("text2slant", t2s) t2w = kwargs.pop("text2weight", t2w) assert t2c is not None assert t2f is not None assert t2g is not None assert t2s is not None assert t2w is not None self.t2c: dict[str, str] = {k: ManimColor(v).to_hex() for k, v in t2c.items()} self.t2f: dict[str, str] = t2f self.t2g: dict[str, Iterable[ParsableManimColor]] = t2g self.t2s: dict[str, str] = t2s self.t2w: dict[str, str] = t2w self.original_text = text self.disable_ligatures = disable_ligatures text_without_tabs = text if text.find("\t") != -1: text_without_tabs = text.replace("\t", " " * self.tab_width) self.text = text_without_tabs if self.line_spacing == -1: self.line_spacing = ( self._font_size + self._font_size * DEFAULT_LINE_SPACING_SCALE ) else: self.line_spacing = self._font_size + self._font_size * self.line_spacing parsed_color: ManimColor = ManimColor(color) if color else VMobject().color file_name = self._text2svg(parsed_color.to_hex()) PangoUtils.remove_last_M(file_name) super().__init__( file_name, fill_opacity=fill_opacity, stroke_width=stroke_width, height=height, width=width, should_center=should_center, use_svg_cache=use_svg_cache, **kwargs, ) self.text = text if self.disable_ligatures: self.submobjects = [*self._gen_chars()] self.chars = self.get_group_class()(*self.submobjects) self.text = text_without_tabs.replace(" ", "").replace("\n", "") nppc = self.n_points_per_curve for each in self: if len(each.points) == 0: continue points = each.points curve_start = points[0] assert len(curve_start) == self.dim, curve_start # Some of the glyphs in this text might not be closed, # so we close them by identifying when one curve ends # but it is not where the next curve starts. # It is more efficient to temporarily create a list # of points and add them one at a time, then turn them # into a numpy array at the end, rather than creating # new numpy arrays every time a point or fixing line # is added (which is O(n^2) for numpy arrays). closed_curve_points: list[Point3D] = [] # OpenGL has points be part of quadratic Bezier curves; # Cairo uses cubic Bezier curves. if nppc == 3: # RendererType.OPENGL def add_line_to(end: Point3D) -> None: nonlocal closed_curve_points start = closed_curve_points[-1] closed_curve_points += [ start, (start + end) / 2, end, ] else: # RendererType.CAIRO def add_line_to(end: Point3D) -> None: nonlocal closed_curve_points start = closed_curve_points[-1] closed_curve_points += [ start, (start + start + end) / 3, (start + end + end) / 3, end, ] for index, point in enumerate(points): closed_curve_points.append(point) if ( index != len(points) - 1 and (index + 1) % nppc == 0 and any(point != points[index + 1]) ): # Add straight line from last point on this curve to the # start point on the next curve. We represent the line # as a cubic bezier curve where the two control points # are half-way between the start and stop point. add_line_to(curve_start) curve_start = points[index + 1] # Make sure last curve is closed add_line_to(curve_start) each.points = np.array(closed_curve_points, ndmin=2) # anti-aliasing if height is None and width is None: self.scale(TEXT_MOB_SCALE_FACTOR) self.initial_height = self.height def __repr__(self) -> str: return f"Text({repr(self.original_text)})" @property def font_size(self) -> float: return ( self.height / self.initial_height / TEXT_MOB_SCALE_FACTOR * 2.4 * self._font_size / DEFAULT_FONT_SIZE ) @font_size.setter def font_size(self, font_val: float) -> None: # TODO: use pango's font size scaling. if font_val <= 0: raise ValueError("font_size must be greater than 0.") else: self.scale(font_val / self.font_size) def _gen_chars(self) -> VGroup: chars = self.get_group_class()() submobjects_char_index = 0 for char_index in range(len(self.text)): if self.text[char_index].isspace(): space = Dot(radius=0, fill_opacity=0, stroke_opacity=0) if char_index == 0: space.move_to(self.submobjects[submobjects_char_index].get_center()) else: space.move_to( self.submobjects[submobjects_char_index - 1].get_center(), ) chars.add(space) else: chars.add(self.submobjects[submobjects_char_index]) submobjects_char_index += 1 return chars def _find_indexes(self, word: str, text: str) -> list[tuple[int, int]]: """Finds the indexes of ``text`` in ``word``.""" temp = re.match(r"\[([0-9\-]{0,}):([0-9\-]{0,})\]", word) if temp: start = int(temp.group(1)) if temp.group(1) != "" else 0 end = int(temp.group(2)) if temp.group(2) != "" else len(text) start = len(text) + start if start < 0 else start end = len(text) + end if end < 0 else end return [ (start, end), ] indexes = [] index = text.find(word) while index != -1: indexes.append((index, index + len(word))) index = text.find(word, index + len(word)) return indexes def _text2hash(self, color: ParsableManimColor) -> str: """Generates ``sha256`` hash for file name.""" settings = ( "PANGO" + self.font + self.slant + self.weight + str(color) ) # to differentiate Text and CairoText settings += str(self.t2f) + str(self.t2s) + str(self.t2w) + str(self.t2c) settings += str(self.line_spacing) + str(self._font_size) settings += str(self.disable_ligatures) settings += str(self.gradient) id_str = self.text + settings hasher = hashlib.sha256() hasher.update(id_str.encode()) return hasher.hexdigest()[:16] def _merge_settings( self, left_setting: TextSetting, right_setting: TextSetting, default_args: dict[str, Iterable[str]], ) -> TextSetting: contained = right_setting.end < left_setting.end new_setting = copy.copy(left_setting) if contained else copy.copy(right_setting) new_setting.start = right_setting.end if contained else left_setting.end left_setting.end = right_setting.start if not contained: right_setting.end = new_setting.start for arg in default_args: left = getattr(left_setting, arg) right = getattr(right_setting, arg) default = default_args[arg] if left != default and getattr(right_setting, arg) != default: raise ValueError( f"Ambiguous style for text '{self.text[right_setting.start : right_setting.end]}':" + f"'{arg}' cannot be both '{left}' and '{right}'." ) setattr(right_setting, arg, left if left != default else right) return new_setting def _get_settings_from_t2xs( self, t2xs: Sequence[tuple[dict[str, str], str]], default_args: dict[str, Iterable[str]], ) -> list[TextSetting]: settings = [] t2xwords = set(chain(*([*t2x.keys()] for t2x, _ in t2xs))) for word in t2xwords: setting_args = { arg: str(t2x[word]) if word in t2x else default_args[arg] # NOTE: when t2x[word] is a ManimColor, str will yield the # hex representation for t2x, arg in t2xs } for start, end in self._find_indexes(word, self.text): settings.append(TextSetting(start, end, **setting_args)) return settings def _get_settings_from_gradient( self, default_args: dict[str, Any] ) -> list[TextSetting]: settings = [] args = copy.copy(default_args) if self.gradient: colors: list[ManimColor] = color_gradient(self.gradient, len(self.text)) for i in range(len(self.text)): args["color"] = colors[i].to_hex() settings.append(TextSetting(i, i + 1, **args)) for word, gradient in self.t2g.items(): colors = color_gradient(gradient, len(word)) for start, end in self._find_indexes(word, self.text): for i in range(start, end): args["color"] = colors[i - start].to_hex() settings.append(TextSetting(i, i + 1, **args)) return settings def _text2settings(self, color: ParsableManimColor) -> list[TextSetting]: """Converts the texts and styles to a setting for parsing.""" t2xs: list[tuple[dict[str, str], str]] = [ (self.t2f, "font"), (self.t2s, "slant"), (self.t2w, "weight"), (self.t2c, "color"), ] # setting_args requires values to be strings default_args: dict[str, Any] = { arg: getattr(self, arg) if arg != "color" else color for _, arg in t2xs } settings = self._get_settings_from_t2xs(t2xs, default_args) settings.extend(self._get_settings_from_gradient(default_args)) # Handle overlaps settings.sort(key=lambda setting: setting.start) for index, setting in enumerate(settings): if index + 1 == len(settings): break next_setting = settings[index + 1] if setting.end > next_setting.start: new_setting = self._merge_settings(setting, next_setting, default_args) new_index = index + 1 while ( new_index < len(settings) and settings[new_index].start < new_setting.start ): new_index += 1 settings.insert(new_index, new_setting) # Set all text settings (default font, slant, weight) temp_settings = settings.copy() start = 0 for setting in settings: if setting.start != start: temp_settings.append(TextSetting(start, setting.start, **default_args)) start = setting.end if start != len(self.text): temp_settings.append(TextSetting(start, len(self.text), **default_args)) settings = sorted(temp_settings, key=lambda setting: setting.start) line_num = 0 if re.search(r"\n", self.text): for for_start, for_end in self._find_indexes("\n", self.text): for setting in settings: if setting.line_num == -1: setting.line_num = line_num if for_start < setting.end: line_num += 1 new_setting = copy.copy(setting) setting.end = for_end new_setting.start = for_end new_setting.line_num = line_num settings.append(new_setting) settings.sort(key=lambda setting: setting.start) break for setting in settings: if setting.line_num == -1: setting.line_num = line_num return settings def _text2svg(self, color: ParsableManimColor) -> str: """Convert the text to SVG using Pango.""" size = self._font_size line_spacing = self.line_spacing size /= TEXT2SVG_ADJUSTMENT_FACTOR line_spacing /= TEXT2SVG_ADJUSTMENT_FACTOR dir_name = config.get_dir("text_dir") dir_name.mkdir(parents=True, exist_ok=True) hash_name = self._text2hash(color) file_name = dir_name / (hash_name + ".svg") if file_name.exists(): svg_file = str(file_name.resolve()) else: settings = self._text2settings(color) width = config["pixel_width"] height = config["pixel_height"] svg_file = manimpango.text2svg( settings, size, line_spacing, self.disable_ligatures, str(file_name.resolve()), START_X, START_Y, width, height, self.text, ) return svg_file def init_colors(self, propagate_colors: bool = True) -> Self: if config.renderer == RendererType.OPENGL: super().init_colors() elif config.renderer == RendererType.CAIRO: super().init_colors(propagate_colors=propagate_colors) return self class MarkupText(SVGMobject): r"""Display (non-LaTeX) text rendered using `Pango `_. Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible. **What is PangoMarkup?** PangoMarkup is a small markup language like html and it helps you avoid using "range of characters" while coloring or styling a piece a Text. You can use this language with :class:`~.MarkupText`. A simple example of a marked-up string might be:: Blue text is cool!" and it can be used with :class:`~.MarkupText` as .. manim:: MarkupExample :save_last_frame: class MarkupExample(Scene): def construct(self): text = MarkupText('Blue text is cool!"') self.add(text) A more elaborate example would be: .. manim:: MarkupElaborateExample :save_last_frame: class MarkupElaborateExample(Scene): def construct(self): text = MarkupText( 'اَ' 'لْعَر' 'َبِي' 'َّة' 'ُ' ) self.add(text) PangoMarkup can also contain XML features such as numeric character entities such as ``©`` for © can be used too. The most general markup tag is ````, then there are some convenience tags. Here is a list of supported tags: - ``bold``, ``italic`` and ``bold+italic`` - ``underline`` and ``strike through`` - ``typewriter font`` - ``bigger font`` and ``smaller font`` - ``superscript`` and ``subscript`` - ``double underline`` - ``error underline`` - ``overline`` - ``strikethrough`` - ``temporary change of font`` - ``temporary change of color`` - ``temporary change of color`` - ``temporary gradient`` For ```` markup, colors can be specified either as hex triples like ``#aabbcc`` or as named CSS colors like ``AliceBlue``. The ```` tag is handled by Manim rather than Pango, and supports hex triplets or Manim constants like ``RED`` or ``RED_A``. If you want to use Manim constants like ``RED_A`` together with ````, you will need to use Python's f-String syntax as follows:: MarkupText(f'here you go') If your text contains ligatures, the :class:`MarkupText` class may incorrectly determine the first and last letter when creating the gradient. This is due to the fact that ``fl`` are two separate characters, but might be set as one single glyph - a ligature. If your language does not depend on ligatures, consider setting ``disable_ligatures`` to ``True``. If you must use ligatures, the ``gradient`` tag supports an optional attribute ``offset`` which can be used to compensate for that error. For example: - ``example`` to *start* the gradient one letter earlier - ``example`` to *end* the gradient one letter earlier - ``example`` to *start* the gradient two letters earlier and *end* it one letter earlier Specifying a second offset may be necessary if the text to be colored does itself contain ligatures. The same can happen when using HTML entities for special chars. When using ``underline``, ``overline`` or ``strikethrough`` together with ```` tags, you will also need to use the offset, because underlines are additional paths in the final :class:`SVGMobject`. Check out the following example. Escaping of special characters: ``>`` **should** be written as ``>`` whereas ``<`` and ``&`` *must* be written as ``<`` and ``&``. You can find more information about Pango markup formatting at the corresponding documentation page: `Pango Markup `_. Please be aware that not all features are supported by this class and that the ```` tag mentioned above is not supported by Pango. Parameters ---------- text The text that needs to be created as mobject. fill_opacity The fill opacity, with 1 meaning opaque and 0 meaning transparent. stroke_width Stroke width. font_size Font size. line_spacing Line spacing. font Global font setting for the entire text. Local overrides are possible. slant Global slant setting, e.g. `NORMAL` or `ITALIC`. Local overrides are possible. weight Global weight setting, e.g. `NORMAL` or `BOLD`. Local overrides are possible. gradient Global gradient setting. Local overrides are possible. warn_missing_font If True (default), Manim will issue a warning if the font does not exist in the (case-sensitive) list of fonts returned from `manimpango.list_fonts()`. Returns ------- :class:`MarkupText` The text displayed in form of a :class:`.VGroup`-like mobject. Examples --------- .. manim:: BasicMarkupExample :save_last_frame: class BasicMarkupExample(Scene): def construct(self): text1 = MarkupText("foo bar foobar") text2 = MarkupText("foo bar big small") text3 = MarkupText("H2O and H3O+") text4 = MarkupText("type help for help") text5 = MarkupText( 'foo bar' ) group = VGroup(text1, text2, text3, text4, text5).arrange(DOWN) self.add(group) .. manim:: ColorExample :save_last_frame: class ColorExample(Scene): def construct(self): text1 = MarkupText( f'all in red except this', color=RED ) text2 = MarkupText("nice gradient", gradient=(BLUE, GREEN)) text3 = MarkupText( 'nice intermediate gradient', gradient=(BLUE, GREEN), ) text4 = MarkupText( 'fl ligature causing trouble here' ) text5 = MarkupText( 'fl ligature defeated with offset' ) text6 = MarkupText( 'fl ligature floating inside' ) text7 = MarkupText( 'fl ligature floating inside' ) group = VGroup(text1, text2, text3, text4, text5, text6, text7).arrange(DOWN) self.add(group) .. manim:: UnderlineExample :save_last_frame: class UnderlineExample(Scene): def construct(self): text1 = MarkupText( 'bla' ) text2 = MarkupText( 'xxxaabby' ) text3 = MarkupText( 'xxxaabby' ) text4 = MarkupText( 'xxxaabby' ) text5 = MarkupText( 'xxxaabby' ) group = VGroup(text1, text2, text3, text4, text5).arrange(DOWN) self.add(group) .. manim:: FontExample :save_last_frame: class FontExample(Scene): def construct(self): text1 = MarkupText( 'all in sans except this', font="sans" ) text2 = MarkupText( 'mixing fonts is ugly' ) text3 = MarkupText("special char > or >") text4 = MarkupText("special char < and &") group = VGroup(text1, text2, text3, text4).arrange(DOWN) self.add(group) .. manim:: NewlineExample :save_last_frame: class NewlineExample(Scene): def construct(self): text = MarkupText('foooooo\nbaaaar') self.add(text) .. manim:: NoLigaturesExample :save_last_frame: class NoLigaturesExample(Scene): def construct(self): text1 = MarkupText('floating') text2 = MarkupText('floating', disable_ligatures=True) group = VGroup(text1, text2).arrange(DOWN) self.add(group) As :class:`MarkupText` uses Pango to render text, rendering non-English characters is easily possible: .. manim:: MultiLanguage :save_last_frame: class MultiLanguage(Scene): def construct(self): morning = MarkupText("வணக்கம்", font="sans-serif") japanese = MarkupText( '日本へようこそ' ) # works as in ``Text``. mess = MarkupText("Multi-Language", weight=BOLD) russ = MarkupText("Здравствуйте मस नम म ", font="sans-serif") hin = MarkupText("नमस्ते", font="sans-serif") chinese = MarkupText("臂猿「黛比」帶著孩子", font="sans-serif") group = VGroup(morning, japanese, mess, russ, hin, chinese).arrange(DOWN) self.add(group) You can justify the text by passing :attr:`justify` parameter. .. manim:: JustifyText class JustifyText(Scene): def construct(self): ipsum_text = ( "Lorem ipsum dolor sit amet, consectetur adipiscing elit." "Praesent feugiat metus sit amet iaculis pulvinar. Nulla posuere " "quam a ex aliquam, eleifend consectetur tellus viverra. Aliquam " "fermentum interdum justo, nec rutrum elit pretium ac. Nam quis " "leo pulvinar, dignissim est at, venenatis nisi." ) justified_text = MarkupText(ipsum_text, justify=True).scale(0.4) not_justified_text = MarkupText(ipsum_text, justify=False).scale(0.4) just_title = Title("Justified") njust_title = Title("Not Justified") self.add(njust_title, not_justified_text) self.play( FadeOut(not_justified_text), FadeIn(justified_text), FadeOut(njust_title), FadeIn(just_title), ) self.wait(1) Tests ----- Check that the creation of :class:`~.MarkupText` works:: >>> MarkupText('The horse does not eat cucumber salad.') MarkupText('The horse does not eat cucumber salad.') """ @staticmethod @functools.cache def font_list() -> list[str]: value: list[str] = manimpango.list_fonts() return value def __init__( self, text: str, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor | None = None, font_size: float = DEFAULT_FONT_SIZE, line_spacing: float = -1, font: str = "", slant: str = NORMAL, weight: str = NORMAL, justify: bool = False, gradient: Iterable[ParsableManimColor] | None = None, tab_width: int = 4, height: int | None = None, width: int | None = None, should_center: bool = True, disable_ligatures: bool = False, warn_missing_font: bool = True, **kwargs: Any, ): self.text = text self.line_spacing: float = line_spacing if font and warn_missing_font: fonts_list = Text.font_list() # handle special case of sans/sans-serif if font.lower() == "sans-serif": font = "sans" if font not in fonts_list: # check if the capitalized version is in the supported fonts if font.capitalize() in fonts_list: font = font.capitalize() elif font.lower() in fonts_list: font = font.lower() elif font.title() in fonts_list: font = font.title() else: logger.warning(f"Font {font} not in {fonts_list}.") self.font = font self._font_size = float(font_size) self.slant = slant self.weight = weight self.gradient = gradient self.tab_width = tab_width self.justify = justify self.original_text = text self.disable_ligatures = disable_ligatures text_without_tabs = text if "\t" in text: text_without_tabs = text.replace("\t", " " * self.tab_width) colormap = self._extract_color_tags() if len(colormap) > 0: logger.warning( 'Using tags in MarkupText is deprecated. Please use instead.', ) gradientmap = self._extract_gradient_tags() validate_error = MarkupUtils.validate(self.text) if validate_error: raise ValueError(validate_error) if self.line_spacing == -1: self.line_spacing = ( self._font_size + self._font_size * DEFAULT_LINE_SPACING_SCALE ) else: self.line_spacing = self._font_size + self._font_size * self.line_spacing parsed_color: ManimColor = ManimColor(color) if color else VMobject().color file_name = self._text2svg(parsed_color) PangoUtils.remove_last_M(file_name) super().__init__( file_name, fill_opacity=fill_opacity, stroke_width=stroke_width, height=height, width=width, should_center=should_center, **kwargs, ) self.chars = self.get_group_class()(*self.submobjects) self.text = text_without_tabs.replace(" ", "").replace("\n", "") nppc = self.n_points_per_curve for each in self: if len(each.points) == 0: continue points = each.points curve_start = points[0] assert len(curve_start) == self.dim, curve_start # Some of the glyphs in this text might not be closed, # so we close them by identifying when one curve ends # but it is not where the next curve starts. # It is more efficient to temporarily create a list # of points and add them one at a time, then turn them # into a numpy array at the end, rather than creating # new numpy arrays every time a point or fixing line # is added (which is O(n^2) for numpy arrays). closed_curve_points: list[Point3D] = [] # OpenGL has points be part of quadratic Bezier curves; # Cairo uses cubic Bezier curves. if nppc == 3: # RendererType.OPENGL def add_line_to(end: Point3D) -> None: nonlocal closed_curve_points start = closed_curve_points[-1] closed_curve_points += [ start, (start + end) / 2, end, ] else: # RendererType.CAIRO def add_line_to(end: Point3D) -> None: nonlocal closed_curve_points start = closed_curve_points[-1] closed_curve_points += [ start, (start + start + end) / 3, (start + end + end) / 3, end, ] for index, point in enumerate(points): closed_curve_points.append(point) if ( index != len(points) - 1 and (index + 1) % nppc == 0 and any(point != points[index + 1]) ): # Add straight line from last point on this curve to the # start point on the next curve. add_line_to(curve_start) curve_start = points[index + 1] # Make sure last curve is closed add_line_to(curve_start) each.points = np.array(closed_curve_points, ndmin=2) if self.gradient: self.set_color_by_gradient(*self.gradient) for col in colormap: self.chars[ col["start"] - col["start_offset"] : col["end"] - col["start_offset"] - col["end_offset"] ].set_color(self._parse_color(col["color"])) for grad in gradientmap: self.chars[ grad["start"] - grad["start_offset"] : grad["end"] - grad["start_offset"] - grad["end_offset"] ].set_color_by_gradient( *(self._parse_color(grad["from"]), self._parse_color(grad["to"])) ) # anti-aliasing if height is None and width is None: self.scale(TEXT_MOB_SCALE_FACTOR) self.initial_height = self.height @property def font_size(self) -> float: return ( self.height / self.initial_height / TEXT_MOB_SCALE_FACTOR * 2.4 * self._font_size / DEFAULT_FONT_SIZE ) @font_size.setter def font_size(self, font_val: float) -> None: # TODO: use pango's font size scaling. if font_val <= 0: raise ValueError("font_size must be greater than 0.") else: self.scale(font_val / self.font_size) def _text2hash(self, color: ParsableManimColor) -> str: """Generates ``sha256`` hash for file name.""" settings = ( "MARKUPPANGO" + self.font + self.slant + self.weight + ManimColor(color).to_hex().lower() ) # to differentiate from classical Pango Text settings += str(self.line_spacing) + str(self._font_size) settings += str(self.disable_ligatures) settings += str(self.justify) id_str = self.text + settings hasher = hashlib.sha256() hasher.update(id_str.encode()) return hasher.hexdigest()[:16] def _text2svg(self, color: ParsableManimColor | None) -> str: """Convert the text to SVG using Pango.""" color = ManimColor(color) size = self._font_size line_spacing: float = self.line_spacing size /= TEXT2SVG_ADJUSTMENT_FACTOR line_spacing /= TEXT2SVG_ADJUSTMENT_FACTOR dir_name = config.get_dir("text_dir") dir_name.mkdir(parents=True, exist_ok=True) hash_name = self._text2hash(color) file_name = dir_name / (hash_name + ".svg") if file_name.exists(): svg_file: str = str(file_name.resolve()) else: final_text = ( f'{self.text}' if color is not None else self.text ) logger.debug(f"Setting Text {self.text}") svg_file = MarkupUtils.text2svg( final_text, self.font, self.slant, self.weight, size, line_spacing, self.disable_ligatures, str(file_name.resolve()), START_X, START_Y, 600, # width 400, # height justify=self.justify, pango_width=500, ) return svg_file def _count_real_chars(self, s: str) -> int: """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. """ count = 0 level = 0 # temporarily replace HTML entities by single char s = re.sub("&[^;]+;", "x", s) for c in s: if c == "<": level += 1 if c == ">" and level > 0: level -= 1 elif c != " " and c != "\t" and level == 0: count += 1 return count def _extract_gradient_tags(self) -> list[dict[str, Any]]: """Used to determine which parts (if any) of the string should be formatted with a gradient. Removes the ```` tag, as it is not part of Pango's markup and would cause an error. """ tags = re.finditer( r'(.+?)', self.original_text, re.S, ) gradientmap: list[dict[str, Any]] = [] for tag in tags: start = self._count_real_chars(self.original_text[: tag.start(0)]) end = start + self._count_real_chars(tag.group(5)) offsets = tag.group(4).split(",") if tag.group(4) else [0] start_offset = int(offsets[0]) if offsets[0] else 0 end_offset = int(offsets[1]) if len(offsets) == 2 and offsets[1] else 0 gradientmap.append( { "start": start, "end": end, "from": tag.group(1), "to": tag.group(2), "start_offset": start_offset, "end_offset": end_offset, }, ) self.text = re.sub( "]+>(.+?)", r"\1", self.text, count=0, flags=re.S ) return gradientmap def _parse_color(self, col: str) -> str: """Parse color given in ```` or ```` tags.""" if re.match("#[0-9a-f]{6}", col): return col else: return ManimColor(col).to_hex() def _extract_color_tags(self) -> list[dict[str, Any]]: """Used to determine which parts (if any) of the string should be formatted with a custom color. Removes the ```` tag, as it is not part of Pango's markup and would cause an error. Note: Using the ```` tags is deprecated. As soon as the legacy syntax is gone, this function will be removed. """ tags = re.finditer( r'(.+?)', self.original_text, re.S, ) colormap: list[dict[str, Any]] = [] for tag in tags: start = self._count_real_chars(self.original_text[: tag.start(0)]) end = start + self._count_real_chars(tag.group(4)) offsets = tag.group(3).split(",") if tag.group(3) else [0] start_offset = int(offsets[0]) if offsets[0] else 0 end_offset = int(offsets[1]) if len(offsets) == 2 and offsets[1] else 0 colormap.append( { "start": start, "end": end, "color": tag.group(1), "start_offset": start_offset, "end_offset": end_offset, }, ) self.text = re.sub( "]+>(.+?)", r"\1", self.text, count=0, flags=re.S ) return colormap def __repr__(self) -> str: return f"MarkupText({repr(self.original_text)})" @contextmanager def register_font(font_file: str | Path) -> Iterator[None]: """Temporarily add a font file to Pango's search path. This searches for the font_file at various places. The order it searches it described below. 1. Absolute path. 2. In ``assets/fonts`` folder. 3. In ``font/`` folder. 4. In the same directory. Parameters ---------- font_file The font file to add. Examples -------- Use ``with register_font(...)`` to add a font file to search path. .. code-block:: python with register_font("path/to/font_file.ttf"): a = Text("Hello", font="Custom Font Name") Raises ------ FileNotFoundError: If the font doesn't exists. AttributeError: If this method is used on macOS. .. important :: 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), input_folder / "assets/fonts" / font_file, input_folder / "fonts" / font_file, input_folder / font_file, ] for path in possible_paths: path = path.resolve() if path.exists(): file_path = path logger.debug("Found file at %s", file_path.absolute()) break else: error = f"Can't find {font_file}. Checked paths: {possible_paths}" raise FileNotFoundError(error) try: assert manimpango.register_font(str(file_path)) yield finally: manimpango.unregister_font(str(file_path)) ================================================ FILE: manim/mobject/three_d/__init__.py ================================================ """Three-dimensional mobjects. Modules ======= .. autosummary:: :toctree: ../reference ~polyhedra ~three_d_utils ~three_dimensions """ ================================================ FILE: manim/mobject/three_d/polyhedra.py ================================================ """General polyhedral class and platonic solids.""" from __future__ import annotations from collections.abc import Hashable from typing import TYPE_CHECKING, Any import numpy as np from manim.mobject.geometry.polygram import Polygon from manim.mobject.graph import Graph from manim.mobject.three_d.three_dimensions import Dot3D from manim.mobject.types.vectorized_mobject import VGroup from manim.utils.qhull import QuickHull if TYPE_CHECKING: from manim.mobject.mobject import Mobject from manim.typing import Point3D, Point3DLike_Array __all__ = [ "Polyhedron", "Tetrahedron", "Octahedron", "Icosahedron", "Dodecahedron", "ConvexHull3D", ] class Polyhedron(VGroup): """An abstract polyhedra class. In this implementation, polyhedra are defined with a list of vertex coordinates in space, and a list of faces. This implementation mirrors that of a standard polyhedral data format (OFF, object file format). Parameters ---------- vertex_coords A list of coordinates of the corresponding vertices in the polyhedron. Each coordinate will correspond to a vertex. The vertices are indexed with the usual indexing of Python. faces_list A list of faces. Each face is a sublist containing the indices of the vertices that form the corners of that face. faces_config Configuration for the polygons representing the faces of the polyhedron. graph_config Configuration for the graph containing the vertices and edges of the polyhedron. Examples -------- To understand how to create a custom polyhedra, let's use the example of a rather simple one - a square pyramid. .. manim:: SquarePyramidScene :save_last_frame: class SquarePyramidScene(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) vertex_coords = [ [1, 1, 0], [1, -1, 0], [-1, -1, 0], [-1, 1, 0], [0, 0, 2] ] faces_list = [ [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4], [0, 1, 2, 3] ] pyramid = Polyhedron(vertex_coords, faces_list) self.add(pyramid) In defining the polyhedron above, we first defined the coordinates of the vertices. These are the corners of the square base, given as the first four coordinates in the vertex list, and the apex, the last coordinate in the list. Next, we define the faces of the polyhedron. The triangular surfaces of the pyramid are polygons with two adjacent vertices in the base and the vertex at the apex as corners. We thus define these surfaces in the first four elements of our face list. The last element defines the base of the pyramid. The graph and faces of polyhedra can also be accessed and modified directly, after instantiation. They are stored in the `graph` and `faces` attributes respectively. .. manim:: PolyhedronSubMobjects :save_last_frame: class PolyhedronSubMobjects(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) octahedron = Octahedron(edge_length = 3) octahedron.graph[0].set_color(RED) octahedron.faces[2].set_color(YELLOW) self.add(octahedron) """ def __init__( self, vertex_coords: Point3DLike_Array, faces_list: list[list[int]], faces_config: dict[str, str | int | float | bool] = {}, graph_config: dict[str, Any] = {}, ): super().__init__() self.faces_config = dict( {"fill_opacity": 0.5, "shade_in_3d": True}, **faces_config ) self.graph_config = dict( { "vertex_type": Dot3D, "edge_config": { "stroke_opacity": 0, # I find that having the edges visible makes the polyhedra look weird }, }, **graph_config, ) self.vertex_coords = vertex_coords self.vertex_indices = list(range(len(self.vertex_coords))) self.layout: dict[Hashable, Any] = dict(enumerate(self.vertex_coords)) self.faces_list = faces_list self.face_coords = [[self.layout[j] for j in i] for i in faces_list] self.edges = self.get_edges(self.faces_list) self.faces = self.create_faces(self.face_coords) self.graph = Graph( self.vertex_indices, self.edges, layout=self.layout, **self.graph_config ) self.add(self.faces, self.graph) self.add_updater(self.update_faces) def get_edges(self, faces_list: list[list[int]]) -> list[tuple[int, int]]: """Creates list of cyclic pairwise tuples.""" edges: list[tuple[int, int]] = [] for face in faces_list: edges += zip(face, face[1:] + face[:1], strict=True) return edges def create_faces( self, face_coords: Point3DLike_Array, ) -> VGroup: """Creates VGroup of faces from a list of face coordinates.""" face_group = VGroup() for face in face_coords: face_group.add(Polygon(*face, **self.faces_config)) return face_group def update_faces(self, m: Mobject) -> None: face_coords = self.extract_face_coords() new_faces = self.create_faces(face_coords) self.faces.match_points(new_faces) def extract_face_coords(self) -> Point3DLike_Array: """Extracts the coordinates of the vertices in the graph. Used for updating faces. """ new_vertex_coords = [self.graph[v].get_center() for v in self.graph.vertices] layout = dict(enumerate(new_vertex_coords)) return [[layout[j] for j in i] for i in self.faces_list] class Tetrahedron(Polyhedron): """A tetrahedron, one of the five platonic solids. It has 4 faces, 6 edges, and 4 vertices. Parameters ---------- edge_length The length of an edge between any two vertices. Examples -------- .. manim:: TetrahedronScene :save_last_frame: class TetrahedronScene(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) obj = Tetrahedron() self.add(obj) """ def __init__(self, edge_length: float = 1, **kwargs: Any): unit = edge_length * np.sqrt(2) / 4 super().__init__( vertex_coords=[ np.array([unit, unit, unit]), np.array([unit, -unit, -unit]), np.array([-unit, unit, -unit]), np.array([-unit, -unit, unit]), ], faces_list=[[0, 1, 2], [3, 0, 2], [0, 1, 3], [3, 1, 2]], **kwargs, ) class Octahedron(Polyhedron): """An octahedron, one of the five platonic solids. It has 8 faces, 12 edges and 6 vertices. Parameters ---------- edge_length The length of an edge between any two vertices. Examples -------- .. manim:: OctahedronScene :save_last_frame: class OctahedronScene(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) obj = Octahedron() self.add(obj) """ def __init__(self, edge_length: float = 1, **kwargs: Any): unit = edge_length * np.sqrt(2) / 2 super().__init__( vertex_coords=[ np.array([unit, 0, 0]), np.array([-unit, 0, 0]), np.array([0, unit, 0]), np.array([0, -unit, 0]), np.array([0, 0, unit]), np.array([0, 0, -unit]), ], faces_list=[ [2, 4, 1], [0, 4, 2], [4, 3, 0], [1, 3, 4], [3, 5, 0], [1, 5, 3], [2, 5, 1], [0, 5, 2], ], **kwargs, ) class Icosahedron(Polyhedron): """An icosahedron, one of the five platonic solids. It has 20 faces, 30 edges and 12 vertices. Parameters ---------- edge_length The length of an edge between any two vertices. Examples -------- .. manim:: IcosahedronScene :save_last_frame: class IcosahedronScene(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) obj = Icosahedron() self.add(obj) """ def __init__(self, edge_length: float = 1, **kwargs: Any): unit_a = edge_length * ((1 + np.sqrt(5)) / 4) unit_b = edge_length * (1 / 2) super().__init__( vertex_coords=[ np.array([0, unit_b, unit_a]), np.array([0, -unit_b, unit_a]), np.array([0, unit_b, -unit_a]), np.array([0, -unit_b, -unit_a]), np.array([unit_b, unit_a, 0]), np.array([unit_b, -unit_a, 0]), np.array([-unit_b, unit_a, 0]), np.array([-unit_b, -unit_a, 0]), np.array([unit_a, 0, unit_b]), np.array([unit_a, 0, -unit_b]), np.array([-unit_a, 0, unit_b]), np.array([-unit_a, 0, -unit_b]), ], faces_list=[ [1, 8, 0], [1, 5, 7], [8, 5, 1], [7, 3, 5], [5, 9, 3], [8, 9, 5], [3, 2, 9], [9, 4, 2], [8, 4, 9], [0, 4, 8], [6, 4, 0], [6, 2, 4], [11, 2, 6], [3, 11, 2], [0, 6, 10], [10, 1, 0], [10, 7, 1], [11, 7, 3], [10, 11, 7], [10, 11, 6], ], **kwargs, ) class Dodecahedron(Polyhedron): """A dodecahedron, one of the five platonic solids. It has 12 faces, 30 edges and 20 vertices. Parameters ---------- edge_length The length of an edge between any two vertices. Examples -------- .. manim:: DodecahedronScene :save_last_frame: class DodecahedronScene(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) obj = Dodecahedron() self.add(obj) """ def __init__(self, edge_length: float = 1, **kwargs: Any): unit_a = edge_length * ((1 + np.sqrt(5)) / 4) unit_b = edge_length * ((3 + np.sqrt(5)) / 4) unit_c = edge_length * (1 / 2) super().__init__( vertex_coords=[ np.array([unit_a, unit_a, unit_a]), np.array([unit_a, unit_a, -unit_a]), np.array([unit_a, -unit_a, unit_a]), np.array([unit_a, -unit_a, -unit_a]), np.array([-unit_a, unit_a, unit_a]), np.array([-unit_a, unit_a, -unit_a]), np.array([-unit_a, -unit_a, unit_a]), np.array([-unit_a, -unit_a, -unit_a]), np.array([0, unit_c, unit_b]), np.array([0, unit_c, -unit_b]), np.array([0, -unit_c, -unit_b]), np.array([0, -unit_c, unit_b]), np.array([unit_c, unit_b, 0]), np.array([-unit_c, unit_b, 0]), np.array([unit_c, -unit_b, 0]), np.array([-unit_c, -unit_b, 0]), np.array([unit_b, 0, unit_c]), np.array([-unit_b, 0, unit_c]), np.array([unit_b, 0, -unit_c]), np.array([-unit_b, 0, -unit_c]), ], faces_list=[ [18, 16, 0, 12, 1], [3, 18, 16, 2, 14], [3, 10, 9, 1, 18], [1, 9, 5, 13, 12], [0, 8, 4, 13, 12], [2, 16, 0, 8, 11], [4, 17, 6, 11, 8], [17, 19, 5, 13, 4], [19, 7, 15, 6, 17], [6, 15, 14, 2, 11], [19, 5, 9, 10, 7], [7, 10, 3, 14, 15], ], **kwargs, ) class ConvexHull3D(Polyhedron): """A convex hull for a set of points Parameters ---------- points The points to consider. tolerance The tolerance used for quickhull. kwargs Forwarded to the parent constructor. Examples -------- .. manim:: ConvexHull3DExample :save_last_frame: :quality: high class ConvexHull3DExample(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) points = [ [ 1.93192757, 0.44134585, -1.52407061], [-0.93302521, 1.23206983, 0.64117067], [-0.44350918, -0.61043677, 0.21723705], [-0.42640268, -1.05260843, 1.61266094], [-1.84449637, 0.91238739, -1.85172623], [ 1.72068132, -0.11880457, 0.51881751], [ 0.41904805, 0.44938012, -1.86440686], [ 0.83864666, 1.66653337, 1.88960123], [ 0.22240514, -0.80986286, 1.34249326], [-1.29585759, 1.01516189, 0.46187522], [ 1.7776499, -1.59550796, -1.70240747], [ 0.80065226, -0.12530398, 1.70063977], [ 1.28960948, -1.44158255, 1.39938582], [-0.93538943, 1.33617705, -0.24852643], [-1.54868271, 1.7444399, -0.46170734] ] hull = ConvexHull3D( *points, faces_config = {"stroke_opacity": 0}, graph_config = { "vertex_type": Dot3D, "edge_config": { "stroke_color": BLUE, "stroke_width": 2, "stroke_opacity": 0.05, } } ) dots = VGroup(*[Dot3D(point) for point in points]) self.add(hull) self.add(dots) """ def __init__(self, *points: Point3D, tolerance: float = 1e-5, **kwargs: Any): # Build Convex Hull array = np.array(points) hull = QuickHull(tolerance) hull.build(array) # Setup Lists vertices = [] faces = [] # Extract Faces c = 0 d = {} facets = set(hull.facets) - hull.removed for facet in facets: tmp = set() for subfacet in facet.subfacets: for point in subfacet.points: if point not in d: vertices.append(point.coordinates) d[point] = c c += 1 tmp.add(point) faces.append([d[point] for point in tmp]) # Call Polyhedron super().__init__( vertex_coords=vertices, faces_list=faces, **kwargs, ) ================================================ FILE: manim/mobject/three_d/three_d_utils.py ================================================ """Utility functions for three-dimensional mobjects.""" from __future__ import annotations __all__ = [ "get_3d_vmob_gradient_start_and_end_points", "get_3d_vmob_start_corner_index", "get_3d_vmob_end_corner_index", "get_3d_vmob_start_corner", "get_3d_vmob_end_corner", "get_3d_vmob_unit_normal", "get_3d_vmob_start_corner_unit_normal", "get_3d_vmob_end_corner_unit_normal", ] from typing import TYPE_CHECKING, Literal import numpy as np from manim.constants import ORIGIN, UP from manim.utils.space_ops import get_unit_normal if TYPE_CHECKING: from manim.typing import Point3D, Vector3D from ..types.vectorized_mobject import VMobject def get_3d_vmob_gradient_start_and_end_points( vmob: VMobject, ) -> tuple[Point3D, Point3D]: return ( get_3d_vmob_start_corner(vmob), get_3d_vmob_end_corner(vmob), ) def get_3d_vmob_start_corner_index(vmob: VMobject) -> Literal[0]: return 0 def get_3d_vmob_end_corner_index(vmob: VMobject) -> int: return ((len(vmob.points) - 1) // 6) * 3 def get_3d_vmob_start_corner(vmob: VMobject) -> Point3D: if vmob.get_num_points() == 0: return np.array(ORIGIN) return vmob.points[get_3d_vmob_start_corner_index(vmob)] def get_3d_vmob_end_corner(vmob: VMobject) -> Point3D: if vmob.get_num_points() == 0: return np.array(ORIGIN) return vmob.points[get_3d_vmob_end_corner_index(vmob)] def get_3d_vmob_unit_normal(vmob: VMobject, point_index: int) -> Vector3D: n_points = vmob.get_num_points() if len(vmob.get_anchors()) <= 2: return np.array(UP) i = point_index im3 = i - 3 if i > 2 else (n_points - 4) ip3 = i + 3 if i < (n_points - 3) else 3 unit_normal = get_unit_normal( vmob.points[ip3] - vmob.points[i], vmob.points[im3] - vmob.points[i], ) if np.linalg.norm(unit_normal) == 0: return np.array(UP) return unit_normal def get_3d_vmob_start_corner_unit_normal(vmob: VMobject) -> Vector3D: return get_3d_vmob_unit_normal(vmob, get_3d_vmob_start_corner_index(vmob)) def get_3d_vmob_end_corner_unit_normal(vmob: VMobject) -> Vector3D: return get_3d_vmob_unit_normal(vmob, get_3d_vmob_end_corner_index(vmob)) ================================================ FILE: manim/mobject/three_d/three_dimensions.py ================================================ """Three-dimensional mobjects.""" from __future__ import annotations __all__ = [ "ThreeDVMobject", "Surface", "Sphere", "Dot3D", "Cube", "Prism", "Cone", "Arrow3D", "Cylinder", "Line3D", "Torus", ] from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING, Any, Literal, Self import numpy as np from manim import config, logger from manim.constants import * from manim.mobject.geometry.arc import Circle from manim.mobject.geometry.polygram import Square from manim.mobject.mobject import * from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject from manim.utils.color import ( BLUE, BLUE_D, BLUE_E, LIGHT_GREY, WHITE, ManimColor, ParsableManimColor, interpolate_color, ) from manim.utils.space_ops import normalize, perpendicular_bisector, z_to_vector if TYPE_CHECKING: from manim.mobject.graphing.coordinate_systems import ThreeDAxes from manim.typing import Point3D, Point3DLike, Vector3D, Vector3DLike class ThreeDVMobject(VMobject, metaclass=ConvertToOpenGL): u_index: int v_index: int u1: float u2: float v1: float v2: float def __init__(self, shade_in_3d: bool = True, **kwargs: Any): super().__init__(shade_in_3d=shade_in_3d, **kwargs) class Surface(VGroup, metaclass=ConvertToOpenGL): """Creates a Parametric Surface using a checkerboard pattern. Parameters ---------- func The function defining the :class:`Surface`. u_range The range of the ``u`` variable: ``(u_min, u_max)``. v_range The range of the ``v`` variable: ``(v_min, v_max)``. resolution The number of samples taken of the :class:`Surface`. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively. fill_color The color of the :class:`Surface`. Ignored if ``checkerboard_colors`` is set. fill_opacity The opacity of the :class:`Surface`, from 0 being fully transparent to 1 being fully opaque. Defaults to 1. checkerboard_colors ng individual faces alternating colors. Overrides ``fill_color``. stroke_color Color of the stroke surrounding each face of :class:`Surface`. stroke_width Width of the stroke surrounding each face of :class:`Surface`. Defaults to 0.5. should_make_jagged Changes the anchor mode of the Bézier curves from smooth to jagged. Defaults to ``False``. Examples -------- .. manim:: ParaSurface :save_last_frame: class ParaSurface(ThreeDScene): def func(self, u, v): return np.array([np.cos(u) * np.cos(v), np.cos(u) * np.sin(v), u]) def construct(self): axes = ThreeDAxes(x_range=[-4,4], x_length=8) surface = Surface( lambda u, v: axes.c2p(*self.func(u, v)), u_range=[-PI, PI], v_range=[0, TAU], resolution=8, ) self.set_camera_orientation(theta=70 * DEGREES, phi=75 * DEGREES) self.add(axes, surface) """ def __init__( self, func: Callable[[float, float], np.ndarray], u_range: tuple[float, float] = (0, 1), v_range: tuple[float, float] = (0, 1), resolution: int | Sequence[int] = 32, surface_piece_config: dict = {}, fill_color: ParsableManimColor = BLUE_D, fill_opacity: float = 1.0, checkerboard_colors: Iterable[ParsableManimColor] | Literal[False] = [ BLUE_D, BLUE_E, ], stroke_color: ParsableManimColor = LIGHT_GREY, stroke_width: float = 0.5, should_make_jagged: bool = False, pre_function_handle_to_anchor_scale_factor: float = 0.00001, **kwargs: Any, ) -> None: self.u_range = u_range self.v_range = v_range super().__init__( fill_color=fill_color, fill_opacity=fill_opacity, stroke_color=stroke_color, stroke_width=stroke_width, **kwargs, ) self.resolution = resolution self.surface_piece_config = surface_piece_config self.checkerboard_colors: list[ManimColor] | Literal[False] if checkerboard_colors is False: self.checkerboard_colors = checkerboard_colors else: self.checkerboard_colors = [ManimColor(i) for i in checkerboard_colors] self.should_make_jagged = should_make_jagged self.pre_function_handle_to_anchor_scale_factor = ( pre_function_handle_to_anchor_scale_factor ) self.list_of_faces: list[ThreeDVMobject] = [] self._func = func self._setup_in_uv_space() self.apply_function(lambda p: func(p[0], p[1])) if self.should_make_jagged: self.make_jagged() def func(self, u: float, v: float) -> np.ndarray: return self._func(u, v) def _get_u_values_and_v_values(self) -> tuple[np.ndarray, np.ndarray]: if isinstance(self.resolution, int): u_res = v_res = self.resolution else: u_res, v_res = self.resolution u_values = np.linspace(*self.u_range, u_res + 1) v_values = np.linspace(*self.v_range, v_res + 1) return u_values, v_values def _setup_in_uv_space(self) -> None: u_values, v_values = self._get_u_values_and_v_values() faces = VGroup() self.list_of_faces = [] for i in range(len(u_values) - 1): for j in range(len(v_values) - 1): u1, u2 = u_values[i : i + 2] v1, v2 = v_values[j : j + 2] face = ThreeDVMobject() face.set_points_as_corners( [ [u1, v1, 0], [u2, v1, 0], [u2, v2, 0], [u1, v2, 0], [u1, v1, 0], ], ) faces.add(face) face.u_index = i face.v_index = j face.u1 = u1 face.u2 = u2 face.v1 = v1 face.v2 = v2 self.list_of_faces.append(face) faces.set_fill(color=self.fill_color, opacity=self.fill_opacity) faces.set_stroke( color=self.stroke_color, width=self.stroke_width, opacity=self.stroke_opacity, ) self.add(*faces) if self.checkerboard_colors: self.set_fill_by_checkerboard(*self.checkerboard_colors) def set_fill_by_checkerboard( self, *colors: ParsableManimColor, opacity: float | None = None ) -> Self: """Sets the fill_color of each face of :class:`Surface` in an alternating pattern. Parameters ---------- colors List of colors for alternating pattern. opacity The fill_opacity of :class:`Surface`, from 0 being fully transparent to 1 being fully opaque. Returns ------- :class:`~.Surface` The parametric surface with an alternating pattern. """ n_colors = len(colors) for face in self.list_of_faces: c_index = (face.u_index + face.v_index) % n_colors face.set_fill(colors[c_index], opacity=opacity) return self def set_fill_by_value( self, axes: ThreeDAxes, colorscale: Iterable[ParsableManimColor] | Iterable[tuple[ParsableManimColor, float]] | None = None, axis: int = 2, **kwargs: Any, ) -> Self: """Sets the color of each mobject of a parametric surface to a color relative to its axis-value. Parameters ---------- axes The axes for the parametric surface, which will be used to map axis-values to colors. colorscale A list of colors, ordered from lower axis-values to higher axis-values. If a list of tuples is passed containing colors paired with numbers, then those numbers will be used as the pivots. axis The chosen axis to use for the color mapping. (0 = x, 1 = y, 2 = z) Returns ------- :class:`~.Surface` The parametric surface with a gradient applied by value. For chaining. Examples -------- .. manim:: FillByValueExample :save_last_frame: class FillByValueExample(ThreeDScene): def construct(self): resolution_fa = 8 self.set_camera_orientation(phi=75 * DEGREES, theta=-160 * DEGREES) axes = ThreeDAxes(x_range=(0, 5, 1), y_range=(0, 5, 1), z_range=(-1, 1, 0.5)) def param_surface(u, v): x = u y = v z = np.sin(x) * np.cos(y) return z surface_plane = Surface( lambda u, v: axes.c2p(u, v, param_surface(u, v)), resolution=(resolution_fa, resolution_fa), v_range=[0, 5], u_range=[0, 5], ) surface_plane.set_style(fill_opacity=1) surface_plane.set_fill_by_value(axes=axes, colorscale=[(RED, -0.5), (YELLOW, 0), (GREEN, 0.5)], axis=2) self.add(axes, surface_plane) """ if "colors" in kwargs and colorscale is None: colorscale = kwargs.pop("colors") if kwargs: raise ValueError( "Unsupported keyword argument(s): " f"{', '.join(str(key) for key in kwargs)}" ) if colorscale is None: logger.warning( "The value passed to the colorscale keyword argument was None, " "the surface fill color has not been changed" ) return self colorscale_list = list(colorscale) ranges = [axes.x_range, axes.y_range, axes.z_range] assert isinstance(colorscale_list, list) new_colors: list[ManimColor] if type(colorscale_list[0]) is tuple and len(colorscale_list[0]) == 2: new_colors, pivots = [ [ManimColor(i) for i, j in colorscale_list], [j for i, j in colorscale_list], ] else: new_colors = [ManimColor(i) for i in colorscale_list] current_range = ranges[axis] assert current_range is not None pivot_min = current_range[0] pivot_max = current_range[1] pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1) pivots = np.arange( start=pivot_min, stop=pivot_max + pivot_frequency, step=pivot_frequency, ) for mob in self.family_members_with_points(): axis_value = axes.point_to_coords(mob.get_midpoint())[axis] if axis_value <= pivots[0]: mob.set_color(new_colors[0]) elif axis_value >= pivots[-1]: mob.set_color(new_colors[-1]) else: for i, pivot in enumerate(pivots): if pivot > axis_value: color_index = (axis_value - pivots[i - 1]) / ( pivots[i] - pivots[i - 1] ) color_index = min(color_index, 1) mob_color = interpolate_color( new_colors[i - 1], new_colors[i], color_index, ) if config.renderer == RendererType.OPENGL: assert isinstance(mob, OpenGLMobject) mob.set_color(mob_color, recurse=False) elif config.renderer == RendererType.CAIRO: mob.set_color(mob_color, family=False) break return self # Specific shapes class Sphere(Surface): """A three-dimensional sphere. Parameters ---------- center Center of the :class:`Sphere`. radius The radius of the :class:`Sphere`. resolution The number of samples taken of the :class:`Sphere`. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively. u_range The range of the ``u`` variable: ``(u_min, u_max)``. v_range The range of the ``v`` variable: ``(v_min, v_max)``. Examples -------- .. manim:: ExampleSphere :save_last_frame: class ExampleSphere(ThreeDScene): def construct(self): self.set_camera_orientation(phi=PI / 6, theta=PI / 6) sphere1 = Sphere(center=(3, 0, 0), radius=1, resolution=(20, 20)) sphere1.set_color(RED) self.add(sphere1) sphere2 = Sphere(center=(-1, -3, 0), radius=2, resolution=(18, 18)) sphere2.set_color(GREEN) self.add(sphere2) sphere3 = Sphere(center=(-1, 2, 0), radius=2, resolution=(16, 16)) sphere3.set_color(BLUE) self.add(sphere3) This example shows that overlapping spheres can intersect with rough transitions. .. manim:: ExampleSphereOverlap :save_last_frame: class ExampleSphereOverlap(ThreeDScene): def construct(self): self.set_camera_orientation(phi=PI / 4, theta=PI / 4) sphere1 = Sphere(center=(0, 0, 0), radius=1, resolution=(20, 20)) sphere1.set_color(RED) self.add(sphere1) sphere2 = Sphere(center=(-0.5, -1, 0.5), radius=1.2, resolution=(20, 20)) sphere2.set_color(GREEN) self.add(sphere2) sphere3 = Sphere(center=(1, -1, 0), radius=1.1, resolution=(20, 20)) sphere3.set_color(BLUE) self.add(sphere3) In this example, by modifying ``u_range`` (the range of the azimuthal angle) and ``v_range`` (the range of the polar angle), it is possible to obtain a portion of a sphere: .. manim:: ExamplePartialSpheres :save_last_frame: class ExamplePartialSpheres(ThreeDScene): def construct(self): self.set_camera_orientation(phi=PI / 4) sphere1 = Sphere( center=(-3, 0, 0), resolution=(10, 20), u_range=[TAU / 4, 3 * TAU / 4], ) sphere1.set_color(RED) self.add(sphere1) sphere2 = Sphere( center=(0, 0, 0), resolution=(20, 10), v_range=[0, TAU / 4], ) sphere2.set_color(GREEN) self.add(sphere2) sphere3 = Sphere( center=(3, 0, 0), resolution=(5, 10), u_range=[3 * TAU / 4, TAU], v_range=[TAU / 4, TAU / 2], ) sphere3.set_color(BLUE) self.add(sphere3) """ def __init__( self, center: Point3DLike = ORIGIN, radius: float = 1, resolution: int | Sequence[int] | None = None, u_range: tuple[float, float] = (0, TAU), v_range: tuple[float, float] = (0, PI), **kwargs: Any, ) -> None: if config.renderer == RendererType.OPENGL: res_value = (101, 51) elif config.renderer == RendererType.CAIRO: res_value = (24, 12) else: raise Exception("Unknown renderer") resolution = resolution if resolution is not None else res_value self.radius = radius super().__init__( self.func, resolution=resolution, u_range=u_range, v_range=v_range, **kwargs, ) self.shift(center) def func(self, u: float, v: float) -> Point3D: """The z values defining the :class:`Sphere` being plotted. Returns ------- :class:`Point3D` The z values defining the :class:`Sphere`. """ return self.radius * np.array( [np.cos(u) * np.sin(v), np.sin(u) * np.sin(v), -np.cos(v)], ) class Dot3D(Sphere): """A spherical dot. Parameters ---------- point The location of the dot. radius The radius of the dot. color The color of the :class:`Dot3D`. resolution The number of samples taken of the :class:`Dot3D`. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively. Examples -------- .. manim:: Dot3DExample :save_last_frame: class Dot3DExample(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75*DEGREES, theta=-45*DEGREES) axes = ThreeDAxes() dot_1 = Dot3D(point=axes.coords_to_point(0, 0, 1), color=RED) dot_2 = Dot3D(point=axes.coords_to_point(2, 0, 0), radius=0.1, color=BLUE) dot_3 = Dot3D(point=[0, 0, 0], radius=0.1, color=ORANGE) self.add(axes, dot_1, dot_2,dot_3) """ def __init__( self, point: Point3D = ORIGIN, radius: float = DEFAULT_DOT_RADIUS, color: ParsableManimColor = WHITE, resolution: int | tuple[int, int] | None = (8, 8), **kwargs: Any, ) -> None: super().__init__(center=point, radius=radius, resolution=resolution, **kwargs) self.set_color(color) class Cube(VGroup): """A three-dimensional cube. Parameters ---------- side_length Length of each side of the :class:`Cube`. fill_opacity The opacity of the :class:`Cube`, from 0 being fully transparent to 1 being fully opaque. Defaults to 0.75. fill_color The color of the :class:`Cube`. stroke_width The width of the stroke surrounding each face of the :class:`Cube`. Examples -------- .. manim:: CubeExample :save_last_frame: class CubeExample(ThreeDScene): def construct(self): self.set_camera_orientation(phi=75*DEGREES, theta=-45*DEGREES) axes = ThreeDAxes() cube = Cube(side_length=3, fill_opacity=0.7, fill_color=BLUE) self.add(cube) """ def __init__( self, side_length: float = 2, fill_opacity: float = 0.75, fill_color: ParsableManimColor = BLUE, stroke_width: float = 0, **kwargs: Any, ) -> None: self.side_length = side_length super().__init__( fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs, ) def generate_points(self) -> None: """Creates the sides of the :class:`Cube`.""" for vect in IN, OUT, LEFT, RIGHT, UP, DOWN: face = Square( side_length=self.side_length, shade_in_3d=True, joint_type=LineJointType.BEVEL, ) face.flip() face.shift(self.side_length * OUT / 2.0) face.apply_matrix(z_to_vector(vect)) self.add(face) def init_points(self) -> None: self.generate_points() class Prism(Cube): """A right rectangular prism (or rectangular cuboid). Defined by the length of each side in ``[x, y, z]`` format. Parameters ---------- dimensions Dimensions of the :class:`Prism` in ``[x, y, z]`` format. Examples -------- .. manim:: ExamplePrism :save_last_frame: class ExamplePrism(ThreeDScene): def construct(self): self.set_camera_orientation(phi=60 * DEGREES, theta=150 * DEGREES) prismSmall = Prism(dimensions=[1, 2, 3]).rotate(PI / 2) prismLarge = Prism(dimensions=[1.5, 3, 4.5]).move_to([2, 0, 0]) self.add(prismSmall, prismLarge) """ def __init__( self, dimensions: Vector3DLike = [3, 2, 1], **kwargs: Any, ) -> None: self.dimensions = dimensions super().__init__(**kwargs) def generate_points(self) -> None: """Creates the sides of the :class:`Prism`.""" super().generate_points() for dim, value in enumerate(self.dimensions): self.rescale_to_fit(value, dim, stretch=True) class Cone(Surface): """A circular cone. Can be defined using 2 parameters: its height, and its base radius. The polar angle, theta, can be calculated using arctan(base_radius / height) The spherical radius, r, is calculated using the pythagorean theorem. Parameters ---------- base_radius The base radius from which the cone tapers. height The height measured from the plane formed by the base_radius to the apex of the cone. direction The direction of the apex. show_base Whether to show the base plane or not. v_range The azimuthal angle to start and end at. u_min The radius at the apex. checkerboard_colors Show checkerboard grid texture on the cone. Examples -------- .. manim:: ExampleCone :save_last_frame: class ExampleCone(ThreeDScene): def construct(self): axes = ThreeDAxes() cone = Cone(direction=X_AXIS+Y_AXIS+2*Z_AXIS, resolution=8) self.set_camera_orientation(phi=5*PI/11, theta=PI/9) self.add(axes, cone) """ def __init__( self, base_radius: float = 1, height: float = 1, direction: Vector3DLike = Z_AXIS, show_base: bool = False, v_range: tuple[float, float] = (0, TAU), u_min: float = 0, checkerboard_colors: Iterable[ParsableManimColor] | Literal[False] = False, **kwargs: Any, ) -> None: self.direction = np.array(direction) self.theta = PI - np.arctan(base_radius / height) super().__init__( self.func, v_range=v_range, u_range=(u_min, np.sqrt(base_radius**2 + height**2)), checkerboard_colors=checkerboard_colors, **kwargs, ) # used for rotations self.new_height = height self._current_theta = 0 self._current_phi = 0 self.base_circle = Circle( radius=base_radius, color=self.fill_color, fill_opacity=self.fill_opacity, stroke_width=0, ) self.base_circle.shift(height * IN) self._set_start_and_end_attributes(direction) if show_base: self.add(self.base_circle) self._rotate_to_direction() def func(self, u: float, v: float) -> Point3D: """Converts from spherical coordinates to cartesian. Parameters ---------- u The radius. v The azimuthal angle. Returns ------- :class:`numpy.array` Points defining the :class:`Cone`. """ r = u phi = v return np.array( [ r * np.sin(self.theta) * np.cos(phi), r * np.sin(self.theta) * np.sin(phi), r * np.cos(self.theta), ], ) def get_start(self) -> Point3D: return self.start_point.get_center() def get_end(self) -> Point3D: return self.end_point.get_center() def _rotate_to_direction(self) -> None: x, y, z = self.direction r = np.sqrt(x**2 + y**2 + z**2) theta = np.arccos(z / r) if r > 0 else 0 if x == 0: if y == 0: # along the z axis phi = 0 else: phi = np.arctan(np.inf) if y < 0: phi += PI else: phi = np.arctan(y / x) if x < 0: phi += PI # Undo old rotation (in reverse order) self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN) self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN) # Do new rotation self.rotate(theta, Y_AXIS, about_point=ORIGIN) self.rotate(phi, Z_AXIS, about_point=ORIGIN) # Store values self._current_theta = theta self._current_phi = phi def set_direction(self, direction: Vector3DLike) -> None: """Changes the direction of the apex of the :class:`Cone`. Parameters ---------- direction The direction of the apex. """ self.direction = np.array(direction) self._rotate_to_direction() def get_direction(self) -> Vector3D: """Returns the current direction of the apex of the :class:`Cone`. Returns ------- direction : :class:`numpy.array` The direction of the apex. """ return self.direction def _set_start_and_end_attributes(self, direction: Vector3D) -> None: normalized_direction = direction * np.linalg.norm(direction) start = self.base_circle.get_center() end = start + normalized_direction * self.new_height self.start_point = VectorizedPoint(start) self.end_point = VectorizedPoint(end) self.add(self.start_point, self.end_point) class Cylinder(Surface): """A cylinder, defined by its height, radius and direction, Parameters ---------- radius The radius of the cylinder. height The height of the cylinder. direction The direction of the central axis of the cylinder. v_range The height along the height axis (given by direction) to start and end on. show_ends Whether to show the end caps or not. resolution The number of samples taken of the :class:`Cylinder`. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively. Examples -------- .. manim:: ExampleCylinder :save_last_frame: class ExampleCylinder(ThreeDScene): def construct(self): axes = ThreeDAxes() cylinder = Cylinder(radius=2, height=3) self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(axes, cylinder) """ def __init__( self, radius: float = 1, height: float = 2, direction: Vector3DLike = Z_AXIS, v_range: tuple[float, float] = (0, TAU), show_ends: bool = True, resolution: int | tuple[int, int] = (24, 24), **kwargs: Any, ) -> None: self._height = height self.radius = radius super().__init__( self.func, resolution=resolution, u_range=(-self._height / 2, self._height / 2), v_range=v_range, **kwargs, ) if show_ends: self.add_bases() self._current_phi = 0 self._current_theta = 0 self.set_direction(direction) def func(self, u: float, v: float) -> np.ndarray: """Converts from cylindrical coordinates to cartesian. Parameters ---------- u The height. v The azimuthal angle. Returns ------- :class:`numpy.ndarray` Points defining the :class:`Cylinder`. """ height = u phi = v r = self.radius return np.array([r * np.cos(phi), r * np.sin(phi), height]) def add_bases(self) -> None: """Adds the end caps of the cylinder.""" opacity: float if config.renderer == RendererType.OPENGL: assert isinstance(self, OpenGLMobject) color = self.color opacity = self.opacity elif config.renderer == RendererType.CAIRO: color = self.fill_color opacity = self.fill_opacity self.base_top = Circle( radius=self.radius, color=color, fill_opacity=opacity, shade_in_3d=True, stroke_width=0, ) self.base_top.shift(self.u_range[1] * IN) self.base_bottom = Circle( radius=self.radius, color=color, fill_opacity=opacity, shade_in_3d=True, stroke_width=0, ) self.base_bottom.shift(self.u_range[0] * IN) self.add(self.base_top, self.base_bottom) def _rotate_to_direction(self) -> None: x, y, z = self.direction r = np.sqrt(x**2 + y**2 + z**2) theta = np.arccos(z / r) if r > 0 else 0 if x == 0: if y == 0: # along the z axis phi = 0 else: # along the x axis phi = np.arctan(np.inf) if y < 0: phi += PI else: phi = np.arctan(y / x) if x < 0: phi += PI # undo old rotation (in reverse direction) self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN) self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN) # do new rotation self.rotate(theta, Y_AXIS, about_point=ORIGIN) self.rotate(phi, Z_AXIS, about_point=ORIGIN) # store new values self._current_theta = theta self._current_phi = phi def set_direction(self, direction: Vector3DLike) -> None: """Sets the direction of the central axis of the :class:`Cylinder`. Parameters ---------- direction : :class:`numpy.array` The direction of the central axis of the :class:`Cylinder`. """ # if get_norm(direction) is get_norm(self.direction): # pass self.direction = direction self._rotate_to_direction() def get_direction(self) -> np.ndarray: """Returns the direction of the central axis of the :class:`Cylinder`. Returns ------- direction : :class:`numpy.array` The direction of the central axis of the :class:`Cylinder`. """ return self.direction class Line3D(Cylinder): """A cylindrical line, for use in ThreeDScene. Parameters ---------- start The start point of the line. end The end point of the line. thickness The thickness of the line. color The color of the line. resolution The resolution of the line. By default this value is the number of points the line will sampled at. If you want the line to also come out checkered, use a tuple. For example, for a line made of 24 points with 4 checker points on each cylinder, pass the tuple (4, 24). Examples -------- .. manim:: ExampleLine3D :save_last_frame: class ExampleLine3D(ThreeDScene): def construct(self): axes = ThreeDAxes() line = Line3D(start=np.array([0, 0, 0]), end=np.array([2, 2, 2])) self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(axes, line) """ def __init__( self, start: Point3DLike = LEFT, end: Point3DLike = RIGHT, thickness: float = 0.02, color: ParsableManimColor | None = None, resolution: int | tuple[int, int] = 24, **kwargs: Any, ): self.thickness = thickness self.resolution: tuple[int, int] = ( (2, resolution) if isinstance(resolution, int) else resolution ) start = np.array(start, dtype=np.float64) end = np.array(end, dtype=np.float64) self.set_start_and_end_attrs(start, end, **kwargs) if color is not None: self.set_color(color) def set_start_and_end_attrs( self, start: Point3DLike, end: Point3DLike, **kwargs: Any ) -> None: """Sets the start and end points of the line. If either ``start`` or ``end`` are :class:`Mobjects <.Mobject>`, this gives their centers. Parameters ---------- start Starting point or :class:`Mobject`. end Ending point or :class:`Mobject`. """ rough_start = self.pointify(start) rough_end = self.pointify(end) self.vect = rough_end - rough_start self.length = np.linalg.norm(self.vect) self.direction: Vector3D = normalize(self.vect) # Now that we know the direction between them, # we can the appropriate boundary point from # start and end, if they're mobjects self.start = self.pointify(start, self.direction) self.end = self.pointify(end, -self.direction) super().__init__( height=np.linalg.norm(self.vect), radius=self.thickness, direction=self.direction, resolution=self.resolution, **kwargs, ) self.shift((self.start + self.end) / 2) def pointify( self, mob_or_point: Mobject | Point3DLike, direction: Vector3DLike | None = None, ) -> Point3D: """Gets a point representing the center of the :class:`Mobjects <.Mobject>`. Parameters ---------- mob_or_point :class:`Mobjects <.Mobject>` or point whose center should be returned. direction If an edge of a :class:`Mobjects <.Mobject>` should be returned, the direction of the edge. Returns ------- :class:`numpy.array` Center of the :class:`Mobjects <.Mobject>` or point, or edge if direction is given. """ if isinstance(mob_or_point, (Mobject, OpenGLMobject)): mob = mob_or_point if direction is None: return mob.get_center() else: return mob.get_boundary_point(direction) return np.array(mob_or_point) def get_start(self) -> Point3D: """Returns the starting point of the :class:`Line3D`. Returns ------- start : :class:`numpy.array` Starting point of the :class:`Line3D`. """ return self.start def get_end(self) -> Point3D: """Returns the ending point of the :class:`Line3D`. Returns ------- end : :class:`numpy.array` Ending point of the :class:`Line3D`. """ return self.end @classmethod def parallel_to( cls, line: Line3D, point: Point3DLike = ORIGIN, length: float = 5, **kwargs: Any, ) -> Line3D: """Returns a line parallel to another line going through a given point. Parameters ---------- line The line to be parallel to. point The point to pass through. length Length of the parallel line. kwargs Additional parameters to be passed to the class. Returns ------- :class:`Line3D` Line parallel to ``line``. Examples -------- .. manim:: ParallelLineExample :save_last_frame: class ParallelLineExample(ThreeDScene): def construct(self): self.set_camera_orientation(PI / 3, -PI / 4) ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10) line1 = Line3D(RIGHT * 2, UP + OUT, color=RED) line2 = Line3D.parallel_to(line1, color=YELLOW) self.add(ax, line1, line2) """ np_point = np.asarray(point) vect = normalize(line.vect) return cls( np_point + vect * length / 2, np_point - vect * length / 2, **kwargs, ) @classmethod def perpendicular_to( cls, line: Line3D, point: Point3DLike = ORIGIN, length: float = 5, **kwargs: Any, ) -> Line3D: """Returns a line perpendicular to another line going through a given point. Parameters ---------- line The line to be perpendicular to. point The point to pass through. length Length of the perpendicular line. kwargs Additional parameters to be passed to the class. Returns ------- :class:`Line3D` Line perpendicular to ``line``. Examples -------- .. manim:: PerpLineExample :save_last_frame: class PerpLineExample(ThreeDScene): def construct(self): self.set_camera_orientation(PI / 3, -PI / 4) ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10) line1 = Line3D(RIGHT * 2, UP + OUT, color=RED) line2 = Line3D.perpendicular_to(line1, color=BLUE) self.add(ax, line1, line2) """ np_point = np.asarray(point) norm = np.cross(line.vect, np_point - line.start) if all(np.linalg.norm(norm) == np.zeros(3)): raise ValueError("Could not find the perpendicular.") start, end = perpendicular_bisector([line.start, line.end], norm) vect = normalize(end - start) return cls( np_point + vect * length / 2, np_point - vect * length / 2, **kwargs, ) class Arrow3D(Line3D): """An arrow made out of a cylindrical line and a conical tip. Parameters ---------- start The start position of the arrow. end The end position of the arrow. thickness The thickness of the arrow. height The height of the conical tip. base_radius The base radius of the conical tip. color The color of the arrow. resolution The resolution of the arrow line. Examples -------- .. manim:: ExampleArrow3D :save_last_frame: class ExampleArrow3D(ThreeDScene): def construct(self): axes = ThreeDAxes() arrow = Arrow3D( start=np.array([0, 0, 0]), end=np.array([2, 2, 2]), resolution=8 ) self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(axes, arrow) """ def __init__( self, start: Point3DLike = LEFT, end: Point3DLike = RIGHT, thickness: float = 0.02, height: float = 0.3, base_radius: float = 0.08, color: ParsableManimColor = WHITE, resolution: int | tuple[int, int] = 24, **kwargs: Any, ) -> None: super().__init__( start=start, end=end, thickness=thickness, color=color, resolution=resolution, **kwargs, ) self.length = np.linalg.norm(self.vect) self.set_start_and_end_attrs( self.start, self.end - height * self.direction, **kwargs, ) self.cone = Cone( direction=self.direction, base_radius=base_radius, height=height, **kwargs, ) np_end = np.asarray(end, dtype=np.float64) self.cone.shift(np_end) self.end_point = VectorizedPoint(np_end) self.add(self.end_point, self.cone) self.set_color(color) def get_end(self) -> np.ndarray: return self.end_point.get_center() class Torus(Surface): """A torus. Parameters ---------- major_radius Distance from the center of the tube to the center of the torus. minor_radius Radius of the tube. u_range The range of the ``u`` variable: ``(u_min, u_max)``. v_range The range of the ``v`` variable: ``(v_min, v_max)``. resolution The number of samples taken of the :class:`Torus`. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively. Examples -------- .. manim :: ExampleTorus :save_last_frame: class ExampleTorus(ThreeDScene): def construct(self): axes = ThreeDAxes() torus = Torus() self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) self.add(axes, torus) """ def __init__( self, major_radius: float = 3, minor_radius: float = 1, u_range: tuple[float, float] = (0, TAU), v_range: tuple[float, float] = (0, TAU), resolution: int | tuple[int, int] | None = None, **kwargs: Any, ) -> None: if config.renderer == RendererType.OPENGL: res_value = (101, 101) elif config.renderer == RendererType.CAIRO: res_value = (24, 24) resolution = resolution if resolution is not None else res_value self.R = major_radius self.r = minor_radius super().__init__( self.func, u_range=u_range, v_range=v_range, resolution=resolution, **kwargs, ) def func(self, u: float, v: float) -> Point3D: """The z values defining the :class:`Torus` being plotted. Returns ------- :class:`numpy.ndarray` The z values defining the :class:`Torus`. """ P = np.array([np.cos(u), np.sin(u), 0]) return (self.R - self.r * np.cos(v)) * P - self.r * np.sin(v) * OUT ================================================ FILE: manim/mobject/types/__init__.py ================================================ """Specialized mobject base classes. Modules ======= .. autosummary:: :toctree: ../reference ~image_mobject ~point_cloud_mobject ~vectorized_mobject """ ================================================ FILE: manim/mobject/types/image_mobject.py ================================================ """Mobjects representing raster images.""" from __future__ import annotations __all__ = ["AbstractImageMobject", "ImageMobject", "ImageMobjectFromCamera"] import pathlib from typing import TYPE_CHECKING, Any import numpy as np from PIL import Image from PIL.Image import Resampling from manim.mobject.geometry.shape_matchers import SurroundingRectangle from ... import config from ...camera.moving_camera import MovingCamera from ...constants import * from ...mobject.mobject import Mobject from ...utils.bezier import interpolate from ...utils.color import ( WHITE, YELLOW_C, ManimColor, ParsableManimColor, color_to_int_rgb, ) from ...utils.images import change_to_rgba_array, get_full_raster_image_path __all__ = ["ImageMobject", "ImageMobjectFromCamera"] if TYPE_CHECKING: from typing import Self import numpy.typing as npt from manim.typing import PixelArray, StrPath from ...camera.moving_camera import MovingCamera class AbstractImageMobject(Mobject): """ Automatically filters out black pixels Parameters ---------- scale_to_resolution At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen. """ def __init__( self, scale_to_resolution: int, pixel_array_dtype: str = "uint8", resampling_algorithm: Resampling = Resampling.BICUBIC, **kwargs: Any, ) -> None: self.pixel_array_dtype = pixel_array_dtype self.scale_to_resolution = scale_to_resolution self.set_resampling_algorithm(resampling_algorithm) super().__init__(**kwargs) def get_pixel_array(self) -> PixelArray: raise NotImplementedError() def set_color( self, color: ParsableManimColor = YELLOW_C, alpha: Any = None, family: bool = True, ) -> AbstractImageMobject: # Likely to be implemented in subclasses, but no obligation raise NotImplementedError() def set_resampling_algorithm(self, resampling_algorithm: int) -> Self: """ Sets the interpolation method for upscaling the image. By default the image is interpolated using bicubic algorithm. This method lets you change it. Interpolation is done internally using Pillow, and the function besides the string constants describing the algorithm accepts the Pillow integer constants. Parameters ---------- resampling_algorithm An integer constant described in the Pillow library, or one from the RESAMPLING_ALGORITHMS global dictionary, under the following keys: * 'bicubic' or 'cubic' * 'nearest' or 'none' * 'box' * 'bilinear' or 'linear' * 'hamming' * 'lanczos' or 'antialias' """ if resampling_algorithm not in RESAMPLING_ALGORITHMS.values(): raise ValueError( "resampling_algorithm has to be an int, one of the values defined in " "RESAMPLING_ALGORITHMS or a Pillow resampling filter constant. " "Available algorithms: 'bicubic' (or 'cubic'), 'nearest' (or 'none'), " "'bilinear' (or 'linear').", ) self.resampling_algorithm = resampling_algorithm return self def reset_points(self) -> Self: """Sets :attr:`points` to be the four image corners.""" self.points = np.array( [ UP + LEFT, UP + RIGHT, DOWN + LEFT, DOWN + RIGHT, ], ) self.center() h, w = self.get_pixel_array().shape[:2] if self.scale_to_resolution: height = h / self.scale_to_resolution * config["frame_height"] else: height = 3 # this is the case for ImageMobjectFromCamera self.stretch_to_fit_height(height) self.stretch_to_fit_width(height * w / h) return self class ImageMobject(AbstractImageMobject): """Displays an Image from a numpy array or a file. Parameters ---------- scale_to_resolution At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen. Example ------- .. manim:: ImageFromArray :save_last_frame: class ImageFromArray(Scene): def construct(self): image = ImageMobject(np.uint8([[0, 100, 30, 200], [255, 0, 5, 33]])) image.height = 7 self.add(image) Changing interpolation style: .. manim:: ImageInterpolationEx :save_last_frame: class ImageInterpolationEx(Scene): def construct(self): img = ImageMobject(np.uint8([[63, 0, 0, 0], [0, 127, 0, 0], [0, 0, 191, 0], [0, 0, 0, 255] ])) img.height = 3 group = Group() algorithm_texts = ["nearest", "linear", "cubic"] for algorithm_text in algorithm_texts: algorithm = RESAMPLING_ALGORITHMS[algorithm_text] img_copy = img.copy().set_resampling_algorithm(algorithm) img_copy.add(Text(algorithm_text).scale(0.5).next_to(img_copy, UP)) group.add(img_copy) group.arrange() self.add(group) """ def __init__( self, filename_or_array: StrPath | npt.NDArray, scale_to_resolution: int = QUALITIES[DEFAULT_QUALITY]["pixel_height"], invert: bool = False, image_mode: str = "RGBA", **kwargs: Any, ) -> None: self.fill_opacity: float = 1 self.stroke_opacity: float = 1 self.invert_image = invert self.image_mode = image_mode if isinstance(filename_or_array, (str, pathlib.PurePath)): path = get_full_raster_image_path(filename_or_array) image = Image.open(path).convert(self.image_mode) self.pixel_array = np.array(image) self.path = path else: self.pixel_array = np.array(filename_or_array) self.pixel_array_dtype = kwargs.get("pixel_array_dtype", "uint8") self.pixel_array = change_to_rgba_array( self.pixel_array, self.pixel_array_dtype ) if self.invert_image: self.pixel_array[:, :, :3] = ( np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3] ) self.orig_alpha_pixel_array = self.pixel_array[:, :, 3].copy() super().__init__(scale_to_resolution, **kwargs) def get_pixel_array(self) -> PixelArray: """A simple getter method.""" return self.pixel_array def set_color( self, color: ParsableManimColor = YELLOW_C, alpha: Any = None, family: bool = True, ) -> Self: rgb = color_to_int_rgb(color) self.pixel_array[:, :, :3] = rgb if alpha is not None: self.pixel_array[:, :, 3] = int(255 * alpha) for submob in self.submobjects: submob.set_color(color, alpha, family) self.color = ManimColor(color) return self def set_opacity(self, alpha: float) -> Self: """Sets the image's opacity. Parameters ---------- alpha The alpha value of the object, 1 being opaque and 0 being transparent. """ self.pixel_array[:, :, 3] = self.orig_alpha_pixel_array * alpha self.stroke_opacity = alpha return self def fade(self, darkness: float = 0.5, family: bool = True) -> Self: """Sets the image's opacity using a 1 - alpha relationship. Parameters ---------- darkness The alpha value of the object, 1 being transparent and 0 being opaque. family Whether the submobjects of the ImageMobject should be affected. """ self.set_opacity(1 - darkness) super().fade(darkness, family) return self def interpolate_color( self, mobject1: Mobject, mobject2: Mobject, alpha: float ) -> None: """Interpolates the array of pixel color values from one ImageMobject into an array of equal size in the target ImageMobject. Parameters ---------- mobject1 The ImageMobject to transform from. mobject2 The ImageMobject to transform into. alpha Used to track the lerp relationship. Not opacity related. """ assert isinstance(mobject1, ImageMobject) assert isinstance(mobject2, ImageMobject) assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, ( f"Mobject pixel array shapes incompatible for interpolation.\n" f"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\n" f"Mobject 2 ({mobject2}) : {mobject2.pixel_array.shape}" ) self.fill_opacity = interpolate( mobject1.fill_opacity, mobject2.fill_opacity, alpha, ) self.stroke_opacity = interpolate( mobject1.stroke_opacity, mobject2.stroke_opacity, alpha, ) self.pixel_array = interpolate( mobject1.pixel_array, mobject2.pixel_array, alpha, ).astype(self.pixel_array_dtype) def get_style(self) -> dict[str, Any]: return { "fill_color": ManimColor(self.color.to_rgb()).to_hex(), "fill_opacity": self.fill_opacity, } # TODO, add the ability to have the dimensions/orientation of this # mobject more strongly tied to the frame of the camera it contains, # in the case where that's a MovingCamera class ImageMobjectFromCamera(AbstractImageMobject): def __init__( self, camera: MovingCamera, default_display_frame_config: dict[str, Any] | None = None, **kwargs: Any, ) -> None: self.camera = camera if default_display_frame_config is None: default_display_frame_config = { "stroke_width": 3, "stroke_color": WHITE, "buff": 0, } self.default_display_frame_config = default_display_frame_config self.pixel_array = self.camera.pixel_array super().__init__(scale_to_resolution=False, **kwargs) # TODO: Get rid of this. def get_pixel_array(self) -> PixelArray: self.pixel_array = self.camera.pixel_array return self.pixel_array def add_display_frame(self, **kwargs: Any) -> Self: config = dict(self.default_display_frame_config) config.update(kwargs) self.display_frame = SurroundingRectangle(self, **config) self.add(self.display_frame) return self def interpolate_color( self, mobject1: Mobject, mobject2: Mobject, alpha: float ) -> None: assert isinstance(mobject1, ImageMobjectFromCamera) assert isinstance(mobject2, ImageMobjectFromCamera) assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, ( f"Mobject pixel array shapes incompatible for interpolation.\n" f"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\n" f"Mobject 2 ({mobject2}) : {mobject2.pixel_array.shape}" ) self.pixel_array = interpolate( mobject1.pixel_array, mobject2.pixel_array, alpha, ).astype(self.pixel_array_dtype) ================================================ FILE: manim/mobject/types/point_cloud_mobject.py ================================================ """Mobjects representing point clouds.""" from __future__ import annotations __all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"] from collections.abc import Callable from typing import TYPE_CHECKING, Any import numpy as np from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject from ...constants import * from ...mobject.mobject import Mobject from ...utils.bezier import interpolate from ...utils.color import ( BLACK, PURE_YELLOW, WHITE, ManimColor, ParsableManimColor, color_gradient, color_to_rgba, rgba_to_color, ) from ...utils.iterables import stretch_array_to_length __all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"] if TYPE_CHECKING: from typing import Self import numpy.typing as npt from manim.typing import ( FloatRGBA_Array, FloatRGBALike_Array, ManimFloat, Point3D_Array, Point3DLike, Point3DLike_Array, ) class PMobject(Mobject, metaclass=ConvertToOpenGL): """A disc made of a cloud of Dots Examples -------- .. manim:: PMobjectExample :save_last_frame: class PMobjectExample(Scene): def construct(self): pG = PGroup() # This is just a collection of PMobject's # As the scale factor increases, the number of points # removed increases. for sf in range(1, 9 + 1): p = PointCloudDot(density=20, radius=1).thin_out(sf) # PointCloudDot is a type of PMobject # and can therefore be added to a PGroup pG.add(p) # This organizes all the shapes in a grid. pG.arrange_in_grid() self.add(pG) """ def __init__(self, stroke_width: int = DEFAULT_STROKE_WIDTH, **kwargs: Any) -> None: self.stroke_width = stroke_width super().__init__(**kwargs) def reset_points(self) -> Self: self.rgbas: FloatRGBA_Array = np.zeros((0, 4)) self.points: Point3D_Array = np.zeros((0, 3)) return self def get_array_attrs(self) -> list[str]: return super().get_array_attrs() + ["rgbas"] def add_points( self, points: Point3DLike_Array, rgbas: FloatRGBALike_Array | None = None, color: ParsableManimColor | None = None, alpha: float = 1.0, ) -> Self: """Add points. Points must be a Nx3 numpy array. Rgbas must be a Nx4 numpy array if it is not None. """ if not isinstance(points, np.ndarray): points = np.array(points) num_new_points = len(points) self.points = np.append(self.points, points, axis=0) if rgbas is None: color = ManimColor(color) if color else self.color rgbas = np.repeat([color_to_rgba(color, alpha)], num_new_points, axis=0) elif len(rgbas) != len(points): raise ValueError("points and rgbas must have same length") self.rgbas = np.append(self.rgbas, rgbas, axis=0) return self def set_color( self, color: ParsableManimColor = PURE_YELLOW, family: bool = True ) -> Self: rgba = color_to_rgba(color) mobs = self.family_members_with_points() if family else [self] for mob in mobs: mob.rgbas[:, :] = rgba self.color = ManimColor.parse(color) return self def get_stroke_width(self) -> int: return self.stroke_width def set_stroke_width(self, width: int, family: bool = True) -> Self: mobs = self.family_members_with_points() if family else [self] for mob in mobs: mob.stroke_width = width return self def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self: self.rgbas = np.array( list(map(color_to_rgba, color_gradient(colors, len(self.points)))), ) return self def set_colors_by_radial_gradient( self, center: Point3DLike | None = None, radius: float = 1, inner_color: ParsableManimColor = WHITE, outer_color: ParsableManimColor = BLACK, ) -> Self: start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color])) if center is None: center = self.get_center() for mob in self.family_members_with_points(): distances = np.abs(self.points - center) alphas = np.linalg.norm(distances, axis=1) / radius mob.rgbas = np.array( np.array( [interpolate(start_rgba, end_rgba, alpha) for alpha in alphas], ), ) return self def match_colors(self, mobject: Mobject) -> Self: Mobject.align_data(self, mobject) self.rgbas = np.array(mobject.rgbas) return self def filter_out(self, condition: npt.NDArray) -> Self: for mob in self.family_members_with_points(): to_eliminate = ~np.apply_along_axis(condition, 1, mob.points) mob.points = mob.points[to_eliminate] mob.rgbas = mob.rgbas[to_eliminate] return self def thin_out(self, factor: int = 5) -> Self: """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( lambda arr, n=num_points: arr[np.arange(0, n, factor)], # type: ignore[misc] ) return self def sort_points( self, function: Callable[[npt.NDArray[ManimFloat]], float] = lambda p: p[0] ) -> Self: """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]) # type: ignore[misc] return self def fade_to( self, color: ParsableManimColor, alpha: float, family: bool = True ) -> Self: self.rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha) for mob in self.submobjects: mob.fade_to(color, alpha, family) return self def get_all_rgbas(self) -> npt.NDArray: return self.get_merged_array("rgbas") def ingest_submobjects(self) -> Self: attrs = self.get_array_attrs() arrays = list(map(self.get_merged_array, attrs)) for attr, array in zip(attrs, arrays, strict=True): setattr(self, attr, array) self.submobjects = [] return self def get_color(self) -> ManimColor: return rgba_to_color(self.rgbas[0, :]) def point_from_proportion(self, alpha: float) -> Any: index = alpha * (self.get_num_points() - 1) return self.points[np.floor(index)] @staticmethod def get_mobject_type_class() -> type[PMobject]: return PMobject # Alignment def align_points_with_larger(self, larger_mobject: Mobject) -> None: assert isinstance(larger_mobject, PMobject) self.apply_over_attr_arrays( lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()), ) def get_point_mobject(self, center: Point3DLike | None = None) -> Point: if center is None: center = self.get_center() return Point(center) def interpolate_color( self, mobject1: Mobject, mobject2: Mobject, alpha: float ) -> Self: self.rgbas = interpolate(mobject1.rgbas, mobject2.rgbas, alpha) self.set_stroke_width( interpolate( mobject1.get_stroke_width(), mobject2.get_stroke_width(), alpha, ), ) return self def pointwise_become_partial(self, mobject: Mobject, a: float, b: float) -> None: lower_index, upper_index = (int(x * mobject.get_num_points()) for x in (a, b)) for attr in self.get_array_attrs(): full_array = getattr(mobject, attr) partial_array = full_array[lower_index:upper_index] setattr(self, attr, partial_array) # TODO, Make the two implementations below non-redundant class Mobject1D(PMobject, metaclass=ConvertToOpenGL): def __init__(self, density: int = DEFAULT_POINT_DENSITY_1D, **kwargs: Any) -> None: self.density = density self.epsilon = 1.0 / self.density super().__init__(**kwargs) def add_line( self, start: npt.NDArray, end: npt.NDArray, color: ParsableManimColor | None = None, ) -> None: start, end = list(map(np.array, [start, end])) length = np.linalg.norm(end - start) if length == 0: points = np.array([start]) else: epsilon = self.epsilon / length points = np.array( [interpolate(start, end, t) for t in np.arange(0, 1, epsilon)] ) self.add_points(points, color=color) class Mobject2D(PMobject, metaclass=ConvertToOpenGL): def __init__(self, density: int = DEFAULT_POINT_DENSITY_2D, **kwargs: Any) -> None: self.density = density self.epsilon = 1.0 / self.density super().__init__(**kwargs) class PGroup(PMobject): """A group for several point mobjects. Examples -------- .. manim:: PgroupExample :save_last_frame: class PgroupExample(Scene): def construct(self): p1 = PointCloudDot(radius=1, density=20, color=BLUE) p1.move_to(4.5 * LEFT) p2 = PointCloudDot() p3 = PointCloudDot(radius=1.5, stroke_width=2.5, color=PINK) p3.move_to(4.5 * RIGHT) pList = PGroup(p1, p2, p3) self.add(pList) """ def __init__(self, *pmobs: Any, **kwargs: Any) -> None: if not all(isinstance(m, (PMobject, OpenGLPMobject)) for m in pmobs): raise ValueError( "All submobjects must be of type PMobject or OpenGLPMObject" " if using the opengl renderer", ) super().__init__(**kwargs) self.add(*pmobs) def fade_to( self, color: ParsableManimColor, alpha: float, family: bool = True ) -> Self: if family: for mob in self.submobjects: mob.fade_to(color, alpha, family) return self class PointCloudDot(Mobject1D): """A disc made of a cloud of dots. Examples -------- .. manim:: PointCloudDotExample :save_last_frame: class PointCloudDotExample(Scene): def construct(self): cloud_1 = PointCloudDot(color=RED) cloud_2 = PointCloudDot(stroke_width=4, radius=1) cloud_3 = PointCloudDot(density=15) group = Group(cloud_1, cloud_2, cloud_3).arrange() self.add(group) .. manim:: PointCloudDotExample2 class PointCloudDotExample2(Scene): def construct(self): plane = ComplexPlane() cloud = PointCloudDot(color=RED) self.add( plane, cloud ) self.wait() self.play( cloud.animate.apply_complex_function(lambda z: np.exp(z)) ) """ def __init__( self, center: Point3DLike = ORIGIN, radius: float = 2.0, stroke_width: int = 2, density: int = DEFAULT_POINT_DENSITY_1D, color: ManimColor = PURE_YELLOW, **kwargs: Any, ) -> None: self.radius = radius self.epsilon = 1.0 / density super().__init__( stroke_width=stroke_width, density=density, color=color, **kwargs ) self.shift(center) def init_points(self) -> None: self.reset_points() self.generate_points() def generate_points(self) -> None: self.add_points( np.array( [ r * (np.cos(theta) * RIGHT + np.sin(theta) * UP) for r in np.arange(self.epsilon, self.radius, self.epsilon) # Num is equal to int(stop - start)/ (step + 1) reformulated. for theta in np.linspace( 0, 2 * np.pi, num=int(2 * np.pi * (r + self.epsilon) / self.epsilon), ) ] ), ) class Point(PMobject): """A mobject representing a point. Examples -------- .. manim:: ExamplePoint :save_last_frame: class ExamplePoint(Scene): def construct(self): colorList = [RED, GREEN, BLUE, YELLOW] for i in range(200): point = Point(location=[0.63 * np.random.randint(-4, 4), 0.37 * np.random.randint(-4, 4), 0], color=np.random.choice(colorList)) self.add(point) for i in range(200): point = Point(location=[0.37 * np.random.randint(-4, 4), 0.63 * np.random.randint(-4, 4), 0], color=np.random.choice(colorList)) self.add(point) self.add(point) """ def __init__( self, location: Point3DLike = ORIGIN, color: ManimColor = BLACK, **kwargs: Any ) -> None: self.location = location super().__init__(color=color, **kwargs) def init_points(self) -> None: self.reset_points() self.generate_points() self.set_points([self.location]) def generate_points(self) -> None: self.add_points(np.array([self.location])) ================================================ FILE: manim/mobject/types/vectorized_mobject.py ================================================ """Mobjects that use vector graphics.""" from __future__ import annotations __all__ = [ "VMobject", "VGroup", "VDict", "VectorizedPoint", "CurvesAsSubmobjects", "DashedVMobject", ] import itertools as it import sys from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence from typing import TYPE_CHECKING, Any, Literal import numpy as np from PIL.Image import Image from manim import config from manim.constants import * from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.mobject.three_d.three_d_utils import ( get_3d_vmob_gradient_start_and_end_points, ) from manim.utils.bezier import ( bezier, bezier_remap, get_smooth_cubic_bezier_handle_points, integer_interpolate, interpolate, partial_bezier_points, proportions_along_bezier_curve_for_point, ) from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor from manim.utils.iterables import ( make_even, resize_array, stretch_array_to_length, tuplify, ) from manim.utils.space_ops import rotate_vector, shoelace_direction if TYPE_CHECKING: from collections.abc import Iterator from typing import Self import numpy.typing as npt from manim.typing import ( CubicBezierPath, CubicBezierPointsLike, CubicSpline, FloatRGBA, FloatRGBA_Array, ManimFloat, MappingFunction, Point2DLike, Point3D, Point3D_Array, Point3DLike, Point3DLike_Array, Vector3D, Vector3DLike, ) # TODO # - Change cubic curve groups to have 4 points instead of 3 # - Change sub_path idea accordingly # - No more mark_paths_closed, instead have the camera test # if last point in close to first point # - Think about length of self.points. Always 0 or 1 mod 4? # That's kind of weird. class VMobject(Mobject): """A vectorized mobject. Parameters ---------- background_stroke_color The purpose of background stroke is to have something that won't overlap fill, e.g. For text against some textured background. sheen_factor When a color c is set, there will be a second color computed based on interpolating c to WHITE by with sheen_factor, and the display will gradient to this secondary color in the direction of sheen_direction. close_new_points Indicates that it will not be displayed, but that it should count in parent mobject's path tolerance_for_point_equality This is within a pixel joint_type The line joint type used to connect the curve segments of this vectorized mobject. See :class:`.LineJointType` for options. """ sheen_factor = 0.0 target: VMobject def __init__( self, fill_color: ParsableManimColor | None = None, fill_opacity: float = 0.0, stroke_color: ParsableManimColor | None = None, stroke_opacity: float = 1.0, stroke_width: float = DEFAULT_STROKE_WIDTH, background_stroke_color: ParsableManimColor | None = BLACK, background_stroke_opacity: float = 1.0, background_stroke_width: float = 0, sheen_factor: float = 0.0, joint_type: LineJointType | None = None, sheen_direction: Vector3DLike = UL, close_new_points: bool = False, pre_function_handle_to_anchor_scale_factor: float = 0.01, make_smooth_after_applying_functions: bool = False, background_image: Image | str | None = None, shade_in_3d: bool = False, # TODO, do we care about accounting for varying zoom levels? tolerance_for_point_equality: float = 1e-6, n_points_per_cubic_curve: int = 4, cap_style: CapStyleType = CapStyleType.AUTO, **kwargs: Any, ): self.fill_opacity = fill_opacity self.stroke_opacity = stroke_opacity self.stroke_width = stroke_width if background_stroke_color is not None: self.background_stroke_color: ManimColor = ManimColor( background_stroke_color ) self.background_stroke_opacity: float = background_stroke_opacity self.background_stroke_width: float = background_stroke_width self.sheen_factor: float = sheen_factor self.joint_type: LineJointType = ( LineJointType.AUTO if joint_type is None else joint_type ) self.sheen_direction = sheen_direction self.close_new_points: bool = close_new_points self.pre_function_handle_to_anchor_scale_factor: float = ( pre_function_handle_to_anchor_scale_factor ) self.make_smooth_after_applying_functions: bool = ( make_smooth_after_applying_functions ) self.background_image: Image | str | None = background_image self.shade_in_3d: bool = shade_in_3d self.tolerance_for_point_equality: float = tolerance_for_point_equality self.n_points_per_cubic_curve: int = n_points_per_cubic_curve self._bezier_t_values: npt.NDArray[float] = np.linspace( 0, 1, n_points_per_cubic_curve ) self.cap_style: CapStyleType = cap_style super().__init__(**kwargs) self.submobjects: list[VMobject] # TODO: Find where color overwrites are happening and remove the color doubling # if "color" in kwargs: # fill_color = kwargs["color"] # stroke_color = kwargs["color"] if fill_color is not None: self.fill_color = ManimColor.parse(fill_color) if stroke_color is not None: self.stroke_color = ManimColor.parse(stroke_color) def _assert_valid_submobjects(self, submobjects: Iterable[VMobject]) -> Self: return self._assert_valid_submobjects_internal(submobjects, VMobject) def __iter__(self) -> Iterator[VMobject]: return iter(self.split()) # OpenGL compatibility @property def n_points_per_curve(self) -> int: return self.n_points_per_cubic_curve def get_group_class(self) -> type[VGroup]: return VGroup @staticmethod def get_mobject_type_class() -> type[VMobject]: return VMobject # Colors def init_colors(self, propagate_colors: bool = True) -> Self: self.set_fill( color=self.fill_color, opacity=self.fill_opacity, family=propagate_colors, ) self.set_stroke( color=self.stroke_color, width=self.stroke_width, opacity=self.stroke_opacity, family=propagate_colors, ) self.set_background_stroke( color=self.background_stroke_color, width=self.background_stroke_width, opacity=self.background_stroke_opacity, family=propagate_colors, ) self.set_sheen( factor=self.sheen_factor, direction=self.sheen_direction, family=propagate_colors, ) if not propagate_colors: for submobject in self.submobjects: submobject.init_colors(propagate_colors=False) return self def generate_rgbas_array( self, color: ParsableManimColor | Iterable[ManimColor] | None, opacity: float | Iterable[float], ) -> FloatRGBA: """ First arg can be either a color, or a tuple/list of colors. Likewise, opacity can either be a float, or a tuple of floats. If self.sheen_factor is not zero, and only one color was passed in, a second slightly light color will automatically be added for the gradient """ colors: list[ManimColor] = [ ManimColor(c) if (c is not None) else BLACK for c in tuplify(color) ] opacities: list[float] = [ o if (o is not None) else 0.0 for o in tuplify(opacity) ] rgbas: FloatRGBA_Array = np.array( [ c.to_rgba_with_alpha(o) for c, o in zip(*make_even(colors, opacities), strict=True) ], ) sheen_factor = self.get_sheen_factor() if sheen_factor != 0 and len(rgbas) == 1: light_rgbas = np.array(rgbas) light_rgbas[:, :3] += sheen_factor np.clip(light_rgbas, 0, 1, out=light_rgbas) rgbas = np.append(rgbas, light_rgbas, axis=0) return rgbas def update_rgbas_array( self, array_name: str, color: ParsableManimColor | Iterable[ManimColor] | None = None, opacity: float | None = None, ) -> Self: rgbas = self.generate_rgbas_array(color, opacity) if not hasattr(self, array_name): setattr(self, array_name, rgbas) return self # Match up current rgbas array with the newly calculated # one. 99% of the time they'll be the same. curr_rgbas = getattr(self, array_name) if len(curr_rgbas) < len(rgbas): curr_rgbas = stretch_array_to_length(curr_rgbas, len(rgbas)) setattr(self, array_name, curr_rgbas) elif len(rgbas) < len(curr_rgbas): rgbas = stretch_array_to_length(rgbas, len(curr_rgbas)) # Only update rgb if color was not None, and only # update alpha channel if opacity was passed in if color is not None: curr_rgbas[:, :3] = rgbas[:, :3] if opacity is not None: curr_rgbas[:, 3] = rgbas[:, 3] return self def set_fill( self, color: ParsableManimColor | None = None, opacity: float | None = None, family: bool = True, ) -> Self: """Set the fill color and fill opacity of a :class:`VMobject`. Parameters ---------- color Fill color of the :class:`VMobject`. opacity Fill opacity of the :class:`VMobject`. family If ``True``, the fill color of all submobjects is also set. Returns ------- :class:`VMobject` ``self`` Examples -------- .. manim:: SetFill :save_last_frame: class SetFill(Scene): def construct(self): square = Square().scale(2).set_fill(WHITE,1) circle1 = Circle().set_fill(GREEN,0.8) circle2 = Circle().set_fill(YELLOW) # No fill_opacity circle3 = Circle().set_fill(color = '#FF2135', opacity = 0.2) group = Group(circle1,circle2,circle3).arrange() self.add(square) self.add(group) See Also -------- :meth:`~.VMobject.set_style` """ if family: for submobject in self.submobjects: submobject.set_fill(color, opacity, family) self.update_rgbas_array("fill_rgbas", color, opacity) self.fill_rgbas: FloatRGBA_Array if opacity is not None: self.fill_opacity = opacity return self def set_stroke( self, color: ParsableManimColor = None, width: float | None = None, opacity: float | None = None, background=False, family: bool = True, ) -> Self: if family: for submobject in self.submobjects: submobject.set_stroke(color, width, opacity, background, family) if background: array_name = "background_stroke_rgbas" width_name = "background_stroke_width" opacity_name = "background_stroke_opacity" else: array_name = "stroke_rgbas" width_name = "stroke_width" opacity_name = "stroke_opacity" self.update_rgbas_array(array_name, color, opacity) if width is not None: setattr(self, width_name, width) if opacity is not None: setattr(self, opacity_name, opacity) if color is not None and background: if isinstance(color, (list, tuple)): self.background_stroke_color = ManimColor.parse(color) else: self.background_stroke_color = ManimColor(color) return self def set_cap_style(self, cap_style: CapStyleType) -> Self: """ Sets the cap style of the :class:`VMobject`. Parameters ---------- cap_style The cap style to be set. See :class:`.CapStyleType` for options. Returns ------- :class:`VMobject` ``self`` Examples -------- .. manim:: CapStyleExample :save_last_frame: class CapStyleExample(Scene): def construct(self): line = Line(LEFT, RIGHT, color=YELLOW, stroke_width=20) line.set_cap_style(CapStyleType.ROUND) self.add(line) """ self.cap_style = cap_style return self def set_background_stroke(self, **kwargs) -> Self: kwargs["background"] = True self.set_stroke(**kwargs) return self def set_style( self, fill_color: ParsableManimColor | None = None, fill_opacity: float | None = None, stroke_color: ParsableManimColor | None = None, stroke_width: float | None = None, stroke_opacity: float | None = None, background_stroke_color: ParsableManimColor | None = None, background_stroke_width: float | None = None, background_stroke_opacity: float | None = None, sheen_factor: float | None = None, sheen_direction: Vector3DLike | None = None, background_image: Image | str | None = None, family: bool = True, ) -> Self: self.set_fill(color=fill_color, opacity=fill_opacity, family=family) self.set_stroke( color=stroke_color, width=stroke_width, opacity=stroke_opacity, family=family, ) self.set_background_stroke( color=background_stroke_color, width=background_stroke_width, opacity=background_stroke_opacity, family=family, ) if sheen_factor: self.set_sheen( factor=sheen_factor, direction=sheen_direction, family=family, ) if background_image: self.color_using_background_image(background_image) return self def get_style(self, simple: bool = False) -> dict: ret = { "stroke_opacity": self.get_stroke_opacity(), "stroke_width": self.get_stroke_width(), } # TODO: FIX COLORS HERE if simple: ret["fill_color"] = self.get_fill_color() ret["fill_opacity"] = self.get_fill_opacity() ret["stroke_color"] = self.get_stroke_color() else: ret["fill_color"] = self.get_fill_colors() ret["fill_opacity"] = self.get_fill_opacities() ret["stroke_color"] = self.get_stroke_colors() ret["background_stroke_color"] = self.get_stroke_colors(background=True) ret["background_stroke_width"] = self.get_stroke_width(background=True) ret["background_stroke_opacity"] = self.get_stroke_opacity(background=True) ret["sheen_factor"] = self.get_sheen_factor() ret["sheen_direction"] = self.get_sheen_direction() ret["background_image"] = self.get_background_image() return ret def match_style(self, vmobject: VMobject, family: bool = True) -> Self: self.set_style(**vmobject.get_style(), family=False) if family: # Does its best to match up submobject lists, and # match styles accordingly submobs1, submobs2 = self.submobjects, vmobject.submobjects if len(submobs1) == 0: return self elif len(submobs2) == 0: submobs2 = [vmobject] for sm1, sm2 in zip(*make_even(submobs1, submobs2), strict=True): sm1.match_style(sm2) return self def set_color(self, color: ParsableManimColor, family: bool = True) -> Self: self.set_fill(color, family=family) self.set_stroke(color, family=family) return self def set_opacity(self, opacity: float, family: bool = True) -> Self: self.set_fill(opacity=opacity, family=family) self.set_stroke(opacity=opacity, family=family) self.set_stroke(opacity=opacity, family=family, background=True) return self def scale( self, scale_factor: float, scale_stroke: bool = False, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: r"""Scale the size by a factor. Default behavior is to scale about the center of the vmobject. Parameters ---------- scale_factor The scaling factor :math:`\alpha`. If :math:`0 < |\alpha| < 1`, the mobject will shrink, and for :math:`|\alpha| > 1` it will grow. Furthermore, if :math:`\alpha < 0`, the mobject is also flipped. scale_stroke Boolean determining if the object's outline is scaled when the object is scaled. If enabled, and object with 2px outline is scaled by a factor of .5, it will have an outline of 1px. kwargs Additional keyword arguments passed to :meth:`~.Mobject.scale`. Returns ------- :class:`VMobject` ``self`` Examples -------- .. manim:: MobjectScaleExample :save_last_frame: class MobjectScaleExample(Scene): def construct(self): c1 = Circle(1, RED).set_x(-1) c2 = Circle(1, GREEN).set_x(1) vg = VGroup(c1, c2) vg.set_stroke(width=50) self.add(vg) self.play( c1.animate.scale(.25), c2.animate.scale(.25, scale_stroke=True) ) See also -------- :meth:`move_to` """ if scale_stroke: self.set_stroke(width=abs(scale_factor) * self.get_stroke_width()) self.set_stroke( width=abs(scale_factor) * self.get_stroke_width(background=True), background=True, ) super().scale(scale_factor, about_point=about_point, about_edge=about_edge) return self def fade(self, darkness: float = 0.5, family: bool = True) -> Self: factor = 1.0 - darkness self.set_fill(opacity=factor * self.get_fill_opacity(), family=False) self.set_stroke(opacity=factor * self.get_stroke_opacity(), family=False) self.set_background_stroke( opacity=factor * self.get_stroke_opacity(background=True), family=False, ) super().fade(darkness, family) return self def get_fill_rgbas(self) -> FloatRGBA_Array: try: return self.fill_rgbas except AttributeError: return np.zeros((1, 4)) def get_fill_color(self) -> ManimColor: """ If there are multiple colors (for gradient) this returns the first one """ return self.get_fill_colors()[0] fill_color = property(get_fill_color, set_fill) def get_fill_opacity(self) -> ManimFloat: """ If there are multiple opacities, this returns the first """ return self.get_fill_opacities()[0] # TODO: Does this just do a copy? # TODO: I have the feeling that this function should not return None, does that have any usage ? def get_fill_colors(self) -> list[ManimColor | None]: return [ ManimColor(rgba[:3]) if rgba.any() else None for rgba in self.get_fill_rgbas() ] def get_fill_opacities(self) -> npt.NDArray[ManimFloat]: return self.get_fill_rgbas()[:, 3] def get_stroke_rgbas(self, background: bool = False) -> FloatRGBA_Array: try: if background: self.background_stroke_rgbas: FloatRGBA_Array rgbas = self.background_stroke_rgbas else: self.stroke_rgbas: FloatRGBA_Array rgbas = self.stroke_rgbas return rgbas except AttributeError: return np.zeros((1, 4)) def get_stroke_color(self, background: bool = False) -> ManimColor | None: return self.get_stroke_colors(background)[0] stroke_color = property(get_stroke_color, set_stroke) def get_stroke_width(self, background: bool = False) -> float: if background: width = self.background_stroke_width else: width = self.stroke_width if isinstance(width, str): width = int(width) return max(0.0, width) def get_stroke_opacity(self, background: bool = False) -> ManimFloat: return self.get_stroke_opacities(background)[0] def get_stroke_colors(self, background: bool = False) -> list[ManimColor | None]: return [ ManimColor(rgba[:3]) if rgba.any() else None for rgba in self.get_stroke_rgbas(background) ] def get_stroke_opacities(self, background: bool = False) -> npt.NDArray[ManimFloat]: return self.get_stroke_rgbas(background)[:, 3] def get_color(self) -> ManimColor: if np.all(self.get_fill_opacities() == 0): return self.get_stroke_color() return self.get_fill_color() color: ManimColor = property(get_color, set_color) def nonempty_submobjects(self) -> Sequence[VMobject]: return [ submob for submob in self.submobjects if len(submob.submobjects) != 0 or len(submob.points) != 0 ] def split(self) -> list[VMobject]: result: list[VMobject] = [self] if len(self.points) > 0 else [] return result + self.submobjects def set_sheen_direction(self, direction: Vector3DLike, family: bool = True) -> Self: """Sets the direction of the applied sheen. Parameters ---------- direction Direction from where the gradient is applied. Examples -------- Normal usage:: Circle().set_sheen_direction(UP) See Also -------- :meth:`~.VMobject.set_sheen` :meth:`~.VMobject.rotate_sheen_direction` """ direction_copy = np.array(direction) if family: for submob in self.get_family(): submob.sheen_direction = direction_copy.copy() else: self.sheen_direction = direction_copy return self def rotate_sheen_direction( self, angle: float, axis: Vector3DLike = OUT, family: bool = True ) -> Self: """Rotates the direction of the applied sheen. Parameters ---------- angle Angle by which the direction of sheen is rotated. axis Axis of rotation. Examples -------- Normal usage:: Circle().set_sheen_direction(UP).rotate_sheen_direction(PI) See Also -------- :meth:`~.VMobject.set_sheen_direction` """ if family: for submob in self.get_family(): submob.sheen_direction = rotate_vector( submob.sheen_direction, angle, axis, ) else: self.sheen_direction = rotate_vector(self.sheen_direction, angle, axis) return self def set_sheen( self, factor: float, direction: Vector3DLike | None = None, family: bool = True ) -> Self: """Applies a color gradient from a direction. Parameters ---------- factor The extent of lustre/gradient to apply. If negative, the gradient starts from black, if positive the gradient starts from white and changes to the current color. direction Direction from where the gradient is applied. Examples -------- .. manim:: SetSheen :save_last_frame: class SetSheen(Scene): def construct(self): 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) self.sheen_factor: float = factor if direction is not None: # family set to false because recursion will # already be handled above self.set_sheen_direction(direction, family=False) # Reset color to put sheen_factor into effect if factor != 0: self.set_stroke(self.get_stroke_color(), family=family) self.set_fill(self.get_fill_color(), family=family) return self def get_sheen_direction(self) -> Vector3D: return np.array(self.sheen_direction) def get_sheen_factor(self) -> float: return self.sheen_factor def get_gradient_start_and_end_points(self) -> tuple[Point3D, Point3D]: if self.shade_in_3d: return get_3d_vmob_gradient_start_and_end_points(self) else: direction = self.get_sheen_direction() c = self.get_center() bases = np.array( [self.get_edge_center(vect) - c for vect in [RIGHT, UP, OUT]], ).transpose() offset = np.dot(bases, direction) return (c - offset, c + offset) def color_using_background_image(self, background_image: Image | str) -> Self: self.background_image: Image | str = background_image self.set_color(WHITE) for submob in self.submobjects: submob.color_using_background_image(background_image) return self def get_background_image(self) -> Image | str: return self.background_image def match_background_image(self, vmobject: VMobject) -> Self: self.color_using_background_image(vmobject.get_background_image()) return self def set_shade_in_3d( self, value: bool = True, z_index_as_group: bool = False ) -> Self: for submob in self.get_family(): submob.shade_in_3d = value if z_index_as_group: submob.z_index_group = self return self def set_points(self, points: Point3DLike_Array) -> Self: self.points: Point3D_Array = np.array(points) return self def resize_points( self, new_length: int, resize_func: Callable[[Point3D_Array, int], Point3D_Array] = resize_array, ) -> Self: """Resize the array of anchor points and handles to have the specified size. Parameters ---------- new_length The new (total) number of points. resize_func A function mapping a Numpy array (the points) and an integer (the target size) to a Numpy array. The default implementation is based on Numpy's ``resize`` function. """ if new_length != len(self.points): self.points = resize_func(self.points, new_length) return self def set_anchors_and_handles( self, anchors1: Point3DLike_Array, handles1: Point3DLike_Array, handles2: Point3DLike_Array, anchors2: Point3DLike_Array, ) -> Self: """Given two sets of anchors and handles, process them to set them as anchors and handles of the VMobject. anchors1[i], handles1[i], handles2[i] and anchors2[i] define the i-th bezier curve of the vmobject. There are four hardcoded parameters and this is a problem as it makes the number of points per cubic curve unchangeable from 4 (two anchors and two handles). Returns ------- :class:`VMobject` ``self`` """ assert len(anchors1) == len(handles1) == len(handles2) == len(anchors2) nppcc = self.n_points_per_cubic_curve # 4 total_len = nppcc * len(anchors1) self.points = np.empty((total_len, self.dim)) # the following will, from the four sets, dispatch them in points such that # self.points = [ # anchors1[0], handles1[0], handles2[0], anchors1[0], anchors1[1], # handles1[1], ... # ] arrays = [anchors1, handles1, handles2, anchors2] for index, array in enumerate(arrays): self.points[index::nppcc] = array return self def clear_points(self) -> None: # TODO: shouldn't this return self instead of None? self.points = np.zeros((0, self.dim)) def append_points(self, new_points: Point3DLike_Array) -> Self: """Append the given ``new_points`` to the end of :attr:`VMobject.points`. Parameters ---------- new_points An array of 3D points to append. Returns ------- :class:`VMobject` The VMobject itself, after appending ``new_points``. """ # TODO, check that number new points is a multiple of 4? # or else that if len(self.points) % 4 == 1, then # len(new_points) % 4 == 3? n = len(self.points) points = np.empty((n + len(new_points), self.dim)) points[:n] = self.points points[n:] = new_points self.points = points return self def start_new_path(self, point: Point3DLike) -> Self: """Append a ``point`` to the :attr:`VMobject.points`, which will be the beginning of a new Bézier curve in the path given by the points. If there's an unfinished curve at the end of :attr:`VMobject.points`, complete it by appending the last Bézier curve's start anchor as many times as needed. Parameters ---------- point A 3D point to append to :attr:`VMobject.points`. Returns ------- :class:`VMobject` The VMobject itself, after appending ``point`` and starting a new curve. """ n_points = len(self.points) nppc = self.n_points_per_curve if n_points % nppc != 0: # close the open path by appending the last # start anchor sufficiently often last_anchor = self.get_start_anchors()[-1] closure = [last_anchor] * (nppc - (n_points % nppc)) self.append_points(closure + [point]) else: self.append_points([point]) return self def add_cubic_bezier_curve( self, anchor1: Point3DLike, handle1: Point3DLike, handle2: Point3DLike, anchor2: Point3DLike, ) -> None: # TODO, check the len(self.points) % 4 == 0? self.append_points([anchor1, handle1, handle2, anchor2]) # what type is curves? def add_cubic_bezier_curves(self, curves) -> None: self.append_points(curves.flatten()) def add_cubic_bezier_curve_to( self, handle1: Point3DLike, handle2: Point3DLike, anchor: Point3DLike, ) -> Self: """Add cubic bezier curve to the path. NOTE : the first anchor is not a parameter as by default the end of the last sub-path! Parameters ---------- handle1 first handle handle2 second handle anchor anchor Returns ------- :class:`VMobject` ``self`` """ self.throw_error_if_no_points() new_points = [handle1, handle2, anchor] if self.has_new_path_started(): self.append_points(new_points) else: self.append_points([self.get_last_point()] + new_points) return self def add_quadratic_bezier_curve_to( self, handle: Point3DLike, anchor: Point3DLike, ) -> Self: """Add Quadratic bezier curve to the path. Returns ------- :class:`VMobject` ``self`` """ # How does one approximate a quadratic with a cubic? # refer to the Wikipedia page on Bezier curves # https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Degree_elevation, accessed Jan 20, 2021 # 1. Copy the end points, and then # 2. Place the 2 middle control points 2/3 along the line segments # from the end points to the quadratic curve's middle control point. # I think that's beautiful. self.add_cubic_bezier_curve_to( 2 / 3 * handle + 1 / 3 * self.get_last_point(), 2 / 3 * handle + 1 / 3 * anchor, anchor, ) return self def add_line_to(self, point: Point3DLike) -> Self: """Add a straight line from the last point of VMobject to the given point. Parameters ---------- point The end of the straight line. Returns ------- :class:`VMobject` ``self`` """ self.add_cubic_bezier_curve_to( *( interpolate(self.get_last_point(), point, t) for t in self._bezier_t_values[1:] ) ) return self def add_smooth_curve_to(self, *points: Point3DLike) -> Self: """Creates a smooth curve from given points and add it to the VMobject. If two points are passed in, the first is interpreted as a handle, the second as an anchor. Parameters ---------- points Points (anchor and handle, or just anchor) to add a smooth curve from Returns ------- :class:`VMobject` ``self`` Raises ------ ValueError If 0 or more than 2 points are given. """ # TODO remove the value error and just add two parameters with one optional if len(points) == 1: handle2 = None new_anchor = points[0] elif len(points) == 2: handle2, new_anchor = points else: name = sys._getframe(0).f_code.co_name raise ValueError(f"Only call {name} with 1 or 2 points") if self.has_new_path_started(): self.add_line_to(new_anchor) else: self.throw_error_if_no_points() last_h2, last_a2 = self.points[-2:] last_tangent = last_a2 - last_h2 handle1 = last_a2 + last_tangent if handle2 is None: to_anchor_vect = new_anchor - last_a2 new_tangent = rotate_vector(last_tangent, PI, axis=to_anchor_vect) handle2 = new_anchor - new_tangent self.append_points([last_a2, handle1, handle2, new_anchor]) return self def has_new_path_started(self) -> bool: nppcc = self.n_points_per_cubic_curve # 4 # A new path starting is defined by a control point which is not part of a bezier subcurve. return len(self.points) % nppcc == 1 def get_last_point(self) -> Point3D: return self.points[-1] def is_closed(self) -> bool: # TODO use consider_points_equals_2d ? return self.consider_points_equals(self.points[0], self.points[-1]) def close_path(self) -> None: if not self.is_closed(): self.add_line_to(self.get_subpaths()[-1][0]) def add_points_as_corners(self, points: Point3DLike_Array) -> Self: """Append multiple straight lines at the end of :attr:`VMobject.points`, which connect the given ``points`` in order starting from the end of the current path. These ``points`` would be therefore the corners of the new polyline appended to the path. Parameters ---------- points An array of 3D points representing the corners of the polyline to append to :attr:`VMobject.points`. Returns ------- :class:`VMobject` The VMobject itself, after appending the straight lines to its path. """ self.throw_error_if_no_points() points = np.asarray(points).reshape(-1, self.dim) num_points = points.shape[0] if num_points == 0: return self start_corners = np.empty((num_points, self.dim)) start_corners[0] = self.points[-1] start_corners[1:] = points[:-1] end_corners = points if self.has_new_path_started(): # Remove the last point from the new path self.points = self.points[:-1] nppcc = self.n_points_per_cubic_curve new_points = np.empty((nppcc * start_corners.shape[0], self.dim)) new_points[::nppcc] = start_corners new_points[nppcc - 1 :: nppcc] = end_corners for i, t in enumerate(self._bezier_t_values): new_points[i::nppcc] = interpolate(start_corners, end_corners, t) self.append_points(new_points) return self def set_points_as_corners(self, points: Point3DLike_Array) -> Self: """Given an array of points, set them as corners of the :class:`VMobject`. To achieve that, this algorithm sets handles aligned with the anchors such that the resultant Bézier curve will be the segment between the two anchors. Parameters ---------- points Array of points that will be set as corners. Returns ------- :class:`VMobject` The VMobject itself, after setting the new points as corners. Examples -------- .. manim:: PointsAsCornersExample :save_last_frame: class PointsAsCornersExample(Scene): def construct(self): corners = ( # create square UR, UL, DL, DR, UR, # create crosses DL, UL, DR ) vmob = VMobject(stroke_color=RED) vmob.set_points_as_corners(corners).scale(2) self.add(vmob) """ points = np.array(points) # This will set the handles aligned with the anchors. # Id est, a bezier curve will be the segment from the two anchors such that the handles belongs to this segment. self.set_anchors_and_handles( *(interpolate(points[:-1], points[1:], t) for t in self._bezier_t_values) ) return self def set_points_smoothly(self, points: Point3DLike_Array) -> Self: self.set_points_as_corners(points) self.make_smooth() return self def change_anchor_mode(self, mode: Literal["jagged", "smooth"]) -> Self: """Changes the anchor mode of the bezier curves. This will modify the handles. There can be only two modes, "jagged", and "smooth". Returns ------- :class:`VMobject` ``self`` """ assert mode in ["jagged", "smooth"], 'mode must be either "jagged" or "smooth"' nppcc = self.n_points_per_cubic_curve for submob in self.family_members_with_points(): subpaths = submob.get_subpaths() submob.clear_points() # A subpath can be composed of several bezier curves. for subpath in subpaths: # This will retrieve the anchors of the subpath, by selecting every n element in the array subpath # The append is needed as the last element is not reached when slicing with numpy. anchors = np.append(subpath[::nppcc], subpath[-1:], 0) if mode == "smooth": h1, h2 = get_smooth_cubic_bezier_handle_points(anchors) else: # mode == "jagged" # The following will make the handles aligned with the anchors, thus making the bezier curve a segment a1 = anchors[:-1] a2 = anchors[1:] h1 = interpolate(a1, a2, 1.0 / 3) h2 = interpolate(a1, a2, 2.0 / 3) new_subpath = np.array(subpath) new_subpath[1::nppcc] = h1 new_subpath[2::nppcc] = h2 submob.append_points(new_subpath) return self def make_smooth(self) -> Self: return self.change_anchor_mode("smooth") def make_jagged(self) -> Self: return self.change_anchor_mode("jagged") def add_subpath(self, points: CubicBezierPathLike) -> Self: assert len(points) % 4 == 0 self.append_points(points) return self def append_vectorized_mobject(self, vectorized_mobject: VMobject) -> None: if self.has_new_path_started(): # Remove last point, which is starting # a new path self.points = self.points[:-1] self.append_points(vectorized_mobject.points) def apply_function( self, function: MappingFunction, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: factor = self.pre_function_handle_to_anchor_scale_factor self.scale_handle_to_anchor_distances(factor) super().apply_function(function) self.scale_handle_to_anchor_distances(1.0 / factor) if self.make_smooth_after_applying_functions: self.make_smooth() return self def rotate( self, angle: float, axis: Vector3DLike = OUT, *, about_point: Point3DLike | None = None, about_edge: Vector3DLike | None = None, ) -> Self: self.rotate_sheen_direction(angle, axis) super().rotate(angle, axis, about_point=about_point, about_edge=about_edge) return self def scale_handle_to_anchor_distances(self, factor: float) -> Self: """If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d away from A, but so that the line from A to H doesn't change. This is mostly useful in the context of applying a (differentiable) function, to preserve tangency properties. One would pull all the handles closer to their anchors, apply the function then push them out again. Parameters ---------- factor The factor used for scaling. Returns ------- :class:`VMobject` ``self`` """ for submob in self.family_members_with_points(): if len(submob.points) < self.n_points_per_cubic_curve: # The case that a bezier quad is not complete (there is no bezier curve as there is not enough control points.) continue a1, h1, h2, a2 = submob.get_anchors_and_handles() a1_to_h1 = h1 - a1 a2_to_h2 = h2 - a2 new_h1 = a1 + factor * a1_to_h1 new_h2 = a2 + factor * a2_to_h2 submob.set_anchors_and_handles(a1, new_h1, new_h2, a2) return self # def consider_points_equals(self, p0: Point3DLike, p1: Point3DLike) -> bool: return np.allclose(p0, p1, atol=self.tolerance_for_point_equality) def consider_points_equals_2d(self, p0: Point2DLike, p1: Point2DLike) -> bool: """Determine if two points are close enough to be considered equal. This uses the algorithm from np.isclose(), but expanded here for the 2D point case. NumPy is overkill for such a small question. Parameters ---------- p0 first point p1 second point Returns ------- bool whether two points considered close. """ rtol = 1.0e-5 # default from np.isclose() atol = self.tolerance_for_point_equality if abs(p0[0] - p1[0]) > atol + rtol * abs(p1[0]): return False return abs(p0[1] - p1[1]) <= atol + rtol * abs(p1[1]) # Information about line def get_cubic_bezier_tuples_from_points( self, points: CubicBezierPathLike ) -> CubicBezierPoints_Array: return np.array(self.gen_cubic_bezier_tuples_from_points(points)) def gen_cubic_bezier_tuples_from_points( self, points: CubicBezierPathLike ) -> tuple[CubicBezierPointsLike, ...]: """Returns the bezier tuples from an array of points. self.points is a list of the anchors and handles of the bezier curves of the mobject (ie [anchor1, handle1, handle2, anchor2, anchor3 ..]) This algorithm basically retrieve them by taking an element every n, where n is the number of control points of the bezier curve. Parameters ---------- points Points from which control points will be extracted. Returns ------- tuple Bezier control points. """ nppcc = self.n_points_per_cubic_curve remainder = len(points) % nppcc points = points[: len(points) - remainder] # Basically take every nppcc element. return tuple(points[i : i + nppcc] for i in range(0, len(points), nppcc)) def get_cubic_bezier_tuples(self) -> CubicBezierPoints_Array: return self.get_cubic_bezier_tuples_from_points(self.points) def _gen_subpaths_from_points( self, points: CubicBezierPath, filter_func: Callable[[int], bool], ) -> Iterable[CubicSpline]: """Given an array of points defining the bezier curves of the vmobject, return subpaths formed by these points. Here, Two bezier curves form a path if at least two of their anchors are evaluated True by the relation defined by filter_func. The algorithm every bezier tuple (anchors and handles) in ``self.points`` (by regrouping each n elements, where n is the number of points per cubic curve)), and evaluate the relation between two anchors with filter_func. NOTE : The filter_func takes an int n as parameter, and will evaluate the relation between points[n] and points[n - 1]. This should probably be changed so the function takes two points as parameters. Parameters ---------- points points defining the bezier curve. filter_func Filter-func defining the relation. Returns ------- Iterable[CubicSpline] subpaths formed by the points. """ nppcc = self.n_points_per_cubic_curve filtered = filter(filter_func, range(nppcc, len(points), nppcc)) split_indices = [0] + list(filtered) + [len(points)] return ( points[i1:i2] for i1, i2 in zip(split_indices[:-1], split_indices[1:], strict=True) if (i2 - i1) >= nppcc ) def get_subpaths_from_points(self, points: CubicBezierPath) -> list[CubicSpline]: return list( self._gen_subpaths_from_points( points, lambda n: not self.consider_points_equals(points[n - 1], points[n]), ), ) def gen_subpaths_from_points_2d( self, points: CubicBezierPath ) -> Iterable[CubicSpline]: return self._gen_subpaths_from_points( points, lambda n: not self.consider_points_equals_2d(points[n - 1], points[n]), ) def get_subpaths(self) -> list[CubicSpline]: """Returns subpaths formed by the curves of the VMobject. Subpaths are ranges of curves with each pair of consecutive curves having their end/start points coincident. Returns ------- list[CubicSpline] subpaths. """ return self.get_subpaths_from_points(self.points) def get_nth_curve_points(self, n: int) -> CubicBezierPoints: """Returns the points defining the nth curve of the vmobject. Parameters ---------- n index of the desired bezier curve. Returns ------- CubicBezierPoints points defining the nth bezier curve (anchors, handles) """ assert n < self.get_num_curves() nppcc = self.n_points_per_cubic_curve return self.points[nppcc * n : nppcc * (n + 1)] def get_nth_curve_function(self, n: int) -> Callable[[float], Point3D]: """Returns the expression of the nth curve. Parameters ---------- n index of the desired curve. Returns ------- Callable[float, Point3D] expression of the nth bezier curve. """ return bezier(self.get_nth_curve_points(n)) def get_nth_curve_length_pieces( self, n: int, sample_points: int | None = None, ) -> npt.NDArray[ManimFloat]: """Returns the array of short line lengths used for length approximation. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- The short length-pieces of the nth curve. """ if sample_points is None: sample_points = 10 curve = self.get_nth_curve_function(n) points = np.array([curve(a) for a in np.linspace(0, 1, sample_points)]) diffs = points[1:] - points[:-1] norms = np.linalg.norm(diffs, axis=1) return norms def get_nth_curve_length( self, n: int, sample_points: int | None = None, ) -> float: """Returns the (approximate) length of the nth curve. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- length : :class:`float` The length of the nth curve. """ _, length = self.get_nth_curve_function_with_length(n, sample_points) return length def get_nth_curve_function_with_length( self, n: int, sample_points: int | None = None, ) -> tuple[Callable[[float], Point3D], float]: """Returns the expression of the nth curve along with its (approximate) length. Parameters ---------- n The index of the desired curve. sample_points The number of points to sample to find the length. Returns ------- curve : Callable[[float], Point3D] The function for the nth curve. 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) return curve, length def get_num_curves(self) -> int: """Returns the number of curves of the vmobject. Returns ------- int number of curves of the vmobject. """ nppcc = self.n_points_per_cubic_curve return len(self.points) // nppcc def get_curve_functions( self, ) -> Iterable[Callable[[float], Point3D]]: """Gets the functions for the curves of the mobject. Returns ------- Iterable[Callable[[float], Point3D]] The functions for the curves. """ num_curves = self.get_num_curves() for n in range(num_curves): yield self.get_nth_curve_function(n) def get_curve_functions_with_lengths( self, **kwargs ) -> Iterable[tuple[Callable[[float], Point3D], float]]: """Gets the functions and lengths of the curves for the mobject. Parameters ---------- **kwargs The keyword arguments passed to :meth:`get_nth_curve_function_with_length` Returns ------- Iterable[tuple[Callable[[float], Point3D], float]] The functions and lengths of the curves. """ num_curves = self.get_num_curves() for n in range(num_curves): yield self.get_nth_curve_function_with_length(n, **kwargs) def point_from_proportion(self, alpha: float) -> Point3D: """Gets the point at a proportion along the path of the :class:`VMobject`. Parameters ---------- alpha The proportion along the the path of the :class:`VMobject`. Returns ------- :class:`numpy.ndarray` The point on the :class:`VMobject`. Raises ------ :exc:`ValueError` If ``alpha`` is not between 0 and 1. :exc:`Exception` If the :class:`VMobject` has no points. Example ------- .. manim:: PointFromProportion :save_last_frame: class PointFromProportion(Scene): def construct(self): line = Line(2*DL, 2*UR) self.add(line) colors = (RED, BLUE, YELLOW) proportions = (1/4, 1/2, 3/4) for color, proportion in zip(colors, proportions): self.add(Dot(color=color).move_to( line.point_from_proportion(proportion) )) """ if alpha < 0 or alpha > 1: raise ValueError(f"Alpha {alpha} not between 0 and 1.") self.throw_error_if_no_points() if alpha == 1: return self.points[-1] curves_and_lengths = tuple(self.get_curve_functions_with_lengths()) target_length = alpha * sum(length for _, length in curves_and_lengths) current_length = 0 for curve, length in curves_and_lengths: if current_length + length >= target_length: if length != 0: residue = (target_length - current_length) / length else: residue = 0 return curve(residue) current_length += length raise Exception( "Not sure how you reached here, please file a bug report at https://github.com/ManimCommunity/manim/issues/new/choose" ) def proportion_from_point( self, point: Point3DLike, ) -> float: """Returns the proportion along the path of the :class:`VMobject` a particular given point is at. Parameters ---------- point The Cartesian coordinates of the point which may or may not lie on the :class:`VMobject` Returns ------- float The proportion along the path of the :class:`VMobject`. Raises ------ :exc:`ValueError` If ``point`` does not lie on the curve. :exc:`Exception` If the :class:`VMobject` has no points. """ self.throw_error_if_no_points() # Iterate over each bezier curve that the ``VMobject`` is composed of, checking # if the point lies on that curve. If it does not lie on that curve, add # the whole length of the curve to ``target_length`` and move onto the next # curve. If the point does lie on the curve, add how far along the curve # the point is to ``target_length``. # Then, divide ``target_length`` by the total arc length of the shape to get # the proportion along the ``VMobject`` the point is at. num_curves = self.get_num_curves() total_length = self.get_arc_length() target_length = 0 for n in range(num_curves): control_points = self.get_nth_curve_points(n) length = self.get_nth_curve_length(n) proportions_along_bezier = proportions_along_bezier_curve_for_point( point, control_points, ) if len(proportions_along_bezier) > 0: proportion_along_nth_curve = max(proportions_along_bezier) target_length += length * proportion_along_nth_curve break target_length += length else: raise ValueError(f"Point {point} does not lie on this curve.") alpha = target_length / total_length return alpha def get_anchors_and_handles(self) -> list[Point3D_Array]: """Returns anchors1, handles1, handles2, anchors2, where (anchors1[i], handles1[i], handles2[i], anchors2[i]) will be four points defining a cubic bezier curve for any i in range(0, len(anchors1)) Returns ------- `list[Point3D_Array]` Iterable of the anchors and handles. """ nppcc = self.n_points_per_cubic_curve return [self.points[i::nppcc] for i in range(nppcc)] def get_start_anchors(self) -> Point3D_Array: """Returns the start anchors of the bezier curves. Returns ------- Point3D_Array Starting anchors """ return self.points[:: self.n_points_per_cubic_curve] def get_end_anchors(self) -> Point3D_Array: """Return the end anchors of the bezier curves. Returns ------- Point3D_Array Starting anchors """ nppcc = self.n_points_per_cubic_curve return self.points[nppcc - 1 :: nppcc] def get_anchors(self) -> list[Point3D]: """Returns the anchors of the curves forming the VMobject. Returns ------- Point3D_Array The anchors. """ if self.points.shape[0] == 1: return self.points s = self.get_start_anchors() e = self.get_end_anchors() return list(it.chain.from_iterable(zip(s, e, strict=True))) def get_points_defining_boundary(self) -> Point3D_Array: # Probably returns all anchors, but this is weird regarding the name of the method. return np.array( tuple(it.chain(*(sm.get_anchors() for sm in self.get_family()))) ) def get_arc_length(self, sample_points_per_curve: int | None = None) -> float: """Return the approximated length of the whole curve. Parameters ---------- sample_points_per_curve Number of sample points per curve used to approximate the length. More points result in a better approximation. Returns ------- float The length of the :class:`VMobject`. """ return sum( length for _, length in self.get_curve_functions_with_lengths( sample_points=sample_points_per_curve, ) ) # Alignment def align_points(self, vmobject: VMobject) -> Self: """Adds points to self and vmobject so that they both have the same number of subpaths, with corresponding subpaths each containing the same number of points. Points are added either by subdividing curves evenly along the subpath, or by creating new subpaths consisting of a single point repeated. Parameters ---------- vmobject The object to align points with. Returns ------- :class:`VMobject` ``self`` See also -------- :meth:`~.Mobject.interpolate`, :meth:`~.Mobject.align_data` """ self.align_rgbas(vmobject) # TODO: This shortcut can be a bit over eager. What if they have the same length, but different subpath lengths? if self.get_num_points() == vmobject.get_num_points(): return for mob in self, vmobject: # If there are no points, add one to # wherever the "center" is if mob.has_no_points(): mob.start_new_path(mob.get_center()) # If there's only one point, turn it into # a null curve if mob.has_new_path_started(): mob.add_line_to(mob.get_last_point()) # Figure out what the subpaths are subpaths1 = self.get_subpaths() subpaths2 = vmobject.get_subpaths() n_subpaths = max(len(subpaths1), len(subpaths2)) # Start building new ones new_path1 = np.zeros((0, self.dim)) new_path2 = np.zeros((0, self.dim)) nppcc = self.n_points_per_cubic_curve def get_nth_subpath(path_list, n): if n >= len(path_list): # Create a null path at the very end if len(path_list) == 0: return np.tile(np.zeros(3), (nppcc, 1)) return np.tile(path_list[-1][-1], (nppcc, 1)) path = path_list[n] # Check for useless points at the end of the path and remove them # https://github.com/ManimCommunity/manim/issues/1959 while len(path) > nppcc: # If the last nppc points are all equal to the preceding point if self.consider_points_equals(path[-nppcc:], path[-nppcc - 1]): path = path[:-nppcc] else: break return path for n in range(n_subpaths): # For each pair of subpaths, add points until they are the same length sp1 = get_nth_subpath(subpaths1, n) sp2 = get_nth_subpath(subpaths2, n) diff1 = max(0, (len(sp2) - len(sp1)) // nppcc) diff2 = max(0, (len(sp1) - len(sp2)) // nppcc) sp1 = self.insert_n_curves_to_point_list(diff1, sp1) sp2 = self.insert_n_curves_to_point_list(diff2, sp2) new_path1 = np.append(new_path1, sp1, axis=0) new_path2 = np.append(new_path2, sp2, axis=0) self.set_points(new_path1) vmobject.set_points(new_path2) return self def insert_n_curves(self, n: int) -> Self: """Inserts n curves to the bezier curves of the vmobject. Parameters ---------- n Number of curves to insert. Returns ------- :class:`VMobject` ``self`` """ new_path_point = None if self.has_new_path_started(): new_path_point = self.get_last_point() new_points = self.insert_n_curves_to_point_list(n, self.points) self.set_points(new_points) if new_path_point is not None: self.append_points([new_path_point]) return self def insert_n_curves_to_point_list( self, n: int, points: BezierPathLike ) -> BezierPath: """Given an array of k points defining a bezier curves (anchors and handles), returns points defining exactly k + n bezier curves. Parameters ---------- n Number of desired curves. points Starting points. Returns ------- Points generated. """ if len(points) == 1: nppcc = self.n_points_per_cubic_curve return np.repeat(points, nppcc * n, 0) bezier_tuples = self.get_cubic_bezier_tuples_from_points(points) current_number_of_curves = len(bezier_tuples) new_number_of_curves = current_number_of_curves + n new_bezier_tuples = bezier_remap(bezier_tuples, new_number_of_curves) new_points = new_bezier_tuples.reshape(-1, 3) return new_points def align_rgbas(self, vmobject: VMobject) -> Self: attrs = ["fill_rgbas", "stroke_rgbas", "background_stroke_rgbas"] for attr in attrs: a1 = getattr(self, attr) a2 = getattr(vmobject, attr) if len(a1) > len(a2): new_a2 = stretch_array_to_length(a2, len(a1)) setattr(vmobject, attr, new_a2) elif len(a2) > len(a1): new_a1 = stretch_array_to_length(a1, len(a2)) setattr(self, attr, new_a1) return self def get_point_mobject(self, center: Point3DLike | None = None) -> VectorizedPoint: if center is None: center = self.get_center() point = VectorizedPoint(center) point.match_style(self) return point def interpolate_color( self, mobject1: VMobject, mobject2: VMobject, alpha: float ) -> None: attrs = [ "fill_rgbas", "stroke_rgbas", "background_stroke_rgbas", "stroke_width", "background_stroke_width", "sheen_direction", "sheen_factor", ] for attr in attrs: setattr( self, attr, interpolate(getattr(mobject1, attr), getattr(mobject2, attr), alpha), ) if alpha == 1.0: val = getattr(mobject2, attr) if isinstance(val, np.ndarray): val = val.copy() setattr(self, attr, val) def pointwise_become_partial( self, vmobject: VMobject, a: float, b: float, ) -> Self: """Given a 2nd :class:`.VMobject` ``vmobject``, a lower bound ``a`` and an upper bound ``b``, modify this :class:`.VMobject`'s points to match the portion of the Bézier spline described by ``vmobject.points`` with the parameter ``t`` between ``a`` and ``b``. Parameters ---------- vmobject The :class:`.VMobject` that will serve as a model. a The lower bound for ``t``. b The upper bound for ``t`` Returns ------- :class:`.VMobject` The :class:`.VMobject` itself, after the transformation. Raises ------ TypeError If ``vmobject`` is not an instance of :class:`VMobject`. """ if not isinstance(vmobject, VMobject): raise TypeError( f"Expected a VMobject, got value {vmobject} of type " f"{type(vmobject).__name__}." ) # Partial curve includes three portions: # - A middle section, which matches the curve exactly. # - A start, which is some ending portion of an inner cubic. # - An end, which is the starting portion of a later inner cubic. if a <= 0 and b >= 1: self.set_points(vmobject.points) return self num_curves = vmobject.get_num_curves() if num_curves == 0: return self # The following two lines will compute which Bézier curves of the given Mobject must be processed. # The residue indicates the proportion of the selected Bézier curve which must be selected. # # Example: if num_curves is 10, a is 0.34 and b is 0.78, then: # - lower_index is 3 and lower_residue is 0.4, which means the algorithm will look at the 3rd Bézier # and select its part which ranges from t=0.4 to t=1. # - upper_index is 7 and upper_residue is 0.8, which means the algorithm will look at the 7th Bézier # and select its part which ranges from t=0 to t=0.8. lower_index, lower_residue = integer_interpolate(0, num_curves, a) upper_index, upper_residue = integer_interpolate(0, num_curves, b) nppc = self.n_points_per_curve # Copy vmobject.points if vmobject is self to prevent unintended in-place modification vmobject_points = ( vmobject.points.copy() if self is vmobject else vmobject.points ) # If both indices coincide, get a part of a single Bézier curve. if lower_index == upper_index: # Look at the "lower_index"-th Bézier curve and select its part from # t=lower_residue to t=upper_residue. self.points = partial_bezier_points( vmobject_points[nppc * lower_index : nppc * (lower_index + 1)], lower_residue, upper_residue, ) else: # Allocate space for (upper_index-lower_index+1) Bézier curves. self.points = np.empty((nppc * (upper_index - lower_index + 1), self.dim)) # Look at the "lower_index"-th Bezier curve and select its part from # t=lower_residue to t=1. This is the first curve in self.points. self.points[:nppc] = partial_bezier_points( vmobject_points[nppc * lower_index : nppc * (lower_index + 1)], lower_residue, 1, ) # If there are more curves between the "lower_index"-th and the # "upper_index"-th Béziers, add them all to self.points. self.points[nppc:-nppc] = vmobject_points[ nppc * (lower_index + 1) : nppc * upper_index ] # Look at the "upper_index"-th Bézier curve and select its part from # t=0 to t=upper_residue. This is the last curve in self.points. self.points[-nppc:] = partial_bezier_points( vmobject_points[nppc * upper_index : nppc * (upper_index + 1)], 0, upper_residue, ) return self def get_subcurve(self, a: float, b: float) -> Self: """Returns the subcurve of the VMobject between the interval [a, b]. The curve is a VMobject itself. Parameters ---------- a The lower bound. b The upper bound. Returns ------- VMobject The subcurve between of [a, b] """ if self.is_closed() and a > b: vmob = self.copy() vmob.pointwise_become_partial(self, a, 1) vmob2 = self.copy() vmob2.pointwise_become_partial(self, 0, b) vmob.append_vectorized_mobject(vmob2) else: vmob = self.copy() vmob.pointwise_become_partial(self, a, b) return vmob def get_direction(self) -> Literal["CW", "CCW"]: """Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise. Examples -------- The default direction of a :class:`~.Circle` is counterclockwise:: >>> from manim import Circle >>> Circle().get_direction() 'CCW' Returns ------- :class:`str` Either ``"CW"`` or ``"CCW"``. """ return shoelace_direction(self.get_start_anchors()) def reverse_direction(self) -> Self: """Reverts the point direction by inverting the point order. Returns ------- :class:`VMobject` Returns self. Examples -------- .. manim:: ChangeOfDirection class ChangeOfDirection(Scene): def construct(self): ccw = RegularPolygon(5) ccw.shift(LEFT) cw = RegularPolygon(5) cw.shift(RIGHT).reverse_direction() self.play(Create(ccw), Create(cw), run_time=4) """ self.points = self.points[::-1] return self def force_direction(self, target_direction: Literal["CW", "CCW"]) -> Self: """Makes sure that points are either directed clockwise or counterclockwise. Parameters ---------- target_direction Either ``"CW"`` or ``"CCW"``. """ if target_direction not in ("CW", "CCW"): raise ValueError('Invalid input for force_direction. Use "CW" or "CCW"') if self.get_direction() != target_direction: # Since we already assured the input is CW or CCW, # and the directions don't match, we just reverse self.reverse_direction() return self class VGroup(VMobject, metaclass=ConvertToOpenGL): """A group of vectorized mobjects. This can be used to group multiple :class:`~.VMobject` instances together in order to scale, move, ... them together. Notes ----- When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group. Examples -------- To add :class:`~.VMobject`s to a :class:`~.VGroup`, you can either use the :meth:`~.VGroup.add` method, or use the `+` and `+=` operators. Similarly, you can subtract elements of a VGroup via :meth:`~.VGroup.remove` method, or `-` and `-=` operators: >>> from manim import Triangle, Square, VGroup >>> vg = VGroup() >>> triangle, square = Triangle(), Square() >>> vg.add(triangle) VGroup(Triangle) >>> vg + square # a new VGroup is constructed VGroup(Triangle, Square) >>> vg # not modified VGroup(Triangle) >>> vg += square >>> vg # modifies vg VGroup(Triangle, Square) >>> vg.remove(triangle) VGroup(Square) >>> vg - square # a new VGroup is constructed VGroup() >>> vg # not modified VGroup(Square) >>> vg -= square >>> vg # modifies vg VGroup() .. manim:: ArcShapeIris :save_last_frame: class ArcShapeIris(Scene): def construct(self): colors = [DARK_BROWN, BLUE_E, BLUE_D, BLUE_A, TEAL_B, GREEN_B, YELLOW_E] radius = [1 + rad * 0.1 for rad in range(len(colors))] circles_group = VGroup() # zip(radius, color) makes the iterator [(radius[i], color[i]) for i in range(radius)] circles_group.add(*[Circle(radius=rad, stroke_width=10, color=col) for rad, col in zip(radius, colors)]) self.add(circles_group) """ def __init__( self, *vmobjects: VMobject | Iterable[VMobject], **kwargs: Any ) -> None: super().__init__(**kwargs) self.add(*vmobjects) def __repr__(self) -> str: return f"{self.__class__.__name__}({', '.join(str(mob) for mob in self.submobjects)})" def __str__(self) -> str: return ( f"{self.__class__.__name__} of {len(self.submobjects)} " f"submobject{'s' if len(self.submobjects) > 0 else ''}" ) def add( self, *vmobjects: VMobject | Iterable[VMobject], ) -> Self: """Checks if all passed elements are an instance, or iterables of VMobject and then adds them to submobjects Parameters ---------- vmobjects List or iterable of VMobjects to add Returns ------- :class:`VGroup` Raises ------ TypeError If one element of the list, or iterable is not an instance of VMobject Examples -------- The following example shows how to add individual or multiple `VMobject` instances through the `VGroup` constructor and its `.add()` method. .. manim:: AddToVGroup class AddToVGroup(Scene): def construct(self): circle_red = Circle(color=RED) circle_green = Circle(color=GREEN) circle_blue = Circle(color=BLUE) circle_red.shift(LEFT) circle_blue.shift(RIGHT) gr = VGroup(circle_red, circle_green) gr2 = VGroup(circle_blue) # Constructor uses add directly self.add(gr,gr2) self.wait() gr += gr2 # Add group to another self.play( gr.animate.shift(DOWN), ) gr -= gr2 # Remove group self.play( # Animate groups separately gr.animate.shift(LEFT), gr2.animate.shift(UP), ) self.play( #Animate groups without modification (gr+gr2).animate.shift(RIGHT) ) self.play( # Animate group without component (gr-circle_red).animate.shift(RIGHT) ) A `VGroup` can be created using iterables as well. Keep in mind that all generated values from an iterable must be an instance of `VMobject`. This is demonstrated below: .. manim:: AddIterableToVGroupExample :save_last_frame: class AddIterableToVGroupExample(Scene): def construct(self): v = VGroup( Square(), # Singular VMobject instance [Circle(), Triangle()], # List of VMobject instances Dot(), (Dot() for _ in range(2)), # Iterable that generates VMobjects ) v.arrange() self.add(v) To facilitate this, the iterable is unpacked before its individual instances are added to the `VGroup`. As a result, when you index a `VGroup`, you will never get back an iterable. Instead, you will always receive `VMobject` instances, including those that were part of the iterable/s that you originally added to the `VGroup`. """ def get_type_error_message(invalid_obj, invalid_indices): return ( f"Only values of type {vmobject_render_type.__name__} can be added " "as submobjects of VGroup, but the value " f"{repr(invalid_obj)} (at index {invalid_indices[1]} of " f"parameter {invalid_indices[0]}) is of type " f"{type(invalid_obj).__name__}." ) vmobject_render_type = ( OpenGLVMobject if config.renderer == RendererType.OPENGL else VMobject ) valid_vmobjects = [] for i, vmobject in enumerate(vmobjects): if isinstance(vmobject, vmobject_render_type): valid_vmobjects.append(vmobject) elif isinstance(vmobject, Iterable) and not isinstance( vmobject, (Mobject, OpenGLMobject) ): for j, subvmobject in enumerate(vmobject): if not isinstance(subvmobject, vmobject_render_type): raise TypeError(get_type_error_message(subvmobject, (i, j))) valid_vmobjects.append(subvmobject) elif isinstance(vmobject, Iterable) and isinstance( vmobject, (Mobject, OpenGLMobject) ): raise TypeError( f"{get_type_error_message(vmobject, (i, 0))} " "You can try adding this value into a Group instead." ) else: raise TypeError(get_type_error_message(vmobject, (i, 0))) return super().add(*valid_vmobjects) def __add__(self, vmobject: VMobject) -> Self: return VGroup(*self.submobjects, vmobject) def __iadd__(self, vmobject: VMobject) -> Self: return self.add(vmobject) def __sub__(self, vmobject: VMobject) -> Self: copy = VGroup(*self.submobjects) copy.remove(vmobject) return copy def __isub__(self, vmobject: VMobject) -> Self: return self.remove(vmobject) def __setitem__(self, key: int, value: VMobject | Sequence[VMobject]) -> None: """Override the [] operator for item assignment. Parameters ---------- key The index of the submobject to be assigned value The vmobject value to assign to the key Returns ------- None Tests ----- Check that item assignment does not raise error:: >>> vgroup = VGroup(VMobject()) >>> new_obj = VMobject() >>> vgroup[0] = new_obj """ self._assert_valid_submobjects(tuplify(value)) self.submobjects[key] = value def __getitem__(self, key: int | slice) -> VMobject: if isinstance(key, slice): return VGroup(self.submobjects[key]) return self.submobjects[key] class VDict(VMobject, metaclass=ConvertToOpenGL): """A VGroup-like class, also offering submobject access by key, like a python dict Parameters ---------- mapping_or_iterable The parameter specifying the key-value mapping of keys and mobjects. show_keys Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. Defaults to False. kwargs Other arguments to be passed to `Mobject`. Attributes ---------- show_keys : :class:`bool` Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. When displayed, the key is towards the left of the mobject. Defaults to False. submob_dict : :class:`dict` Is the actual python dictionary that is used to bind the keys to the mobjects. Examples -------- .. manim:: ShapesWithVDict class ShapesWithVDict(Scene): def construct(self): square = Square().set_color(RED) circle = Circle().set_color(YELLOW).next_to(square, UP) # create dict from list of tuples each having key-mobject pair pairs = [("s", square), ("c", circle)] my_dict = VDict(pairs, show_keys=True) # display it just like a VGroup self.play(Create(my_dict)) self.wait() text = Tex("Some text").set_color(GREEN).next_to(square, DOWN) # add a key-value pair by wrapping it in a single-element list of tuple # after attrs branch is merged, it will be easier like `.add(t=text)` my_dict.add([("t", text)]) self.wait() rect = Rectangle().next_to(text, DOWN) # can also do key assignment like a python dict my_dict["r"] = rect # access submobjects like a python dict my_dict["t"].set_color(PURPLE) self.play(my_dict["t"].animate.scale(3)) self.wait() # also supports python dict styled reassignment my_dict["t"] = Tex("Some other text").set_color(BLUE) self.wait() # remove submobject by key my_dict.remove("t") self.wait() self.play(Uncreate(my_dict["s"])) self.wait() self.play(FadeOut(my_dict["c"])) self.wait() self.play(FadeOut(my_dict["r"], shift=DOWN)) self.wait() # you can also make a VDict from an existing dict of mobjects plain_dict = { 1: Integer(1).shift(DOWN), 2: Integer(2).shift(2 * DOWN), 3: Integer(3).shift(3 * DOWN), } vdict_from_plain_dict = VDict(plain_dict) vdict_from_plain_dict.shift(1.5 * (UP + LEFT)) self.play(Create(vdict_from_plain_dict)) # you can even use zip vdict_using_zip = VDict(zip(["s", "c", "r"], [Square(), Circle(), Rectangle()])) vdict_using_zip.shift(1.5 * RIGHT) self.play(Create(vdict_using_zip)) self.wait() """ def __init__( self, mapping_or_iterable: ( Mapping[Hashable, VMobject] | Iterable[tuple[Hashable, VMobject]] ) = {}, show_keys: bool = False, **kwargs, ) -> None: super().__init__(**kwargs) self.show_keys = show_keys self.submob_dict = {} self.add(mapping_or_iterable) def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self.submob_dict)})" def add( self, mapping_or_iterable: ( Mapping[Hashable, VMobject] | Iterable[tuple[Hashable, VMobject]] ), ) -> Self: """Adds the key-value pairs to the :class:`VDict` object. Also, it internally adds the value to the `submobjects` :class:`list` of :class:`~.Mobject`, which is responsible for actual on-screen display. Parameters --------- mapping_or_iterable The parameter specifying the key-value mapping of keys and mobjects. Returns ------- :class:`VDict` Returns the :class:`VDict` object on which this method was called. Examples -------- Normal usage:: square_obj = Square() my_dict.add([("s", square_obj)]) """ for key, value in dict(mapping_or_iterable).items(): self.add_key_value_pair(key, value) return self def remove(self, key: Hashable) -> Self: """Removes the mobject from the :class:`VDict` object having the key `key` Also, it internally removes the mobject from the `submobjects` :class:`list` of :class:`~.Mobject`, (which is responsible for removing it from the screen) Parameters ---------- key The key of the submoject to be removed. Returns ------- :class:`VDict` Returns the :class:`VDict` object on which this method was called. Examples -------- Normal usage:: my_dict.remove("square") """ if key not in self.submob_dict: raise KeyError(f"The given key '{key!s}' is not present in the VDict") super().remove(self.submob_dict[key]) del self.submob_dict[key] return self def __getitem__(self, key: Hashable): """Override the [] operator for item retrieval. Parameters ---------- key The key of the submoject to be accessed Returns ------- :class:`VMobject` The submobject corresponding to the key `key` Examples -------- Normal usage:: self.play(Create(my_dict["s"])) """ submob = self.submob_dict[key] return submob def __setitem__(self, key: Hashable, value: VMobject) -> None: """Override the [] operator for item assignment. Parameters ---------- key The key of the submoject to be assigned value The submobject to bind the key to Returns ------- None Examples -------- Normal usage:: square_obj = Square() my_dict["sq"] = square_obj """ if key in self.submob_dict: self.remove(key) self.add([(key, value)]) def __delitem__(self, key: Hashable): """Override the del operator for deleting an item. Parameters ---------- key The key of the submoject to be deleted Returns ------- None Examples -------- :: >>> from manim import * >>> my_dict = VDict({'sq': Square()}) >>> 'sq' in my_dict True >>> del my_dict['sq'] >>> 'sq' in my_dict False Notes ----- Removing an item from a VDict does not remove that item from any Scene that the VDict is part of. """ del self.submob_dict[key] def __contains__(self, key: Hashable): """Override the in operator. Parameters ---------- key The key to check membership of. Returns ------- :class:`bool` Examples -------- :: >>> from manim import * >>> my_dict = VDict({'sq': Square()}) >>> 'sq' in my_dict True """ return key in self.submob_dict def get_all_submobjects(self) -> list[list]: """To get all the submobjects associated with a particular :class:`VDict` object Returns ------- :class:`dict_values` All the submobjects associated with the :class:`VDict` object Examples -------- Normal usage:: for submob in my_dict.get_all_submobjects(): self.play(Create(submob)) """ submobjects = self.submob_dict.values() return submobjects def add_key_value_pair(self, key: Hashable, value: VMobject) -> None: """A utility function used by :meth:`add` to add the key-value pair to :attr:`submob_dict`. Not really meant to be used externally. Parameters ---------- key The key of the submobject to be added. value The mobject associated with the key Returns ------- None Raises ------ TypeError If the value is not an instance of VMobject Examples -------- Normal usage:: square_obj = Square() self.add_key_value_pair("s", square_obj) """ self._assert_valid_submobjects([value]) mob = value if self.show_keys: # This import is here and not at the top to avoid circular import from manim.mobject.text.tex_mobject import Tex key_text = Tex(str(key)).next_to(value, LEFT) mob.add(key_text) self.submob_dict[key] = mob super().add(value) class VectorizedPoint(VMobject, metaclass=ConvertToOpenGL): def __init__( self, location: Point3DLike = ORIGIN, color: ManimColor = BLACK, fill_opacity: float = 0, stroke_width: float = 0, artificial_width: float = 0.01, artificial_height: float = 0.01, **kwargs, ) -> None: self.artificial_width = artificial_width self.artificial_height = artificial_height super().__init__( color=color, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs, ) self.set_points(np.array([location])) basecls = OpenGLVMobject if config.renderer == RendererType.OPENGL else VMobject @basecls.width.getter def width(self) -> float: return self.artificial_width @basecls.height.getter def height(self) -> float: return self.artificial_height def get_location(self) -> Point3D: return np.array(self.points[0]) def set_location(self, new_loc: Point3D): self.set_points(np.array([new_loc])) class CurvesAsSubmobjects(VGroup): """Convert a curve's elements to submobjects. Examples -------- .. manim:: LineGradientExample :save_last_frame: class LineGradientExample(Scene): def construct(self): curve = ParametricFunction(lambda t: [t, np.sin(t), 0], t_range=[-PI, PI, 0.01], stroke_width=10) new_curve = CurvesAsSubmobjects(curve) new_curve.set_color_by_gradient(BLUE, RED) self.add(new_curve.shift(UP), curve) """ def __init__(self, vmobject: VMobject, **kwargs) -> None: super().__init__(**kwargs) tuples = vmobject.get_cubic_bezier_tuples() for tup in tuples: part = VMobject() part.set_points(tup) part.match_style(vmobject) self.add(part) def point_from_proportion(self, alpha: float) -> Point3D: """Gets the point at a proportion along the path of the :class:`CurvesAsSubmobjects`. Parameters ---------- alpha The proportion along the the path of the :class:`CurvesAsSubmobjects`. Returns ------- :class:`numpy.ndarray` The point on the :class:`CurvesAsSubmobjects`. Raises ------ :exc:`ValueError` If ``alpha`` is not between 0 and 1. :exc:`Exception` If the :class:`CurvesAsSubmobjects` has no submobjects, or no submobject has points. """ if alpha < 0 or alpha > 1: raise ValueError(f"Alpha {alpha} not between 0 and 1.") self._throw_error_if_no_submobjects() submobjs_with_pts = self._get_submobjects_with_points() if alpha == 1: return submobjs_with_pts[-1].points[-1] submobjs_arc_lengths = tuple( part.get_arc_length() for part in submobjs_with_pts ) total_length = sum(submobjs_arc_lengths) target_length = alpha * total_length current_length = 0 for i, part in enumerate(submobjs_with_pts): part_length = submobjs_arc_lengths[i] if current_length + part_length >= target_length: residue = (target_length - current_length) / part_length return part.point_from_proportion(residue) current_length += part_length def _throw_error_if_no_submobjects(self): if len(self.submobjects) == 0: caller_name = sys._getframe(1).f_code.co_name raise Exception( f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject with no submobjects" ) def _get_submobjects_with_points(self): submobjs_with_pts = tuple( part for part in self.submobjects if len(part.points) > 0 ) if len(submobjs_with_pts) == 0: caller_name = sys._getframe(1).f_code.co_name raise Exception( f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject whose submobjects have no points" ) return submobjs_with_pts class DashedVMobject(VMobject, metaclass=ConvertToOpenGL): """A :class:`VMobject` composed of dashes instead of lines. Parameters ---------- vmobject The object that will get dashed num_dashes Number of dashes to add. dashed_ratio Ratio of dash to empty space. dash_offset Shifts the starting point of dashes along the path. Value 1 shifts by one full dash length. equal_lengths If ``True``, dashes will be (approximately) equally long. If ``False``, dashes will be split evenly in the curve's input t variable (legacy behavior). Examples -------- .. manim:: DashedVMobjectExample :save_last_frame: class DashedVMobjectExample(Scene): def construct(self): r = 0.5 top_row = VGroup() # Increasing num_dashes for dashes in range(1, 12): circ = DashedVMobject(Circle(radius=r, color=WHITE), num_dashes=dashes) top_row.add(circ) middle_row = VGroup() # Increasing dashed_ratio for ratio in np.arange(1 / 11, 1, 1 / 11): circ = DashedVMobject( Circle(radius=r, color=WHITE), dashed_ratio=ratio ) middle_row.add(circ) func1 = FunctionGraph(lambda t: t**5,[-1,1],color=WHITE) func_even = DashedVMobject(func1,num_dashes=6,equal_lengths=True) func_stretched = DashedVMobject(func1, num_dashes=6, equal_lengths=False) bottom_row = VGroup(func_even,func_stretched) top_row.arrange(buff=0.3) middle_row.arrange() bottom_row.arrange(buff=1) everything = VGroup(top_row, middle_row, bottom_row).arrange(DOWN, buff=1) self.add(everything) """ def __init__( self, vmobject: VMobject, num_dashes: int = 15, dashed_ratio: float = 0.5, dash_offset: float = 0, color: ManimColor = WHITE, equal_lengths: bool = True, **kwargs, ) -> None: self.dashed_ratio = dashed_ratio self.num_dashes = num_dashes super().__init__(color=color, **kwargs) # Work on a copy to avoid mutating the caller's mobject (e.g. removing tips). base_vmobject = vmobject vmobject = base_vmobject.copy() # TipableVMobject instances (Arrow, Vector, etc.) carry tips as submobjects. # When dashing such objects, each subcurve would otherwise include its own # tip, leading to many overlapping arrowheads. Pop tips from the working # copy and re-attach them only once after the dashes are created. tips = None if hasattr(vmobject, "pop_tips"): popped_tips = vmobject.pop_tips() if len(popped_tips.submobjects) > 0: tips = popped_tips r = self.dashed_ratio n = self.num_dashes if n > 0: # Assuming total length is 1 dash_len = r / n if vmobject.is_closed(): void_len = (1 - r) / n else: void_len = 1 - r if n == 1 else (1 - r) / (n - 1) period = dash_len + void_len phase_shift = (dash_offset % 1) * period if vmobject.is_closed(): # noqa: SIM108 # closed curves have equal amount of dashes and voids pattern_len = 1 else: # open curves start and end with a dash, so the whole dash pattern with the last void is longer pattern_len = 1 + void_len dash_starts = [((i * period + phase_shift) % pattern_len) for i in range(n)] dash_ends = [ ((i * period + dash_len + phase_shift) % pattern_len) for i in range(n) ] # closed shapes can handle overflow at the 0-point # open shapes need special treatment for it if not vmobject.is_closed(): # due to phase shift being [0...1] range, always the last dash element needs attention for overflow # if an entire dash moves out of the shape end: if dash_ends[-1] > 1 and dash_starts[-1] > 1: # remove the last element since it is out-of-bounds dash_ends.pop() dash_starts.pop() elif dash_ends[-1] < dash_len: # if it overflowed if ( dash_starts[-1] < 1 ): # if the beginning of the piece is still in range dash_starts.append(0) dash_ends.append(dash_ends[-1]) dash_ends[-2] = 1 else: dash_starts[-1] = 0 elif dash_starts[-1] > (1 - dash_len): dash_ends[-1] = 1 if equal_lengths: # calculate the entire length by adding up short line-pieces norms = np.array(0) for k in range(vmobject.get_num_curves()): norms = np.append(norms, vmobject.get_nth_curve_length_pieces(k)) # add up length-pieces in array form length_vals = np.cumsum(norms) ref_points = np.linspace(0, 1, length_vals.size) curve_length = length_vals[-1] self.add( *( vmobject.get_subcurve( np.interp( dash_starts[i] * curve_length, length_vals, ref_points, ), np.interp( dash_ends[i] * curve_length, length_vals, ref_points, ), ) for i in range(len(dash_starts)) ) ) else: self.add( *( vmobject.get_subcurve( dash_starts[i], dash_ends[i], ) for i in range(len(dash_starts)) ) ) # Family is already taken care of by get_subcurve # implementation if config.renderer == RendererType.OPENGL: self.match_style(base_vmobject, recurse=False) else: self.match_style(base_vmobject, family=False) if tips is not None: self.add(*tips.submobjects) ================================================ FILE: manim/mobject/utils.py ================================================ """Utilities for working with mobjects.""" from __future__ import annotations __all__ = [ "get_mobject_class", "get_point_mobject_class", "get_vectorized_mobject_class", ] from .._config import config from ..constants import RendererType from .mobject import Mobject from .opengl.opengl_mobject import OpenGLMobject from .opengl.opengl_point_cloud_mobject import OpenGLPMobject from .opengl.opengl_vectorized_mobject import OpenGLVMobject from .types.point_cloud_mobject import PMobject from .types.vectorized_mobject import VMobject def get_mobject_class() -> type: """Gets the base mobject class, depending on the currently active renderer. .. NOTE:: This method is intended to be used in the code base of Manim itself or in plugins where code should work independent of the selected renderer. Examples -------- The function has to be explicitly imported. We test that the name of the returned class is one of the known mobject base classes:: >>> from manim.mobject.utils import get_mobject_class >>> get_mobject_class().__name__ in ['Mobject', 'OpenGLMobject'] True """ if config.renderer == RendererType.CAIRO: return Mobject if config.renderer == RendererType.OPENGL: return OpenGLMobject raise NotImplementedError( "Base mobjects are not implemented for the active renderer." ) def get_vectorized_mobject_class() -> type: """Gets the vectorized mobject class, depending on the currently active renderer. .. NOTE:: This method is intended to be used in the code base of Manim itself or in plugins where code should work independent of the selected renderer. Examples -------- The function has to be explicitly imported. We test that the name of the returned class is one of the known mobject base classes:: >>> from manim.mobject.utils import get_vectorized_mobject_class >>> get_vectorized_mobject_class().__name__ in ['VMobject', 'OpenGLVMobject'] True """ if config.renderer == RendererType.CAIRO: return VMobject if config.renderer == RendererType.OPENGL: return OpenGLVMobject raise NotImplementedError( "Vectorized mobjects are not implemented for the active renderer." ) def get_point_mobject_class() -> type: """Gets the point cloud mobject class, depending on the currently active renderer. .. NOTE:: This method is intended to be used in the code base of Manim itself or in plugins where code should work independent of the selected renderer. Examples -------- The function has to be explicitly imported. We test that the name of the returned class is one of the known mobject base classes:: >>> from manim.mobject.utils import get_point_mobject_class >>> get_point_mobject_class().__name__ in ['PMobject', 'OpenGLPMobject'] True """ if config.renderer == RendererType.CAIRO: return PMobject if config.renderer == RendererType.OPENGL: return OpenGLPMobject raise NotImplementedError( "Point cloud mobjects are not implemented for the active renderer." ) ================================================ FILE: manim/mobject/value_tracker.py ================================================ """Simple mobjects that can be used for storing (and updating) a value.""" from __future__ import annotations __all__ = ["ValueTracker", "ComplexValueTracker"] from typing import TYPE_CHECKING, Any import numpy as np from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.utils.paths import straight_path if TYPE_CHECKING: from typing import Self from manim.typing import PathFuncType class ValueTracker(Mobject, metaclass=ConvertToOpenGL): """A mobject that can be used for tracking (real-valued) parameters. Useful for animating parameter changes. Not meant to be displayed. Instead the position encodes some number, often one which another animation or continual_animation uses for its update function, and by treating it as a mobject it can still be animated and manipulated just like anything else. This value changes continuously when animated using the :attr:`animate` syntax. Examples -------- .. manim:: ValueTrackerExample class ValueTrackerExample(Scene): def construct(self): number_line = NumberLine() pointer = Vector(DOWN) label = MathTex("x").add_updater(lambda m: m.next_to(pointer, UP)) tracker = ValueTracker(0) pointer.add_updater( lambda m: m.next_to( number_line.n2p(tracker.get_value()), UP ) ) self.add(number_line, pointer,label) tracker += 1.5 self.wait(1) tracker -= 4 self.wait(0.5) self.play(tracker.animate.set_value(5)) self.wait(0.5) self.play(tracker.animate.set_value(3)) self.play(tracker.animate.increment_value(-2)) self.wait(0.5) .. note:: You can also link ValueTrackers to updaters. In this case, you have to make sure that the ValueTracker is added to the scene by ``add`` .. manim:: ValueTrackerExample class ValueTrackerExample(Scene): def construct(self): tracker = ValueTracker(0) label = Dot(radius=3).add_updater(lambda x : x.set_x(tracker.get_value())) self.add(label) self.add(tracker) tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt)) self.wait(2) """ def __init__(self, value: float = 0, **kwargs: Any) -> None: super().__init__(**kwargs) self.set(points=np.zeros((1, 3))) self.set_value(value) def get_value(self) -> float: """Get the current value of this ValueTracker.""" value: float = self.points[0, 0] return value def set_value(self, value: float) -> Self: """Sets a new scalar value to the ValueTracker.""" self.points[0, 0] = value return self def increment_value(self, d_value: float) -> Self: """Increments (adds) a scalar value to the ValueTracker.""" self.set_value(self.get_value() + d_value) return self def __bool__(self) -> bool: """Return whether the value of this ValueTracker evaluates as true.""" return bool(self.get_value()) def __add__(self, d_value: float | Mobject) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value plus ``d_value``. """ if isinstance(d_value, Mobject): raise ValueError( "Cannot increment ValueTracker by a Mobject. Please provide a scalar value." ) return ValueTracker(self.get_value() + d_value) def __iadd__(self, d_value: float | Mobject) -> Self: """adds ``+=`` syntax to increment the value of the ValueTracker.""" if isinstance(d_value, Mobject): raise ValueError( "Cannot increment ValueTracker by a Mobject. Please provide a scalar value." ) self.increment_value(d_value) return self def __floordiv__(self, d_value: float) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the floor division of the current tracker's value by ``d_value``. """ return ValueTracker(self.get_value() // d_value) def __ifloordiv__(self, d_value: float) -> Self: """Set the value of this ValueTracker to the floor division of the current value by ``d_value``.""" self.set_value(self.get_value() // d_value) return self def __mod__(self, d_value: float) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value modulo ``d_value``. """ return ValueTracker(self.get_value() % d_value) def __imod__(self, d_value: float) -> Self: """Set the value of this ValueTracker to the current value modulo ``d_value``.""" self.set_value(self.get_value() % d_value) return self def __mul__(self, d_value: float) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value multiplied by ``d_value``. """ return ValueTracker(self.get_value() * d_value) def __imul__(self, d_value: float) -> Self: """Set the value of this ValueTracker to the product of the current value and ``d_value``.""" self.set_value(self.get_value() * d_value) return self def __pow__(self, d_value: float) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value raised to the power of ``d_value``. """ return ValueTracker(self.get_value() ** d_value) def __ipow__(self, d_value: float) -> Self: """Set the value of this ValueTracker to the current value raised to the power of ``d_value``.""" self.set_value(self.get_value() ** d_value) return self def __sub__(self, d_value: float | Mobject) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value minus ``d_value``. """ if isinstance(d_value, Mobject): raise ValueError( "Cannot decrement ValueTracker by a Mobject. Please provide a scalar value." ) return ValueTracker(self.get_value() - d_value) def __isub__(self, d_value: float | Mobject) -> Self: """Adds ``-=`` syntax to decrement the value of the ValueTracker.""" if isinstance(d_value, Mobject): raise ValueError( "Cannot decrement ValueTracker by a Mobject. Please provide a scalar value." ) self.increment_value(-d_value) return self def __truediv__(self, d_value: float) -> ValueTracker: """Return a new :class:`ValueTracker` whose value is the current tracker's value divided by ``d_value``. """ return ValueTracker(self.get_value() / d_value) def __itruediv__(self, d_value: float) -> Self: """Sets the value of this ValueTracker to the current value divided by ``d_value``.""" self.set_value(self.get_value() / d_value) return self def interpolate( self, mobject1: Mobject, mobject2: Mobject, alpha: float, path_func: PathFuncType = straight_path(), ) -> Self: """Turns ``self`` into an interpolation between ``mobject1`` and ``mobject2``.""" self.set(points=path_func(mobject1.points, mobject2.points, alpha)) return self class ComplexValueTracker(ValueTracker): """Tracks a complex-valued parameter. 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. When the value is set through :attr:`animate`, the value will take a straight path from the source point to the destination point. Examples -------- .. manim:: ComplexValueTrackerExample class ComplexValueTrackerExample(Scene): def construct(self): tracker = ComplexValueTracker(-2+1j) dot = Dot().add_updater( lambda x: x.move_to(tracker.points) ) self.add(NumberPlane(), dot) self.play(tracker.animate.set_value(3+2j)) self.play(tracker.animate.set_value(tracker.get_value() * 1j)) self.play(tracker.animate.set_value(tracker.get_value() - 2j)) self.play(tracker.animate.set_value(tracker.get_value() / (-2 + 3j))) """ def get_value(self) -> complex: # type: ignore [override] """Get the current value of this ComplexValueTracker as a complex number.""" return complex(*self.points[0, :2]) def set_value(self, value: complex | float) -> Self: """Sets a new complex value to the ComplexValueTracker.""" z = complex(value) self.points[0, :2] = (z.real, z.imag) return self ================================================ FILE: manim/mobject/vector_field.py ================================================ """Mobjects representing vector fields.""" from __future__ import annotations __all__ = [ "VectorField", "ArrowVectorField", "StreamLines", ] import itertools as it import random from collections.abc import Callable, Iterable, Sequence from math import ceil, floor from typing import TYPE_CHECKING import numpy as np from PIL import Image from manim.animation.updaters.update import UpdateFromAlphaFunc from manim.mobject.geometry.line import Vector from manim.mobject.graphing.coordinate_systems import CoordinateSystem from .. import config from ..animation.composition import AnimationGroup, Succession from ..animation.creation import Create from ..animation.indication import ShowPassingFlash from ..constants import OUT, RIGHT, UP, RendererType from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VGroup from ..mobject.utils import get_vectorized_mobject_class from ..utils.bezier import interpolate, inverse_interpolate from ..utils.color import ( BLUE_E, GREEN, RED, YELLOW, ManimColor, ParsableManimColor, color_to_rgb, rgb_to_color, ) from ..utils.rate_functions import ease_out_sine, linear from ..utils.simple_functions import sigmoid if TYPE_CHECKING: from manim.typing import ( FloatRGB, FloatRGB_Array, FloatRGBA_Array, Point3D, Vector3D, ) DEFAULT_SCALAR_FIELD_COLORS: list = [BLUE_E, GREEN, YELLOW, RED] class VectorField(VGroup): """A vector field. Vector fields are based on a function defining a vector at every position. This class does by default not include any visible elements but provides methods to move other :class:`~.Mobject` s along the vector field. Parameters ---------- func The function defining the rate of change at every position of the `VectorField`. color The color of the vector field. If set, position-specific coloring is disabled. color_scheme A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`. min_color_scheme_value The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient. max_color_scheme_value The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient. colors The colors defining the color gradient of the vector field. kwargs Additional arguments to be passed to the :class:`~.VGroup` constructor """ def __init__( self, func: Callable[[Point3D], Vector3D], color: ParsableManimColor | None = None, color_scheme: Callable[[Vector3D], float] | None = None, min_color_scheme_value: float = 0, max_color_scheme_value: float = 2, colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS, **kwargs, ): super().__init__(**kwargs) self.func = func if color is None: self.single_color = False if color_scheme is None: def color_scheme(vec: Vector3D) -> float: return np.linalg.norm(vec) self.color_scheme = color_scheme # TODO maybe other default for direction? self.rgbs: FloatRGB_Array = np.array(list(map(color_to_rgb, colors))) def pos_to_rgb(pos: Point3D) -> FloatRGB: vec = self.func(pos) color_value = np.clip( self.color_scheme(vec), min_color_scheme_value, max_color_scheme_value, ) alpha = inverse_interpolate( min_color_scheme_value, max_color_scheme_value, color_value, ) alpha *= len(self.rgbs) - 1 c1: FloatRGB = self.rgbs[int(alpha)] c2: FloatRGB = self.rgbs[min(int(alpha + 1), len(self.rgbs) - 1)] alpha %= 1 return interpolate(c1, c2, alpha) self.pos_to_rgb = pos_to_rgb self.pos_to_color = lambda pos: rgb_to_color(self.pos_to_rgb(pos)) else: self.single_color = True self.color = ManimColor.parse(color) self.submob_movement_updater = None @staticmethod def shift_func( func: Callable[[np.ndarray], np.ndarray], shift_vector: np.ndarray, ) -> Callable[[np.ndarray], np.ndarray]: """Shift a vector field function. Parameters ---------- func The function defining a vector field. shift_vector The shift to be applied to the vector field. Returns ------- `Callable[[np.ndarray], np.ndarray]` The shifted vector field function. """ return lambda p: func(p - shift_vector) @staticmethod def scale_func( func: Callable[[np.ndarray], np.ndarray], scalar: float, ) -> Callable[[np.ndarray], np.ndarray]: """Scale a vector field function. Parameters ---------- func The function defining a vector field. scalar The scalar to be applied to the vector field. Examples -------- .. manim:: ScaleVectorFieldFunction class ScaleVectorFieldFunction(Scene): def construct(self): func = lambda pos: np.sin(pos[1]) * RIGHT + np.cos(pos[0]) * UP vector_field = ArrowVectorField(func) self.add(vector_field) self.wait() func = VectorField.scale_func(func, 0.5) self.play(vector_field.animate.become(ArrowVectorField(func))) self.wait() Returns ------- `Callable[[np.ndarray], np.ndarray]` The scaled vector field function. """ return lambda p: func(p * scalar) def fit_to_coordinate_system(self, coordinate_system: CoordinateSystem): """Scale the vector field to fit a coordinate system. This method is useful when the vector field is defined in a coordinate system different from the one used to display the vector field. This method can only be used once because it transforms the origin of each vector. Parameters ---------- coordinate_system The coordinate system to fit the vector field to. """ self.apply_function(lambda pos: coordinate_system.coords_to_point(*pos)) def nudge( self, mob: Mobject, dt: float = 1, substeps: int = 1, pointwise: bool = False, ) -> VectorField: """Nudge a :class:`~.Mobject` along the vector field. Parameters ---------- mob The mobject to move along the vector field dt A scalar to the amount the mobject is moved along the vector field. The actual distance is based on the magnitude of the vector field. substeps The amount of steps the whole nudge is divided into. Higher values give more accurate approximations. pointwise Whether to move the mobject along the vector field. If `False` the vector field takes effect on the center of the given :class:`~.Mobject`. If `True` the vector field takes effect on the points of the individual points of the :class:`~.Mobject`, potentially distorting it. Returns ------- VectorField This vector field. Examples -------- .. manim:: Nudging class Nudging(Scene): def construct(self): func = lambda pos: np.sin(pos[1] / 2) * RIGHT + np.cos(pos[0] / 2) * UP vector_field = ArrowVectorField( func, x_range=[-7, 7, 1], y_range=[-4, 4, 1], length_func=lambda x: x / 2 ) self.add(vector_field) circle = Circle(radius=2).shift(LEFT) self.add(circle.copy().set_color(GRAY)) dot = Dot().move_to(circle) vector_field.nudge(circle, -2, 60, True) vector_field.nudge(dot, -2, 60) circle.add_updater(vector_field.get_nudge_updater(pointwise=True)) dot.add_updater(vector_field.get_nudge_updater()) self.add(circle, dot) self.wait(6) """ def runge_kutta(self, p: Sequence[float], step_size: float) -> float: """Returns the change in position of a point along a vector field. Parameters ---------- p The position of each point being moved along the vector field. step_size A scalar that is used to determine how much a point is shifted in a single step. Returns ------- float How much the point is shifted. """ k_1 = self.func(p) k_2 = self.func(p + step_size * (k_1 * 0.5)) k_3 = self.func(p + step_size * (k_2 * 0.5)) k_4 = self.func(p + step_size * k_3) return step_size / 6.0 * (k_1 + 2.0 * k_2 + 2.0 * k_3 + k_4) step_size = dt / substeps for _ in range(substeps): if pointwise: mob.apply_function(lambda p: p + runge_kutta(self, p, step_size)) else: mob.shift(runge_kutta(self, mob.get_center(), step_size)) return self def nudge_submobjects( self, dt: float = 1, substeps: int = 1, pointwise: bool = False, ) -> VectorField: """Apply a nudge along the vector field to all submobjects. Parameters ---------- dt A scalar to the amount the mobject is moved along the vector field. The actual distance is based on the magnitude of the vector field. substeps The amount of steps the whole nudge is divided into. Higher values give more accurate approximations. pointwise Whether to move the mobject along the vector field. See :meth:`nudge` for details. Returns ------- VectorField This vector field. """ for mob in self.submobjects: self.nudge(mob, dt, substeps, pointwise) return self def get_nudge_updater( self, speed: float = 1, pointwise: bool = False, ) -> Callable[[Mobject, float], Mobject]: """Get an update function to move a :class:`~.Mobject` along the vector field. When used with :meth:`~.Mobject.add_updater`, the mobject will move along the vector field, where its speed is determined by the magnitude of the vector field. Parameters ---------- speed At `speed=1` the distance a mobject moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of such a mobject. pointwise Whether to move the mobject along the vector field. See :meth:`nudge` for details. Returns ------- Callable[[Mobject, float], Mobject] The update function. """ return lambda mob, dt: self.nudge(mob, dt * speed, pointwise=pointwise) def start_submobject_movement( self, speed: float = 1, pointwise: bool = False, ) -> VectorField: """Start continuously moving all submobjects along the vector field. Calling this method multiple times will result in removing the previous updater created by this method. Parameters ---------- speed The speed at which to move the submobjects. See :meth:`get_nudge_updater` for details. pointwise Whether to move the mobject along the vector field. See :meth:`nudge` for details. Returns ------- VectorField This vector field. """ self.stop_submobject_movement() self.submob_movement_updater = lambda mob, dt: mob.nudge_submobjects( dt * speed, pointwise=pointwise, ) self.add_updater(self.submob_movement_updater) return self def stop_submobject_movement(self) -> VectorField: """Stops the continuous movement started using :meth:`start_submobject_movement`. Returns ------- VectorField This vector field. """ self.remove_updater(self.submob_movement_updater) self.submob_movement_updater = None return self def get_colored_background_image(self, sampling_rate: int = 5) -> Image.Image: """Generate an image that displays the vector field. The color at each position is calculated by passing the positing through a series of steps: Calculate the vector field function at that position, map that vector to a single value using `self.color_scheme` and finally generate a color from that value using the color gradient. Parameters ---------- sampling_rate The stepsize at which pixels get included in the image. Lower values give more accurate results, but may take a long time to compute. Returns ------- Image.Imgae The vector field image. """ if self.single_color: raise ValueError( "There is no point in generating an image if the vector field uses a single color.", ) ph = int(config["pixel_height"] / sampling_rate) pw = int(config["pixel_width"] / sampling_rate) fw = config["frame_width"] fh = config["frame_height"] points_array = np.zeros((ph, pw, 3)) x_array = np.linspace(-fw / 2, fw / 2, pw) y_array = np.linspace(fh / 2, -fh / 2, ph) x_array = x_array.reshape((1, len(x_array))) y_array = y_array.reshape((len(y_array), 1)) x_array = x_array.repeat(ph, axis=0) y_array.repeat(pw, axis=1) # TODO why not y_array = y_array.repeat(...)? points_array[:, :, 0] = x_array points_array[:, :, 1] = y_array rgbs = np.apply_along_axis(self.pos_to_rgb, 2, points_array) return Image.fromarray((rgbs * 255).astype("uint8")) def get_vectorized_rgba_gradient_function( self, start: float, end: float, colors: Iterable[ParsableManimColor], ) -> Callable[[Sequence[float], float], FloatRGBA_Array]: """ Generates a gradient of rgbas as a numpy array Parameters ---------- start start value used for inverse interpolation at :func:`~.inverse_interpolate` end end value used for inverse interpolation at :func:`~.inverse_interpolate` colors list of colors to generate the gradient Returns ------- function to generate the gradients as numpy arrays representing rgba values """ rgbs: FloatRGB_Array = np.array([color_to_rgb(c) for c in colors]) def func(values: Sequence[float], opacity: float = 1.0) -> FloatRGBA_Array: alphas = inverse_interpolate(start, end, np.array(values)) alphas = np.clip(alphas, 0, 1) scaled_alphas = alphas * (len(rgbs) - 1) indices = scaled_alphas.astype(int) next_indices = np.clip(indices + 1, 0, len(rgbs) - 1) inter_alphas = scaled_alphas % 1 inter_alphas = inter_alphas.repeat(3).reshape((len(indices), 3)) new_rgbs: FloatRGB_Array = interpolate( rgbs[indices], rgbs[next_indices], inter_alphas ) new_rgbas: FloatRGBA_Array = np.concatenate( (new_rgbs, np.full([len(new_rgbs), 1], opacity)), axis=1, ) return new_rgbas return func class ArrowVectorField(VectorField): """A :class:`VectorField` represented by a set of change vectors. Vector fields are always based on a function defining the :class:`~.Vector` at every position. The values of this functions is displayed as a grid of vectors. By default the color of each vector is determined by it's magnitude. Other color schemes can be used however. Parameters ---------- func The function defining the rate of change at every position of the vector field. color The color of the vector field. If set, position-specific coloring is disabled. color_scheme A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`. min_color_scheme_value The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient. max_color_scheme_value The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient. colors The colors defining the color gradient of the vector field. x_range A sequence of x_min, x_max, delta_x y_range A sequence of y_min, y_max, delta_y z_range A sequence of z_min, z_max, delta_z three_dimensions Enables three_dimensions. Default set to False, automatically turns True if z_range is not None. length_func The function determining the displayed size of the vectors. The actual size of the vector is passed, the returned value will be used as display size for the vector. By default this is used to cap the displayed size of vectors to reduce the clutter. opacity The opacity of the arrows. vector_config Additional arguments to be passed to the :class:`~.Vector` constructor kwargs Additional arguments to be passed to the :class:`~.VGroup` constructor Examples -------- .. manim:: BasicUsage :save_last_frame: class BasicUsage(Scene): def construct(self): func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3 self.add(ArrowVectorField(func)) .. manim:: SizingAndSpacing class SizingAndSpacing(Scene): def construct(self): func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT vf = ArrowVectorField(func, x_range=[-7, 7, 1]) self.add(vf) self.wait() length_func = lambda x: x / 3 vf2 = ArrowVectorField(func, x_range=[-7, 7, 1], length_func=length_func) self.play(vf.animate.become(vf2)) self.wait() .. manim:: Coloring :save_last_frame: class Coloring(Scene): def construct(self): func = lambda pos: pos - LEFT * 5 colors = [RED, YELLOW, BLUE, DARK_GRAY] min_radius = Circle(radius=2, color=colors[0]).shift(LEFT * 5) max_radius = Circle(radius=10, color=colors[-1]).shift(LEFT * 5) vf = ArrowVectorField( func, min_color_scheme_value=2, max_color_scheme_value=10, colors=colors ) self.add(vf, min_radius, max_radius) """ def __init__( self, func: Callable[[np.ndarray], np.ndarray], color: ParsableManimColor | None = None, color_scheme: Callable[[np.ndarray], float] | None = None, min_color_scheme_value: float = 0, max_color_scheme_value: float = 2, colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS, # Determining Vector positions: x_range: Sequence[float] = None, y_range: Sequence[float] = None, z_range: Sequence[float] = None, three_dimensions: bool = False, # Automatically True if z_range is set # Takes in actual norm, spits out displayed norm length_func: Callable[[float], float] = lambda norm: 0.45 * sigmoid(norm), opacity: float = 1.0, vector_config: dict | None = None, **kwargs, ): self.x_range = x_range or [ floor(-config["frame_width"] / 2), ceil(config["frame_width"] / 2), ] self.y_range = y_range or [ floor(-config["frame_height"] / 2), ceil(config["frame_height"] / 2), ] self.ranges = [self.x_range, self.y_range] if three_dimensions or z_range: self.z_range = z_range or self.y_range.copy() self.ranges += [self.z_range] else: self.ranges += [[0, 0]] for i in range(len(self.ranges)): if len(self.ranges[i]) == 2: self.ranges[i] += [0.5] self.ranges[i][1] += self.ranges[i][2] self.x_range, self.y_range, self.z_range = self.ranges super().__init__( func, color, color_scheme, min_color_scheme_value, max_color_scheme_value, colors, **kwargs, ) self.length_func = length_func self.opacity = opacity if vector_config is None: vector_config = {} self.vector_config = vector_config self.func = func x_range = np.arange(*self.x_range) y_range = np.arange(*self.y_range) z_range = np.arange(*self.z_range) self.add( *[ self.get_vector(x * RIGHT + y * UP + z * OUT) for x, y, z in it.product(x_range, y_range, z_range) ] ) self.set_opacity(self.opacity) def get_vector(self, point: np.ndarray): """Creates a vector in the vector field. The created vector is based on the function of the vector field and is rooted in the given point. Color and length fit the specifications of this vector field. Parameters ---------- point The root point of the vector. """ output = np.array(self.func(point)) norm = np.linalg.norm(output) if norm != 0: output *= self.length_func(norm) / norm vect = Vector(output, **self.vector_config) vect.shift(point) if self.single_color: vect.set_color(self.color) else: vect.set_color(self.pos_to_color(point)) return vect class StreamLines(VectorField): """StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents. Vector fields are always based on a function defining the vector at every position. The values of this functions is displayed by moving many agents along the vector field and showing their trace. Parameters ---------- func The function defining the rate of change at every position of the vector field. color The color of the vector field. If set, position-specific coloring is disabled. color_scheme A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`. min_color_scheme_value The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient. max_color_scheme_value The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient. colors The colors defining the color gradient of the vector field. x_range A sequence of x_min, x_max, delta_x y_range A sequence of y_min, y_max, delta_y z_range A sequence of z_min, z_max, delta_z three_dimensions Enables three_dimensions. Default set to False, automatically turns True if z_range is not None. noise_factor The amount by which the starting position of each agent is altered along each axis. Defaults to :code:`delta_y / 2` if not defined. n_repeats The number of agents generated at each starting point. dt The factor by which the distance an agent moves per step is stretched. Lower values result in a better approximation of the trajectories in the vector field. virtual_time The time the agents get to move in the vector field. Higher values therefore result in longer stream lines. However, this whole time gets simulated upon creation. max_anchors_per_line The maximum number of anchors per line. Lines with more anchors get reduced in complexity, not in length. padding The distance agents can move out of the generation area before being terminated. stroke_width The stroke with of the stream lines. opacity The opacity of the stream lines. Examples -------- .. manim:: BasicUsage :save_last_frame: class BasicUsage(Scene): def construct(self): func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3 self.add(StreamLines(func)) .. manim:: SpawningAndFlowingArea :save_last_frame: class SpawningAndFlowingArea(Scene): def construct(self): func = lambda pos: np.sin(pos[0]) * UR + np.cos(pos[1]) * LEFT + pos / 5 stream_lines = StreamLines( func, x_range=[-3, 3, 0.2], y_range=[-2, 2, 0.2], padding=1 ) spawning_area = Rectangle(width=6, height=4) flowing_area = Rectangle(width=8, height=6) labels = [Tex("Spawning Area"), Tex("Flowing Area").shift(DOWN * 2.5)] for lbl in labels: lbl.add_background_rectangle(opacity=0.6, buff=0.05) self.add(stream_lines, spawning_area, flowing_area, *labels) """ def __init__( self, func: Callable[[np.ndarray], np.ndarray], color: ParsableManimColor | None = None, color_scheme: Callable[[np.ndarray], float] | None = None, min_color_scheme_value: float = 0, max_color_scheme_value: float = 2, colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS, # Determining stream line starting positions: x_range: Sequence[float] = None, y_range: Sequence[float] = None, z_range: Sequence[float] = None, three_dimensions: bool = False, noise_factor: float | None = None, n_repeats=1, # Determining how lines are drawn dt=0.05, virtual_time=3, max_anchors_per_line=100, padding=3, # Determining stream line appearance: stroke_width=1, opacity=1, **kwargs, ): self.x_range = x_range or [ floor(-config["frame_width"] / 2), ceil(config["frame_width"] / 2), ] self.y_range = y_range or [ floor(-config["frame_height"] / 2), ceil(config["frame_height"] / 2), ] self.ranges = [self.x_range, self.y_range] if three_dimensions or z_range: self.z_range = z_range or self.y_range.copy() self.ranges += [self.z_range] else: self.ranges += [[0, 0]] for i in range(len(self.ranges)): if len(self.ranges[i]) == 2: self.ranges[i] += [0.5] self.ranges[i][1] += self.ranges[i][2] self.x_range, self.y_range, self.z_range = self.ranges super().__init__( func, color, color_scheme, min_color_scheme_value, max_color_scheme_value, colors, **kwargs, ) self.noise_factor = ( noise_factor if noise_factor is not None else self.y_range[2] / 2 ) self.n_repeats = n_repeats self.virtual_time = virtual_time self.max_anchors_per_line = max_anchors_per_line self.padding = padding self.stroke_width = stroke_width half_noise = self.noise_factor / 2 rng = np.random.default_rng(0) start_points = np.array( [ (x - half_noise) * RIGHT + (y - half_noise) * UP + (z - half_noise) * OUT + self.noise_factor * rng.random(3) for n in range(self.n_repeats) for x in np.arange(*self.x_range) for y in np.arange(*self.y_range) for z in np.arange(*self.z_range) ], ) def outside_box(p): return ( p[0] < self.x_range[0] - self.padding or p[0] > self.x_range[1] + self.padding - self.x_range[2] or p[1] < self.y_range[0] - self.padding or p[1] > self.y_range[1] + self.padding - self.y_range[2] or p[2] < self.z_range[0] - self.padding or p[2] > self.z_range[1] + self.padding - self.z_range[2] ) max_steps = ceil(virtual_time / dt) + 1 if not self.single_color: self.background_img = self.get_colored_background_image() if config["renderer"] == RendererType.OPENGL: self.values_to_rgbas = self.get_vectorized_rgba_gradient_function( min_color_scheme_value, max_color_scheme_value, colors, ) for point in start_points: points = [point] for _ in range(max_steps): last_point = points[-1] new_point = last_point + dt * func(last_point) if outside_box(new_point): break points.append(new_point) step = max_steps if not step: continue line = get_vectorized_mobject_class()() line.duration = step * dt step = max(1, int(len(points) / self.max_anchors_per_line)) line.set_points_smoothly(points[::step]) if self.single_color: line.set_stroke( color=self.color, width=self.stroke_width, opacity=opacity ) else: if config.renderer == RendererType.OPENGL: # scaled for compatibility with cairo line.set_stroke(width=self.stroke_width / 4.0) norms = np.array( [np.linalg.norm(self.func(point)) for point in line.points], ) line.set_rgba_array_direct( self.values_to_rgbas(norms, opacity), name="stroke_rgba", ) else: if np.any(self.z_range != np.array([0, 0.5, 0.5])): line.set_stroke( [self.pos_to_color(p) for p in line.get_anchors()], ) else: line.color_using_background_image(self.background_img) line.set_stroke(width=self.stroke_width, opacity=opacity) self.add(line) self.stream_lines = [*self.submobjects] def create( self, lag_ratio: float | None = None, run_time: Callable[[float], float] | None = None, **kwargs, ) -> AnimationGroup: """The creation animation of the stream lines. The stream lines appear in random order. Parameters ---------- lag_ratio The lag ratio of the animation. If undefined, it will be selected so that the total animation length is 1.5 times the run time of each stream line creation. run_time The run time of every single stream line creation. The runtime of the whole animation might be longer due to the `lag_ratio`. If undefined, the virtual time of the stream lines is used as run time. Returns ------- :class:`~.AnimationGroup` The creation animation of the stream lines. Examples -------- .. manim:: StreamLineCreation class StreamLineCreation(Scene): def construct(self): func = lambda pos: (pos[0] * UR + pos[1] * LEFT) - pos stream_lines = StreamLines( func, color=YELLOW, x_range=[-7, 7, 1], y_range=[-4, 4, 1], stroke_width=3, virtual_time=1, # use shorter lines max_anchors_per_line=5, # better performance with fewer anchors ) self.play(stream_lines.create()) # uses virtual_time as run_time self.wait() """ if run_time is None: run_time = self.virtual_time if lag_ratio is None: lag_ratio = run_time / 2 / len(self.submobjects) animations = [ Create(line, run_time=run_time, **kwargs) for line in self.stream_lines ] random.shuffle(animations) return AnimationGroup(*animations, lag_ratio=lag_ratio) def start_animation( self, warm_up: bool = True, flow_speed: float = 1, time_width: float = 0.3, rate_func: Callable[[float], float] = linear, line_animation_class: type[ShowPassingFlash] = ShowPassingFlash, **kwargs, ) -> None: """Animates the stream lines using an updater. The stream lines will continuously flow Parameters ---------- warm_up If `True` the animation is initialized line by line. Otherwise it starts with all lines shown. flow_speed At `flow_speed=1` the distance the flow moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of this flow. time_width The proportion of the stream line shown while being animated rate_func The rate function of each stream line flashing line_animation_class The animation class being used Examples -------- .. manim:: ContinuousMotion class ContinuousMotion(Scene): def construct(self): func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT stream_lines = StreamLines(func, stroke_width=3, max_anchors_per_line=30) self.add(stream_lines) stream_lines.start_animation(warm_up=False, flow_speed=1.5) 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( line, run_time=run_time, rate_func=rate_func, time_width=time_width, **kwargs, ) line.anim.begin() line.time = random.random() * self.virtual_time if warm_up: line.time *= -1 self.add(line.anim.mobject) def updater(mob, dt): for line in mob.stream_lines: line.time += dt * flow_speed if line.time >= self.virtual_time: line.time -= self.virtual_time line.anim.interpolate(np.clip(line.time / line.anim.run_time, 0, 1)) self.add_updater(updater) self.flow_animation = updater self.flow_speed = flow_speed self.time_width = time_width def end_animation(self) -> AnimationGroup: """End the stream line animation smoothly. Returns an animation resulting in fully displayed stream lines without a noticeable cut. Returns ------- :class:`~.AnimationGroup` The animation fading out the running stream animation. Raises ------ ValueError if no stream line animation is running Examples -------- .. manim:: EndAnimation class EndAnimation(Scene): def construct(self): func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT stream_lines = StreamLines( func, stroke_width=3, max_anchors_per_line=5, virtual_time=1, color=BLUE ) self.add(stream_lines) stream_lines.start_animation(warm_up=False, flow_speed=1.5, time_width=0.5) self.wait(1) self.play(stream_lines.end_animation()) """ if self.flow_animation is None: raise ValueError("You have to start the animation before fading it out.") def hide_and_wait(mob, alpha): if alpha == 0: mob.set_stroke(opacity=0) elif alpha == 1: mob.set_stroke(opacity=1) def finish_updater_cycle(line, alpha): line.time += dt * self.flow_speed line.anim.interpolate(min(line.time / line.anim.run_time, 1)) if alpha == 1: self.remove(line.anim.mobject) line.anim.finish() max_run_time = self.virtual_time / self.flow_speed creation_rate_func = ease_out_sine creation_staring_speed = creation_rate_func(0.001) * 1000 creation_run_time = ( max_run_time / (1 + self.time_width) * creation_staring_speed ) # creation_run_time is calculated so that the creation animation starts at the same speed # as the regular line flash animation but eases out. dt = 1 / config["frame_rate"] animations = [] self.remove_updater(self.flow_animation) self.flow_animation = None for line in self.stream_lines: create = Create( line, run_time=creation_run_time, rate_func=creation_rate_func, ) if line.time <= 0: animations.append( Succession( UpdateFromAlphaFunc( line, hide_and_wait, run_time=-line.time / self.flow_speed, ), create, ), ) self.remove(line.anim.mobject) line.anim.finish() else: remaining_time = max_run_time - line.time / self.flow_speed animations.append( Succession( UpdateFromAlphaFunc( line, finish_updater_cycle, run_time=remaining_time, ), create, ), ) return AnimationGroup(*animations) # TODO: Variant of StreamLines that is able to respond to changes in the vector field function ================================================ FILE: manim/opengl/__init__.py ================================================ from __future__ import annotations import contextlib with contextlib.suppress(ImportError): from dearpygui import dearpygui as dpg from manim.mobject.opengl.dot_cloud import * from manim.mobject.opengl.opengl_image_mobject import * from manim.mobject.opengl.opengl_mobject import * from manim.mobject.opengl.opengl_point_cloud_mobject import * from manim.mobject.opengl.opengl_surface import * from manim.mobject.opengl.opengl_three_dimensions import * from manim.mobject.opengl.opengl_vectorized_mobject import * from ..renderer.shader import * from ..utils.opengl import * ================================================ FILE: manim/plugins/__init__.py ================================================ from __future__ import annotations from manim._config import config, logger from manim.plugins.plugins_flags import get_plugins, list_plugins __all__ = [ "get_plugins", "list_plugins", ] requested_plugins: set[str] = set(config["plugins"]) missing_plugins = requested_plugins - set(get_plugins().keys()) if missing_plugins: logger.warning("Missing Plugins: %s", missing_plugins) ================================================ FILE: manim/plugins/plugins_flags.py ================================================ """Plugin Managing Utility""" from __future__ import annotations from importlib.metadata import entry_points from typing import Any from manim._config import console __all__ = ["list_plugins"] def get_plugins() -> dict[str, Any]: plugins: dict[str, Any] = { entry_point.name: entry_point.load() for entry_point in entry_points(group="manim.plugins") } return plugins def list_plugins() -> None: console.print("[green bold]Plugins:[/green bold]", justify="left") plugins = get_plugins() for plugin_name in plugins: console.print(f" • {plugin_name}") ================================================ FILE: manim/py.typed ================================================ ================================================ FILE: manim/renderer/__init__.py ================================================ ================================================ FILE: manim/renderer/cairo_renderer.py ================================================ from __future__ import annotations from collections.abc import Iterable from typing import TYPE_CHECKING, Any import numpy as np from manim.utils.hashing import get_hash_from_play_call from .. import config, logger from ..camera.camera import Camera from ..mobject.mobject import Mobject, _AnimationBuilder from ..scene.scene_file_writer import SceneFileWriter from ..utils.exceptions import EndSceneEarlyException from ..utils.iterables import list_update if TYPE_CHECKING: from manim.animation.animation import Animation from manim.scene.scene import Scene from ..typing import PixelArray __all__ = ["CairoRenderer"] class CairoRenderer: """A renderer using Cairo. Attributes ---------- num_plays : int Number of play() functions in the scene. time : float Time elapsed since initialisation of scene. """ def __init__( self, file_writer_class: type[SceneFileWriter] = SceneFileWriter, camera_class: type[Camera] | None = None, skip_animations: bool = False, **kwargs: Any, ): # All of the following are set to EITHER the value passed via kwargs, # OR the value stored in the global config dict at the time of # _instance construction_. self._file_writer_class = file_writer_class camera_cls = camera_class if camera_class is not None else Camera self.camera = camera_cls() self._original_skipping_status = skip_animations self.skip_animations = skip_animations self.animations_hashes: list[str | None] = [] self.num_plays = 0 self.time = 0.0 self.static_image: PixelArray | None = None def init_scene(self, scene: Scene) -> None: self.file_writer: Any = self._file_writer_class( self, scene.__class__.__name__, ) def play( self, scene: Scene, *args: Animation | Mobject | _AnimationBuilder, **kwargs: Any, ) -> None: # Reset skip_animations to the original state. # Needed when rendering only some animations, and skipping others. self.skip_animations = self._original_skipping_status self.update_skipping_status() scene.compile_animation_data(*args, **kwargs) if self.skip_animations: logger.debug(f"Skipping animation {self.num_plays}") hash_current_animation = None self.time += scene.duration else: if config["disable_caching"]: logger.info("Caching disabled.") hash_current_animation = f"uncached_{self.num_plays:05}" else: assert scene.animations is not None hash_current_animation = get_hash_from_play_call( scene, self.camera, scene.animations, scene.mobjects, ) if self.file_writer.is_already_cached(hash_current_animation): logger.info( f"Animation {self.num_plays} : Using cached data (hash : %(hash_current_animation)s)", {"hash_current_animation": hash_current_animation}, ) self.skip_animations = True self.time += scene.duration # adding None as a partial movie file will make file_writer ignore the latter. self.file_writer.add_partial_movie_file(hash_current_animation) self.animations_hashes.append(hash_current_animation) logger.debug( "List of the first few animation hashes of the scene: %(h)s", {"h": str(self.animations_hashes[:5])}, ) self.file_writer.begin_animation(not self.skip_animations) scene.begin_animations() # Save a static image, to avoid rendering non moving objects. self.save_static_frame_data(scene, scene.static_mobjects) if scene.is_current_animation_frozen_frame(): self.update_frame(scene, mobjects=scene.moving_mobjects) # self.duration stands for the total run time of all the animations. # In this case, as there is only a wait, it will be the length of the wait. self.freeze_current_frame(scene.duration) else: scene.play_internal() self.file_writer.end_animation(not self.skip_animations) self.num_plays += 1 def update_frame( # TODO Description in Docstring self, scene: Scene, mobjects: Iterable[Mobject] | None = None, include_submobjects: bool = True, ignore_skipping: bool = True, **kwargs: Any, ) -> None: """Update the frame. Parameters ---------- scene mobjects list of mobjects include_submobjects ignore_skipping **kwargs """ if self.skip_animations and not ignore_skipping: return if not mobjects: mobjects = list_update( scene.mobjects, scene.foreground_mobjects, ) if self.static_image is not None: self.camera.set_frame_to_background(self.static_image) else: self.camera.reset() kwargs["include_submobjects"] = include_submobjects self.camera.capture_mobjects(mobjects, **kwargs) def render( self, scene: Scene, time: float, moving_mobjects: Iterable[Mobject] | None = None, ) -> None: self.update_frame(scene, moving_mobjects) self.add_frame(self.get_frame()) def get_frame(self) -> PixelArray: """Gets the current frame as NumPy array. Returns ------- PixelArray NumPy array of pixel values of each pixel in screen. The shape of the array is height x width x 3. """ return np.array(self.camera.pixel_array) def add_frame(self, frame: PixelArray, num_frames: int = 1) -> None: """Adds a frame to the video_file_stream Parameters ---------- frame The frame to add, as a pixel array. num_frames The number of times to add frame. """ dt = 1 / self.camera.frame_rate if self.skip_animations: return self.time += num_frames * dt self.file_writer.write_frame(frame, num_frames=num_frames) def freeze_current_frame(self, duration: float) -> None: """Adds a static frame to the movie for a given duration. The static frame is the current frame. Parameters ---------- duration [description] """ dt = 1 / self.camera.frame_rate self.add_frame( self.get_frame(), num_frames=int(duration / dt), ) def show_frame(self, scene: Scene) -> None: """Opens the current frame in the Default Image Viewer of your system. """ self.update_frame(scene, ignore_skipping=True) self.camera.get_image().show() def save_static_frame_data( self, scene: Scene, static_mobjects: Iterable[Mobject], ) -> PixelArray | None: """Compute and save the static frame, that will be reused at each frame to avoid unnecessarily computing static mobjects. Parameters ---------- scene The scene played. static_mobjects Static mobjects of the scene. If None, self.static_image is set to None. Returns ------- PixelArray | None The static image computed. The return value is None if there are no static mobjects in the scene. """ self.static_image = None if not static_mobjects: return None self.update_frame(scene, mobjects=static_mobjects) self.static_image = self.get_frame() return self.static_image def update_skipping_status(self) -> None: """This method is used internally to check if the current animation needs to be skipped or not. It also checks if the number of animations that were played correspond to the number of animations that need to be played, and raises an EndSceneEarlyException if they don't correspond. """ # there is always at least one section -> no out of bounds here if self.file_writer.sections[-1].skip_animations: self.skip_animations = True if config["save_last_frame"]: self.skip_animations = True if ( config.from_animation_number > 0 and self.num_plays < config.from_animation_number ): self.skip_animations = True if ( config.upto_animation_number >= 0 and self.num_plays > config.upto_animation_number ): self.skip_animations = True raise EndSceneEarlyException() def scene_finished(self, scene: Scene) -> None: # If no animations in scene, render an image instead if self.num_plays: self.file_writer.finish() elif config.write_to_movie: config.save_last_frame = True config.write_to_movie = False else: self.static_image = None self.update_frame(scene) if config["save_last_frame"]: self.static_image = None self.update_frame(scene) self.file_writer.save_image(self.camera.get_image()) ================================================ FILE: manim/renderer/opengl_renderer.py ================================================ from __future__ import annotations import contextlib import itertools as it import time import typing from functools import cached_property from typing import TYPE_CHECKING, Any, Self import moderngl import numpy as np from moderngl import Framebuffer from PIL import Image from typing_extensions import override from manim import config, logger from manim.mobject.opengl.opengl_mobject import ( OpenGLMobject, OpenGLPoint, ) from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.typing import MatrixMN, Point3D from manim.utils.caching import handle_caching_play from manim.utils.color import color_to_rgba from manim.utils.exceptions import EndSceneEarlyException from manim.utils.paths import straight_path from ..constants import * from ..scene.scene_file_writer import SceneFileWriter from ..utils import opengl from ..utils.simple_functions import clip from ..utils.space_ops import ( angle_of_vector, quaternion_from_angle_axis, quaternion_mult, rotation_matrix_transpose, rotation_matrix_transpose_from_quaternion, ) from .shader import Mesh, Shader from .vectorized_mobject_rendering import ( render_opengl_vectorized_mobject_fill, render_opengl_vectorized_mobject_stroke, ) if TYPE_CHECKING: from collections.abc import Iterable from typing import Self from manim.animation.animation import Animation from manim.mobject.mobject import Mobject, _AnimationBuilder from manim.scene.scene import Scene from manim.typing import ( FloatRGBA, PathFuncType, Point3DLike, RGBAPixelArray, Vector3DLike, ) from manim.utils.color.core import ParsableManimColor from manim.utils.opengl import FlattenedMatrix4x4 from .opengl_renderer_window import Window __all__ = ["OpenGLCamera", "OpenGLRenderer"] class OpenGLCamera(OpenGLMobject): """ An OpenGL-based camera for 3D scene rendering. Attributes ---------- frame_shape : tuple[float, float] The width and height of the camera frame. center_point : np.ndarray The center point of the camera in 3D space. euler_angles : np.ndarray The Euler angles (theta, phi, gamma) representing the camera's orientation. focal_distance : float The focal distance of the camera. light_source_position : np.ndarray The position of the light source in 3D space. orthographic : bool Whether the camera uses orthographic projection instead of perspective. minimum_polar_angle : float The minimum polar angle for camera rotation. maximum_polar_angle : float The maximum polar angle for camera rotation. inverse_rotation_matrix : np.ndarray The inverse rotation matrix of the camera. """ def __init__( self, frame_shape: tuple[float, float] | None = None, center_point: Point3DLike | None = None, # Theta, phi, gamma euler_angles: Point3DLike | None = None, focal_distance: float = 2.0, light_source_position: Point3DLike | None = None, orthographic: bool = False, minimum_polar_angle: float = -PI / 2, maximum_polar_angle: float = PI / 2, model_matrix: MatrixMN | None = None, **kwargs: Any, ) -> None: """ Initializes an OpenGLCamera instance. Parameters ---------- frame_shape : tuple[float, float], optional The width and height of the camera frame. If not provided, defaults to the global manim config values `frame_width` and `frame_height`. center_point : Point3DLike, optional The center point of the camera in 3D space. If not provided, defaults to the origin (0, 0, 0). euler_angles : Point3DLike, optional The Euler angles (theta, phi, gamma) representing the camera's orientation. If not provided, defaults to (0, 0, 0) (i.e., no rotation). focal_distance : float, optional The focal distance of the camera. Default is 2.0. light_source_position : Point3DLike, optional The position of the light source in 3D space. If not provided, defaults to (-10, 10, 10). orthographic : bool, optional Whether the camera uses orthographic projection instead of perspective. Default is False (perspective). minimum_polar_angle : float, optional The minimum polar angle in radian for camera rotation. Default is -π/2, i.e. no restriction. maximum_polar_angle : float, optional The maximum polar angle in radian for camera rotation. Default is π/2, i.e. no restriction. model_matrix : MatrixMN, optional The initial model matrix [1]_ for the camera. If not provided, defaults to a translation matrix that positions the camera at (0, 0, 11). **kwargs : Any Additional keyword arguments passed to the OpenGLMobject constructor. References ---------- .. [1] Wikipedia, "Camera matrix", https://en.wikipedia.org/wiki/Camera_matrix """ self.use_z_index = True self.frame_rate = 60 self.orthographic = orthographic self.minimum_polar_angle = minimum_polar_angle self.maximum_polar_angle = maximum_polar_angle if self.orthographic: self.projection_matrix = opengl.orthographic_projection_matrix() self.unformatted_projection_matrix = opengl.orthographic_projection_matrix( format_=False, ) else: self.projection_matrix = opengl.perspective_projection_matrix() self.unformatted_projection_matrix = opengl.perspective_projection_matrix( format_=False, ) if frame_shape is None: self.frame_shape = (config["frame_width"], config["frame_height"]) else: self.frame_shape = frame_shape if center_point is None: self.center_point = ORIGIN else: self.center_point = np.asarray(center_point, dtype=float) if model_matrix is None: model_matrix = opengl.translation_matrix(0, 0, 11) self.focal_distance = focal_distance self.light_source_position = np.asarray( light_source_position or [-10, 10, 10], dtype=float ) self.light_source = OpenGLPoint(self.light_source_position) self.default_model_matrix = model_matrix super().__init__(model_matrix=model_matrix, should_render=False, **kwargs) euler_angles = np.asarray(euler_angles or [0, 0, 0], dtype=float) self.euler_angles: Point3D = euler_angles self.refresh_rotation_matrix() def get_position(self) -> Point3D: """Retrieve the camera's position in 3D space.""" return self.model_matrix[:, 3][:3] def set_position(self, position: Point3D) -> Self: """Set the camera's position in 3D space.""" self.model_matrix[:, 3][:3] = position return self @cached_property def formatted_view_matrix(self) -> FlattenedMatrix4x4: """The formatted view matrix for shader input.""" return opengl.matrix_to_shader_input(self.unformatted_view_matrix) @cached_property def unformatted_view_matrix(self) -> MatrixMN: return typing.cast(MatrixMN, np.linalg.inv(self.model_matrix)) def init_points(self) -> None: """Initialize the camera's points based on frame shape and center point.""" self.set_points([ORIGIN, LEFT, RIGHT, DOWN, UP]) self.set_width(self.frame_shape[0], stretch=True) self.set_height(self.frame_shape[1], stretch=True) self.move_to(self.center_point) def to_default_state(self) -> Self: """Reset the camera to its default state (config frame size, centered at origin, no rotation). """ self.center() self.set_height(config["frame_height"]) self.set_width(config["frame_width"]) self.set_euler_angles(0, 0, 0) self.model_matrix = self.default_model_matrix return self def refresh_rotation_matrix(self) -> None: """Refresh the camera's inverse rotation matrix based on its Euler angles.""" # Rotate based on camera orientation theta, phi, gamma = self.euler_angles quat = quaternion_mult( quaternion_from_angle_axis(theta, OUT, axis_normalized=True), quaternion_from_angle_axis(phi, RIGHT, axis_normalized=True), quaternion_from_angle_axis(gamma, OUT, axis_normalized=True), ) self.inverse_rotation_matrix = rotation_matrix_transpose_from_quaternion( np.asarray(quat, dtype=float) ) @override def rotate( self, angle: float, axis: Vector3DLike = OUT, about_point: Point3DLike | None = None, **kwargs: Any, ) -> Self: """ Rotate the camera by a given angle around a specified axis. Parameters ---------- angle : float The angle in radians to rotate the camera. axis : Vector3DLike, optional The axis around which to rotate the camera. Default is OUT (z-axis). about_point : Point3DLike, optional Ignored. For OpenGLCamera, rotation is always about the camera's center. **kwargs : Any Not used for OpenGLCamera. Passing additional keyword arguments has no effect. Returns ------- Self The rotated camera instance. Returned for chaining. """ curr_rot_T = self.inverse_rotation_matrix added_rot_T = rotation_matrix_transpose(angle, axis) new_rot_T = np.dot(curr_rot_T, added_rot_T) Fz = new_rot_T[2] phi = np.arccos(Fz[2]) theta = angle_of_vector(Fz[:2]) + PI / 2 partial_rot_T = np.dot( rotation_matrix_transpose(phi, RIGHT), rotation_matrix_transpose(theta, OUT), ) gamma = angle_of_vector(np.dot(partial_rot_T, new_rot_T.T)[:, 0]) self.set_euler_angles(theta, phi, gamma) return self def set_euler_angles( self, theta: float | None = None, phi: float | None = None, gamma: float | None = None, ) -> Self: """ Set the camera's Euler angles [1]_ (theta, phi, gamma). Parameters ---------- theta : float | None, optional The angle in radians for rotation around the OUT (z) axis. If None, the current theta value is retained. phi : float | None, optional The angle in radians for rotation around the RIGHT (x) axis. If None, the current phi value is retained. gamma : float | None, optional The angle in radians for rotation around the OUT (z) axis. If None, the current gamma value is retained. Returns ------- Self The camera instance with updated Euler angles. Returned for chaining. See Also -------- set_theta : Set the theta Euler angle. set_phi : Set the phi Euler angle. set_gamma : Set the gamma Euler angle. References ---------- .. [1] Wikipedia, "Euler angles", https://en.wikipedia.org/wiki/Euler_angles """ if theta is not None: self.euler_angles[0] = theta if phi is not None: self.euler_angles[1] = phi if gamma is not None: self.euler_angles[2] = gamma self.refresh_rotation_matrix() return self def set_theta(self, theta: float) -> Self: """ Set the camera's theta Euler angle (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_phi : Set the phi Euler angle. set_gamma : Set the gamma Euler angle. """ return self.set_euler_angles(theta=theta) def set_phi(self, phi: float) -> Self: """ Set the camera's phi Euler angle (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_theta : Set the theta Euler angle. set_gamma : Set the gamma Euler angle. """ return self.set_euler_angles(phi=phi) def set_gamma(self, gamma: float) -> Self: """ Set the camera's gamma Euler angle (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_theta : Set the theta Euler angle. set_phi : Set the phi Euler angle. """ return self.set_euler_angles(gamma=gamma) def increment_theta(self, dtheta: float) -> Self: """ Increment the camera's theta Euler angle by a given amount (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_theta : Set the theta Euler angle. """ self.euler_angles[0] += dtheta self.refresh_rotation_matrix() return self def increment_phi(self, dphi: float) -> Self: """ Increment the camera's phi Euler angle by a given amount (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_phi : Set the phi Euler angle. """ phi = self.euler_angles[1] new_phi = clip(phi + dphi, -PI / 2, PI / 2) self.euler_angles[1] = new_phi self.refresh_rotation_matrix() return self def increment_gamma(self, dgamma: float) -> Self: """ Increment the camera's gamma Euler angle by a given amount (in radians). See Also -------- set_euler_angles : Set all Euler angles at once. set_gamma : Set the gamma Euler angle. """ self.euler_angles[2] += dgamma self.refresh_rotation_matrix() return self def get_shape(self) -> tuple[float, float]: """Retrieve the width and height of the camera frame.""" return (self.get_width(), self.get_height()) def get_center(self) -> Point3D: """ Retrieve the center point of the camera in 3D space. Notes ----- The center point is assumed to be the first point in the camera's points array. """ # Assumes first point is at the center return typing.cast(Point3D, self.points[0]) def get_width(self) -> float: """Retrieve the width of the camera frame.""" points = self.points out = points[2, 0] - points[1, 0] return float(out) def get_height(self) -> float: """Retrieve the height of the camera frame.""" points = self.points out = points[4, 1] - points[3, 1] return float(out) # return points[4, 1] - points[3, 1] def get_focal_distance(self) -> float: """Retrieve the focal distance of the camera.""" return self.focal_distance * self.get_height() @override def interpolate( self, mobject1: OpenGLMobject, mobject2: OpenGLMobject, alpha: float, path_func: PathFuncType = straight_path(), ) -> Self: super().interpolate(mobject1, mobject2, alpha, path_func) self.refresh_rotation_matrix() return self class OpenGLRenderer: """ An OpenGL-based renderer. Attributes ---------- animation_elapsed_time : float The elapsed time of the current animation. animation_start_time : float The start time of the current animation. animations_hashes : list[str | None] List of animation hashes for caching. anti_alias_width : float The width used for anti-aliasing in pixel units. background_color : FloatRGBA The background color of the renderer. camera : OpenGLCamera The camera used for rendering. num_plays : float The number of animation plays executed. path_to_texture_id : dict[str, int] Mapping from texture file paths to OpenGL texture IDs. pressed_keys : set[int] Set of currently pressed key codes. skip_animations : bool Whether animations are currently being skipped. time : float The total elapsed time for the renderer. window : Window | None The window used for previewing, if any. """ def __init__( self, file_writer_class: type[SceneFileWriter] = SceneFileWriter, skip_animations: bool = False, ) -> None: """Initializes the OpenGLRenderer. Parameters ---------- file_writer_class : type[SceneFileWriter], optional The class to use for writing scene files, by default SceneFileWriter. skip_animations : bool, optional Whether to skip animations during rendering, by default False. """ # Measured in pixel widths, used for vector graphics self.anti_alias_width = 1.5 self._file_writer_class = file_writer_class self._original_skipping_status = skip_animations self.skip_animations = skip_animations self.animation_start_time = 0.0 self.animation_elapsed_time = 0.0 self.time = 0.0 self.animations_hashes: list[str | None] = [] self.num_plays = 0 self.camera = OpenGLCamera() self.pressed_keys: set[int] = set() self.window: Window | None = None self.path_to_texture_id: dict[str, int] = {} self.background_color = config["background_color"] def init_scene(self, scene: Scene) -> None: """ Initializes the OpenGL rendering context and related resources for the given scene. Set up: - the file writer - the background color - the OpenGL context - the window (if needed) Parameters ---------- scene : Scene The scene to be rendered """ self.partial_movie_files: list[str | None] = [] self.file_writer: SceneFileWriter = self._file_writer_class( self, scene.__class__.__name__, ) self.scene = scene self.background_color = config["background_color"] if self.should_create_window(): from .opengl_renderer_window import Window self.window = Window(self) self.context = self.window.ctx self.frame_buffer_object = self.context.detect_framebuffer() else: # self.window = None try: self.context = moderngl.create_context(standalone=True) except Exception: self.context = moderngl.create_context( standalone=True, backend="egl", ) self.frame_buffer_object = self.get_frame_buffer_object(self.context, 0) self.frame_buffer_object.use() self.context.enable(moderngl.BLEND) self.context.wireframe = config["enable_wireframe"] self.context.blend_func = ( moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA, moderngl.ONE, moderngl.ONE, ) def should_create_window(self) -> bool: """ Determine whether a window should be created for rendering based on the current configuration. Notes ----- A windows is always created if the 'force_window' configuration is enabled. """ if config["force_window"]: logger.warning( "'--force_window' is enabled, this is intended for debugging purposes " "and may impact performance if used when outputting files", ) return True return ( config["preview"] and not config["save_last_frame"] and not config["format"] and not config["write_to_movie"] and not config["dry_run"] ) def get_pixel_shape(self) -> tuple[int, int] | None: """ Retrieve the pixel dimensions of the current frame buffer object (2D). Returns ------- width : int The width of the frame buffer in pixels. height : int The height of the frame buffer in pixels. """ frame_buffer: Framebuffer | None = getattr(self, "frame_buffer_object", None) if frame_buffer is None: return None _, _, pixel_width, pixel_height = frame_buffer.viewport return pixel_width, pixel_height def refresh_perspective_uniforms(self, camera: OpenGLCamera) -> None: """ Update the perspective-related uniform variables used in the OpenGL renderer based on the current camera settings. Parameters ---------- camera : OpenGLCamera The camera object from which to extract perspective and lighting information. Raises ------ ValueError If the renderer's pixel shape is not available. """ pixel_shape = self.get_pixel_shape() if pixel_shape is None: msg = "Pixel shape is None, cannot refresh perspective uniforms." raise ValueError(msg) pixel_width, pixel_height = pixel_shape frame_width, frame_height = camera.get_shape() # TODO, this should probably be a mobject uniform, with # the camera taking care of the conversion factor anti_alias_width = self.anti_alias_width / (pixel_height / frame_height) # Orient light rotation = camera.inverse_rotation_matrix light_pos: Point3D = camera.light_source.get_location() light_pos = np.dot(rotation, light_pos) self.perspective_uniforms = { "frame_shape": camera.get_shape(), "anti_alias_width": anti_alias_width, "camera_center": tuple(camera.get_center()), "camera_rotation": tuple(np.array(rotation).T.flatten()), "light_source_position": tuple(light_pos), "focal_distance": camera.get_focal_distance(), } def render_mobject(self, mobject: OpenGLMobject | OpenGLVMobject) -> None: """ Render an OpenGL mobject (either OpenGLMobject or OpenGLVMobject) using the appropriate shaders and rendering pipeline. Parameters ---------- mobject : OpenGLMobject | OpenGLVMobject The mobject to render. Must be an instance of OpenGLMobject or OpenGLVMobject. Raises ------ TypeError If a shader texture is not a moderngl.Uniform or moderngl.UniformBlock. """ if isinstance(mobject, OpenGLVMobject): if config["use_projection_fill_shaders"]: render_opengl_vectorized_mobject_fill(self, mobject) if config["use_projection_stroke_shaders"]: render_opengl_vectorized_mobject_stroke(self, mobject) shader_wrapper_list = mobject.get_shader_wrapper_list() # Convert ShaderWrappers to Meshes. for shader_wrapper in shader_wrapper_list: folder = shader_wrapper.shader_folder shader = Shader( context=self.context, name=str(folder) if folder is not None else None ) # Set textures. for name, path in shader_wrapper.texture_paths.items(): tid = self.get_texture_id(str(path)) shader_texture = shader.shader_program[name] if not isinstance( shader_texture, (moderngl.Uniform, moderngl.UniformBlock) ): msg = ( f"Shader texture must be a uniform, got {type(shader_texture)}" ) raise TypeError(msg) shader_texture.value = tid # Set uniforms. for name, value in it.chain( shader_wrapper.uniforms.items(), self.perspective_uniforms.items(), ): with contextlib.suppress(KeyError): shader.set_uniform(name, value) try: # TODO: make the type of 'camera' generic in the 'Scene' class # to avoid the cast here cam = typing.cast("OpenGLCamera", self.scene.camera) shader.set_uniform("u_view_matrix", cam.formatted_view_matrix) shader.set_uniform("u_projection_matrix", cam.projection_matrix) except KeyError: pass # Set depth test. if shader_wrapper.depth_test: self.context.enable(moderngl.DEPTH_TEST) else: self.context.disable(moderngl.DEPTH_TEST) # Render. vert_indices = shader_wrapper.vert_indices mesh = Mesh( shader, shader_wrapper.vert_data, indices=np.asarray(vert_indices) if vert_indices is not None else None, use_depth_test=shader_wrapper.depth_test, primitive=mobject.render_primitive, ) mesh.set_uniforms(self) mesh.render() def get_texture_id(self, path: str) -> int: """ Retrieves the OpenGL texture ID associated with the given image file path. Automatically creates a new texture it it has not been loaded before. Parameters ---------- path : str The file path to the texture image. Returns ------- int The OpenGL texture ID corresponding to the given path. """ return ( self.path_to_texture_id[path] if path in self.path_to_texture_id else self._create_texture(path) ) def _create_texture(self, image_path: str) -> int: """ Create an OpenGL texture from the given image file path, get its texture ID, and store it in `self.path_to_texture_id[image_path]`. Parameters ---------- image_path : str The file path to the image to be loaded as a texture. Returns ------- int The texture ID assigned to the newly created texture. """ with Image.open(image_path) as img: tid = len(self.path_to_texture_id) # grayscale image if img.mode == "L": components = 1 swizzle = "RRR1" else: # convert everything to RGBA for consistency img = img.convert("RGBA") components = 4 swizzle = "RGBA" texture = self.context.texture( size=img.size, components=components, data=img.tobytes(), ) texture.repeat_x = False texture.repeat_y = False texture.filter = (moderngl.NEAREST, moderngl.NEAREST) texture.swizzle = swizzle texture.use(location=tid) self.path_to_texture_id[image_path] = tid return tid def update_skipping_status(self) -> None: """ Check and update the skipping status for the current animation (self.skip_animations flag) based on the configuration settings. Parameters ---------- None Raises ------ EndSceneEarlyException If the number of played animations exceeds the configured upper bound. """ # there is always at least one section -> no out of bounds here if self.file_writer.sections[-1].skip_animations: self.skip_animations = True if ( config.from_animation_number > 0 and self.num_plays < config.from_animation_number ): self.skip_animations = True if ( config.upto_animation_number >= 0 and self.num_plays > config.upto_animation_number ): self.skip_animations = True raise EndSceneEarlyException() @handle_caching_play def play( self, scene: Scene, *animations: Animation | Mobject | _AnimationBuilder, **kwargs: Any, ) -> None: """ Plays the given animations or mobjects in the specified scene. "Playing" here refers to the process of compiling animation data, beginning the animations, updating frames, and finalizing the animation in the context of the renderer. Parameters ---------- scene Scene The scene in which to play the animations. *animations Animation | Mobject | _AnimationBuilder The animations, mobjects, or animation builders to play. **kwargs Any Additional keyword arguments to pass to the animation compilation. """ # TODO: Handle data locking / unlocking. self.animation_start_time = time.time() self.file_writer.begin_animation(not self.skip_animations) scene.compile_animation_data(*animations, **kwargs) scene.begin_animations() if scene.is_current_animation_frozen_frame(): self.update_frame(scene) if not self.skip_animations: self.file_writer.write_frame( self, num_frames=int(config.frame_rate * scene.duration) ) if self.window is not None: self.window.swap_buffers() while time.time() - self.animation_start_time < scene.duration: pass self.animation_elapsed_time = scene.duration else: scene.play_internal() self.file_writer.end_animation(not self.skip_animations) self.time += scene.duration self.num_plays += 1 def clear_screen(self) -> None: """ Clears the current frame buffer and updates the display window accordingly. The screen is cleared using the background color specified in the renderer. """ self.frame_buffer_object.clear(*self.background_color) if self.window is None: return self.window.swap_buffers() def render( self, scene: Scene, frame_offset: float, moving_mobjects: list[Mobject] ) -> None: """ Renders a single frame of the given scene using OpenGL. Parameters ---------- scene : Scene The scene to render. frame_offset : float The time offset for the current frame in seconds. If no window is present, this parameter is ignored, and a frame is a true snapshot of the scene at the current time. moving_mobjects : list[Mobject] List of mobjects that are currently moving and need to be updated. Not used at all, kept for compatibility with other renderers. Notes ----- - Updates the frame for the scene. - If animations are skipped, the method returns early. - Writes the current frame using the file writer. - If a window is present, swaps buffers and continues updating frames until the animation elapsed time reaches the frame offset. """ self.update_frame(scene) if self.skip_animations: return self.file_writer.write_frame(self) if self.window is not None: self.window.swap_buffers() while self.animation_elapsed_time < frame_offset: self.update_frame(scene) self.window.swap_buffers() def update_frame(self, scene: Scene) -> None: """ Update and render the current frame for the given scene. Performs the following steps: 1. Clear the frame buffer with the background color. 2. Refresh camera perspective uniforms for rendering. 3. Iterate through all mobjects in the scene, rendering those marked for display. 4. Iterate through all mesh objects in the scene, setting their uniforms and rendering them. 5. Update the elapsed animation time. Parameters ---------- scene : Scene The scene to render the frame for. """ self.frame_buffer_object.clear(*self.background_color) # TODO: make the type of 'camera' generic in the 'Scene' class # to avoid the cast here cam = typing.cast("OpenGLCamera", scene.camera) self.refresh_perspective_uniforms(cam) for mobject in scene.mobjects: if not mobject.should_render: continue # TODO: make the type of 'mobject' generic in the 'Scene' class # to avoid the cast here mobj = typing.cast("OpenGLMobject | OpenGLVMobject", mobject) self.render_mobject(mobj) for obj in scene.meshes: for mesh in obj.get_meshes(): mesh.set_uniforms(self) mesh.render() self.animation_elapsed_time = time.time() - self.animation_start_time def scene_finished(self, scene: Scene) -> None: """ Handle the finalization process after a scene has finished rendering. Performs the following actions: - If any plays (animations) have occurred, finalizes the file writing process. - If no plays have occurred but movie writing is enabled, disables movie writing to avoid creating an empty movie file. - If the configuration requires saving the last frame, updates and saves the final image of the scene. Parameters ---------- scene : Scene The scene that has finished rendering. """ # When num_plays is 0, no images have been output, so output a single # image in this case if self.num_plays > 0: self.file_writer.finish() elif self.num_plays == 0 and config.write_to_movie: config.write_to_movie = False if self.should_save_last_frame(): config.save_last_frame = True self.update_frame(scene) self.file_writer.save_image(self.get_image()) def should_save_last_frame(self) -> bool: """ Determine whether the last frame of the scene should be saved, i.e. if one of the following conditions is met: - The configuration option 'save_last_frame' is enabled. - The scene is not in interactive mode. - This is the first play (i.e., num_plays == 0). """ if config["save_last_frame"]: return True if self.scene.interactive_mode: return False return self.num_plays == 0 def get_image(self) -> Image.Image: """ Get the current OpenGL frame buffer as a PIL Image. Returns ------- Image.Image The image representation of the current frame buffer. Raises ------ ValueError If the pixel shape cannot be determined. Notes ----- The image is constructed from raw RGBA buffer data, with the origin at the bottom-left. """ raw_buffer_data = self.get_raw_frame_buffer_object_data() pixel_shape = self.get_pixel_shape() if pixel_shape is None: msg = "Pixel shape is None, cannot get image." raise ValueError(msg) image = Image.frombytes( "RGBA", # mode (rgb, a for alpha (transparency))) pixel_shape, # size raw_buffer_data, # data "raw", # decoder_name # *args for the decoder "RGBA", # raw mode 0, # stride (O = no extra padding) -1, # orientation (-1 = bottom to top, 1 = top to bottom) ) return image def save_static_frame_data( self, scene: Scene, static_mobjects: Iterable[Mobject] ) -> None: pass def get_frame_buffer_object( self, context: moderngl.Context, samples: int = 0 ) -> Framebuffer: """ Creates and returns a framebuffer object configured with color and depth attachments. Parameters ---------- context : moderngl.Context The ModernGL context used to create the framebuffer and its attachments. samples : int, optional The number of samples for multisample anti-aliasing (MSAA)[1]_. Default is 0 (no MSAA). Returns ------- Framebuffer A framebuffer object with a color texture attachment and a depth renderbuffer attachment, both sized according to the current configuration's pixel width and height. Notes ----- Framebuffer's color attachment is supposed RGBA. Pixel dimensions are taken from the global config of Manim. References ---------- .. [1] Wikipedia, "Multisample anti-aliasing", https://en.wikipedia.org/wiki/Multisample_anti-aliasing """ pixel_width = config["pixel_width"] pixel_height = config["pixel_height"] num_channels = 4 return context.framebuffer( color_attachments=context.texture( (pixel_width, pixel_height), components=num_channels, samples=samples, ), depth_attachment=context.depth_renderbuffer( (pixel_width, pixel_height), samples=samples, ), ) def get_raw_frame_buffer_object_data(self, dtype: str = "f1") -> bytes: """ Get the raw data from the current frame buffer object as bytes. This method reads the pixel data from the frame buffer object using the specified data type. The data is read with 4 color channels (typically RGBA). Args: dtype (str, optional): The data type to use when reading the buffer. Defaults to "f1" (i.e., float with 1 byte). Returns: bytes: The raw pixel data from the frame buffer object. """ # Copy blocks from the fbo_msaa to the drawn fbo using Blit # pw, ph = self.get_pixel_shape() # gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.fbo_msaa.glo) # gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.fbo.glo) # gl.glBlitFramebuffer( # 0, 0, pw, ph, 0, 0, pw, ph, gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR # ) num_channels = 4 ret: bytes = self.frame_buffer_object.read( viewport=self.frame_buffer_object.viewport, components=num_channels, dtype=dtype, ) return ret def get_frame(self) -> RGBAPixelArray: """ Get the current frame buffer as a Numpy array of RGBA pixel values. Returns ------- RGBAPixelArray A Numpy array of shape (height, width, 4) containing the RGBA pixel data of the current frame, with dtype uint8. Raises ------ ValueError If the pixel shape cannot be determined. """ # get current pixel values as numpy data in order to test output raw = self.get_raw_frame_buffer_object_data(dtype="f1") pixel_shape = self.get_pixel_shape() if pixel_shape is None: msg = "Pixel shape is None, cannot get frame." raise ValueError(msg) result_dimensions = (pixel_shape[1], pixel_shape[0], 4) np_buf = np.frombuffer(raw, dtype="uint8").reshape(result_dimensions) np_buf = np.flipud(np_buf) return np_buf # Returns offset from the bottom left corner in pixels. # top_left flag should be set to True when using a GUI framework # where the (0,0) is at the top left: e.g. PySide6 def pixel_coords_to_space_coords( self, px: float, py: float, relative: bool = False, top_left: bool = False ) -> Point3D: """ Converts pixel coordinates to space (scene) coordinates. top_left flag should be set to True when using a GUI framework where the (0,0) is at the top left: e.g. PySide6. Parameters ---------- px : float The x-coordinate in pixel space. py : float The y-coordinate in pixel space. relative : bool, optional If True, returns coordinates relative to the frame (normalized to [-1, 1]). If False, returns absolute space coordinates. Default is False. top_left : bool, optional If True, treats the origin (0, 0) as the top-left corner of the pixel space. If False, treats the origin as the bottom-left. Default is False. Returns ------- Point3D The corresponding coordinates in space as a NumPy array of shape (3,). Notes ----- If the pixel shape is not available, returns the origin [0, 0, 0]. """ pixel_shape = self.get_pixel_shape() if pixel_shape is None: return typing.cast(Point3D, np.array([0.0, 0.0, 0.0])) pixel_width, pixel_height = pixel_shape frame_height = config["frame_height"] frame_center = self.camera.get_center() if relative: # relative -> just normalize to [-1, 1] return 2 * np.array([px / pixel_width, py / pixel_height, 0]) scale = frame_height / pixel_height y_direction = -1 if top_left else 1 return typing.cast( Point3D, frame_center + scale * np.array( [(px - pixel_width / 2), y_direction * (py - pixel_height / 2), 0.0] ), ) @property def background_color(self) -> FloatRGBA: """The background color of the renderer (RGBA format).""" return self._background_color @background_color.setter def background_color(self, value: ParsableManimColor) -> None: self._background_color = color_to_rgba(value, 1.0) ================================================ FILE: manim/renderer/opengl_renderer_window.py ================================================ from __future__ import annotations from typing import TYPE_CHECKING, Any import moderngl_window as mglw from moderngl_window.context.pyglet.window import Window as PygletWindow from moderngl_window.timers.clock import Timer from screeninfo import Monitor, get_monitors from .. import __version__, config if TYPE_CHECKING: from .opengl_renderer import OpenGLRenderer __all__ = ["Window"] class Window(PygletWindow): fullscreen = False resizable = True gl_version = (3, 3) vsync = True cursor = True def __init__( self, renderer: OpenGLRenderer, window_size: str | tuple[int, ...] = config.window_size, **kwargs: Any, ) -> None: monitors = get_monitors() mon_index = config.window_monitor monitor = monitors[min(mon_index, len(monitors) - 1)] invalid_window_size_error_message = ( "window_size must be specified either as 'default', a string of the form " "'width,height', or a tuple of 2 ints of the form (width, height)." ) if isinstance(window_size, tuple): if len(window_size) != 2: raise ValueError(invalid_window_size_error_message) size = window_size elif window_size == "default": # make window_width half the width of the monitor # but make it full screen if --fullscreen window_width = monitor.width if not config.fullscreen: window_width //= 2 # by default window_height = 9/16 * window_width window_height = int( window_width * config.frame_height // config.frame_width, ) size = (window_width, window_height) elif len(window_size.split(",")) == 2: (window_width, window_height) = tuple(map(int, window_size.split(","))) size = (window_width, window_height) else: raise ValueError(invalid_window_size_error_message) super().__init__(size=size) self.title = f"Manim Community {__version__}" self.size = size self.renderer = renderer mglw.activate_context(window=self) self.timer = Timer() self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer) self.timer.start() self.swap_buffers() initial_position = self.find_initial_position(size, monitor) self.position = initial_position # Delegate event handling to scene. def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None: super().on_mouse_motion(x, y, dx, dy) point = self.renderer.pixel_coords_to_space_coords(x, y) d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True) self.renderer.scene.on_mouse_motion(point, d_point) def on_mouse_scroll(self, x: int, y: int, x_offset: float, y_offset: float) -> None: super().on_mouse_scroll(x, y, x_offset, y_offset) point = self.renderer.pixel_coords_to_space_coords(x, y) offset = self.renderer.pixel_coords_to_space_coords( x_offset, y_offset, relative=True, ) self.renderer.scene.on_mouse_scroll(point, offset) def on_key_press(self, symbol: int, modifiers: int) -> bool: self.renderer.pressed_keys.add(symbol) event_handled: bool = super().on_key_press(symbol, modifiers) self.renderer.scene.on_key_press(symbol, modifiers) return event_handled def on_key_release(self, symbol: int, modifiers: int) -> None: if symbol in self.renderer.pressed_keys: self.renderer.pressed_keys.remove(symbol) super().on_key_release(symbol, modifiers) self.renderer.scene.on_key_release(symbol, modifiers) def on_mouse_drag( self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int ) -> None: super().on_mouse_drag(x, y, dx, dy, buttons, modifiers) point = self.renderer.pixel_coords_to_space_coords(x, y) d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True) self.renderer.scene.on_mouse_drag(point, d_point, buttons, modifiers) def find_initial_position( self, size: tuple[int, int], monitor: Monitor ) -> tuple[int, int]: custom_position = config.window_position window_width, window_height = size # Position might be specified with a string of the form x,y for integers x and y if len(custom_position) == 1: raise ValueError( "window_position must specify both Y and X positions (Y/X -> UR). Also accepts LEFT/RIGHT/ORIGIN/UP/DOWN.", ) # in the form Y/X (UR) if custom_position in ["LEFT", "RIGHT"]: custom_position = "O" + custom_position[0] elif custom_position in ["UP", "DOWN"]: custom_position = custom_position[0] + "O" elif custom_position == "ORIGIN": custom_position = "O" * 2 elif "," in custom_position: pos_y, pos_x = tuple(map(int, custom_position.split(","))) return (pos_x, pos_y) # Alternatively, it might be specified with a string like # UR, OO, DL, etc. specifying what corner it should go to char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2} width_diff: int = monitor.width - window_width height_diff: int = monitor.height - window_height return ( monitor.x + char_to_n[custom_position[1]] * width_diff // 2, -monitor.y + char_to_n[custom_position[0]] * height_diff // 2, ) def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> None: super().on_mouse_press(x, y, button, modifiers) point = self.renderer.pixel_coords_to_space_coords(x, y) mouse_button_map = { 1: "LEFT", 2: "MOUSE", 4: "RIGHT", } self.renderer.scene.on_mouse_press(point, mouse_button_map[button], modifiers) ================================================ FILE: manim/renderer/shader.py ================================================ from __future__ import annotations import contextlib import inspect import re import textwrap from collections.abc import Callable, Iterator, Sequence from pathlib import Path from typing import TYPE_CHECKING, Any, Self, TypeAlias import moderngl import numpy as np import numpy.typing as npt if TYPE_CHECKING: from manim.renderer.opengl_renderer import OpenGLRenderer MeshTimeBasedUpdater: TypeAlias = Callable[["Object3D", float], None] MeshNonTimeBasedUpdater: TypeAlias = Callable[["Object3D"], None] MeshUpdater: TypeAlias = MeshNonTimeBasedUpdater | MeshTimeBasedUpdater from manim.typing import MatrixMN, Point3D from .. import config from ..utils import opengl SHADER_FOLDER = Path(__file__).parent / "shaders" shader_program_cache: dict[str, moderngl.Program] = {} file_path_to_code_map: dict[Path, str] = {} __all__ = [ "Object3D", "Mesh", "Shader", "FullScreenQuad", ] def get_shader_code_from_file(file_path: Path) -> str: if file_path in file_path_to_code_map: return file_path_to_code_map[file_path] source = file_path.read_text() include_lines = re.finditer( r"^#include (?P.*\.glsl)$", source, flags=re.MULTILINE, ) for match in include_lines: include_path = match.group("include_path") included_code = get_shader_code_from_file( file_path.parent / include_path, ) source = source.replace(match.group(0), included_code) file_path_to_code_map[file_path] = source return source def filter_attributes( unfiltered_attributes: npt.NDArray, attributes: Sequence[str] ) -> npt.NDArray: # Construct attributes for only those needed by the shader. filtered_attributes_dtype = [] for i, dtype_name in enumerate(unfiltered_attributes.dtype.names): if dtype_name in attributes: filtered_attributes_dtype.append( ( dtype_name, unfiltered_attributes.dtype[i].subdtype[0].str, unfiltered_attributes.dtype[i].shape, ), ) filtered_attributes = np.zeros( unfiltered_attributes[unfiltered_attributes.dtype.names[0]].shape[0], dtype=filtered_attributes_dtype, ) for dtype_name in unfiltered_attributes.dtype.names: if dtype_name in attributes: filtered_attributes[dtype_name] = unfiltered_attributes[dtype_name] return filtered_attributes class Object3D: def __init__(self, *children: Object3D): self.model_matrix = np.eye(4) self.normal_matrix = np.eye(4) self.children: list[Object3D] = [] self.parent: Object3D | None = None self.add(*children) self.init_updaters() # TODO: Use path_func. def interpolate(self, start: Object3D, end: Object3D, alpha: float, _: Any) -> None: self.model_matrix = (1 - alpha) * start.model_matrix + alpha * end.model_matrix self.normal_matrix = ( 1 - alpha ) * start.normal_matrix + alpha * end.normal_matrix def single_copy(self) -> Object3D: copy = Object3D() copy.model_matrix = self.model_matrix.copy() copy.normal_matrix = self.normal_matrix.copy() return copy def copy(self) -> Object3D: node_to_copy = {} bfs = [self] while bfs: node = bfs.pop(0) bfs.extend(node.children) node_copy = node.single_copy() node_to_copy[node] = node_copy # Add the copy to the copy of the parent. if node.parent is not None and node is not self: node_to_copy[node.parent].add(node_copy) return node_to_copy[self] def add(self, *children: Object3D) -> None: for child in children: if child.parent is not None: raise Exception( "Attempt to add child that's already added to another Object3D", ) self.remove(*children, current_children_only=False) self.children.extend(children) for child in children: child.parent = self def remove(self, *children: Object3D, current_children_only: bool = True) -> None: if current_children_only: for child in children: if child.parent != self: raise Exception( "Attempt to remove child that isn't added to this Object3D", ) self.children = list(filter(lambda child: child not in children, self.children)) for child in children: child.parent = None def get_position(self) -> Point3D: return self.model_matrix[:, 3][:3] def set_position(self, position: Point3D) -> Self: self.model_matrix[:, 3][:3] = position return self def get_meshes(self) -> Iterator[Mesh]: dfs = [self] while dfs: parent = dfs.pop() if isinstance(parent, Mesh): yield parent dfs.extend(parent.children) def get_family(self) -> Iterator[Object3D]: dfs = [self] while dfs: parent = dfs.pop() yield parent dfs.extend(parent.children) def align_data_and_family(self, _: Any) -> None: pass def hierarchical_model_matrix(self) -> MatrixMN: if self.parent is None: return self.model_matrix model_matrices = [self.model_matrix] current_object = self while current_object.parent is not None: model_matrices.append(current_object.parent.model_matrix) current_object = current_object.parent return np.linalg.multi_dot(list(reversed(model_matrices))) def hierarchical_normal_matrix(self) -> MatrixMN: if self.parent is None: return self.normal_matrix[:3, :3] normal_matrices = [self.normal_matrix] current_object = self while current_object.parent is not None: normal_matrices.append(current_object.parent.model_matrix) current_object = current_object.parent return np.linalg.multi_dot(list(reversed(normal_matrices)))[:3, :3] def init_updaters(self) -> None: self.time_based_updaters: list[MeshTimeBasedUpdater] = [] self.non_time_updaters: list[MeshNonTimeBasedUpdater] = [] self.has_updaters = False self.updating_suspended = False def update(self, dt: float = 0) -> Self: if not self.has_updaters or self.updating_suspended: return self for time_based_updater in self.time_based_updaters: time_based_updater(self, dt) for non_time_based_updater in self.non_time_updaters: non_time_based_updater(self) return self def get_time_based_updaters(self) -> list[MeshTimeBasedUpdater]: return self.time_based_updaters def has_time_based_updater(self) -> bool: return len(self.time_based_updaters) > 0 def get_updaters(self) -> list[MeshUpdater]: return self.time_based_updaters + self.non_time_updaters def add_updater( self, update_function: MeshUpdater, index: int | None = None, call_updater: bool = True, ) -> Self: if "dt" in inspect.signature(update_function).parameters: self._add_time_based_updater(update_function, index) # type: ignore[arg-type] else: self._add_non_time_updater(update_function, index) # type: ignore[arg-type] self.refresh_has_updater_status() if call_updater: self.update() return self def _add_time_based_updater( self, update_function: MeshTimeBasedUpdater, index: int | None = None ) -> None: if index is None: self.time_based_updaters.append(update_function) else: self.time_based_updaters.insert(index, update_function) def _add_non_time_updater( self, update_function: MeshNonTimeBasedUpdater, index: int | None = None ) -> None: if index is None: self.non_time_updaters.append(update_function) else: self.non_time_updaters.insert(index, update_function) def remove_updater(self, update_function: MeshUpdater) -> Self: while update_function in self.time_based_updaters: self.time_based_updaters.remove(update_function) # type: ignore[arg-type] while update_function in self.non_time_updaters: self.non_time_updaters.remove(update_function) # type: ignore[arg-type] self.refresh_has_updater_status() return self def clear_updaters(self) -> Self: self.time_based_updaters = [] self.non_time_updaters = [] self.refresh_has_updater_status() return self def match_updaters(self, mesh: Object3D) -> Self: self.clear_updaters() for updater in mesh.get_updaters(): self.add_updater(updater) return self def suspend_updating(self) -> Self: self.updating_suspended = True return self def resume_updating(self, call_updater: bool = True) -> Self: self.updating_suspended = False if call_updater: self.update(dt=0) return self def refresh_has_updater_status(self) -> Self: self.has_updaters = len(self.get_updaters()) > 0 return self class Mesh(Object3D): def __init__( self, shader: Shader | None = None, attributes: npt.NDArray | None = None, geometry: Mesh | None = None, material: Shader | None = None, indices: npt.NDArray | None = None, use_depth_test: bool = True, primitive: int = moderngl.TRIANGLES, ): super().__init__() if shader is not None and attributes is not None: self.shader: Shader = shader self.attributes = attributes self.indices = indices elif geometry is not None and material is not None: self.shader = material self.attributes = geometry.attributes self.indices = geometry.indices else: raise Exception( "Mesh requires either attributes and a Shader or a Geometry and a " "Material", ) self.use_depth_test = use_depth_test self.primitive = primitive self.skip_render: bool = False self.init_updaters() def single_copy(self) -> Mesh: copy = Mesh( attributes=self.attributes.copy(), shader=self.shader, indices=self.indices.copy() if self.indices is not None else None, use_depth_test=self.use_depth_test, primitive=self.primitive, ) copy.skip_render = self.skip_render copy.model_matrix = self.model_matrix.copy() copy.normal_matrix = self.normal_matrix.copy() # TODO: Copy updaters? return copy def set_uniforms(self, renderer: OpenGLRenderer) -> None: self.shader.set_uniform( "u_model_matrix", opengl.matrix_to_shader_input(self.model_matrix), ) self.shader.set_uniform("u_view_matrix", renderer.camera.formatted_view_matrix) self.shader.set_uniform( "u_projection_matrix", renderer.camera.projection_matrix, ) def render(self) -> None: if self.skip_render: return if self.use_depth_test: self.shader.context.enable(moderngl.DEPTH_TEST) else: self.shader.context.disable(moderngl.DEPTH_TEST) shader_attribute_names: list[str] = [] for member_name, member in self.shader.shader_program._members.items(): if isinstance(member, moderngl.Attribute): shader_attribute_names.append(member_name) filtered_shader_attributes = filter_attributes( self.attributes, shader_attribute_names ) vertex_buffer_object = self.shader.context.buffer( filtered_shader_attributes.tobytes() ) if self.indices is None: index_buffer_object = None else: vert_index_data = self.indices.astype("i4").tobytes() if vert_index_data: index_buffer_object = self.shader.context.buffer(vert_index_data) else: index_buffer_object = None vertex_array_object = self.shader.context.simple_vertex_array( self.shader.shader_program, vertex_buffer_object, *filtered_shader_attributes.dtype.names, index_buffer=index_buffer_object, ) vertex_array_object.render(self.primitive) vertex_buffer_object.release() vertex_array_object.release() if index_buffer_object is not None: index_buffer_object.release() class Shader: def __init__( self, context: moderngl.Context, name: str | None = None, source: dict[str, Any] | None = None, ): global shader_program_cache self.context = context self.name = name self.source = source # See if the program is cached. if ( self.name in shader_program_cache and shader_program_cache[self.name].ctx == self.context ): self.shader_program = shader_program_cache[self.name] elif self.source is not None: # Generate the shader from inline code if it was passed. self.shader_program = context.program(**self.source) elif self.name is not None: # Search for a file containing the shader. source_dict = {} source_dict_key = { "vert": "vertex_shader", "frag": "fragment_shader", "geom": "geometry_shader", } shader_folder = SHADER_FOLDER / self.name for shader_file in shader_folder.iterdir(): shader_file_path = shader_folder / shader_file shader_source = get_shader_code_from_file(shader_file_path) source_dict[source_dict_key[shader_file_path.stem]] = shader_source self.shader_program = context.program(**source_dict) else: raise Exception("Must either pass shader name or shader source.") # Cache the shader. if self.name is not None and self.name not in shader_program_cache: shader_program_cache[self.name] = self.shader_program def set_uniform(self, name: str, value: Any) -> None: with contextlib.suppress(KeyError): self.shader_program[name] = value class FullScreenQuad(Mesh): def __init__( self, context: moderngl.Context, fragment_shader_source: str | None = None, fragment_shader_name: str | None = None, ): if fragment_shader_source is None and fragment_shader_name is None: raise Exception("Must either pass shader name or shader source.") if fragment_shader_name is not None: # Use the name. shader_file_path = SHADER_FOLDER / f"{fragment_shader_name}.frag" fragment_shader_source = get_shader_code_from_file(shader_file_path) elif fragment_shader_source is not None: fragment_shader_source = textwrap.dedent(fragment_shader_source.lstrip()) shader = Shader( context, source={ "vertex_shader": """ #version 330 in vec4 in_vert; uniform mat4 u_model_view_matrix; uniform mat4 u_projection_matrix; void main() {{ vec4 camera_space_vertex = u_model_view_matrix * in_vert; vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex; gl_Position = clip_space_vertex; }} """, "fragment_shader": fragment_shader_source, }, ) attributes = np.zeros(6, dtype=[("in_vert", np.float32, (4,))]) attributes["in_vert"] = np.array( [ [-config["frame_x_radius"], -config["frame_y_radius"], 0, 1], [-config["frame_x_radius"], config["frame_y_radius"], 0, 1], [config["frame_x_radius"], config["frame_y_radius"], 0, 1], [-config["frame_x_radius"], -config["frame_y_radius"], 0, 1], [config["frame_x_radius"], -config["frame_y_radius"], 0, 1], [config["frame_x_radius"], config["frame_y_radius"], 0, 1], ], ) shader.set_uniform("u_model_view_matrix", opengl.view_matrix()) shader.set_uniform( "u_projection_matrix", opengl.orthographic_projection_matrix(), ) super().__init__(shader, attributes) def render(self) -> None: super().render() ================================================ FILE: manim/renderer/shader_wrapper.py ================================================ from __future__ import annotations import copy import logging import re from collections.abc import Mapping, Sequence from pathlib import Path from typing import TYPE_CHECKING, Self, TypeAlias import moderngl import numpy as np import numpy.typing as npt if TYPE_CHECKING: from manim.typing import FloatRGBLike_Array # Mobjects that should be rendered with # the same shader will be organized and # clumped together based on keeping track # of a dict holding all the relevant information # to that shader __all__ = ["ShaderWrapper"] logger = logging.getLogger("manim") def get_shader_dir(): return Path(__file__).parent / "shaders" def find_file(file_name: Path, directories: list[Path]) -> Path: # Check if what was passed in is already a valid path to a file if file_name.exists(): return file_name possible_paths = (directory / file_name for directory in directories) for path in possible_paths: if path.exists(): return path else: logger.debug(f"{path} does not exist.") raise OSError(f"{file_name} not Found") _ShaderDType: TypeAlias = np.void _ShaderData: TypeAlias = npt.NDArray[_ShaderDType] class ShaderWrapper: def __init__( self, vert_data: _ShaderData = None, vert_indices: Sequence[int] | None = None, shader_folder: Path | str | None = None, # A dictionary mapping names of uniform variables uniforms: dict[str, float | tuple[float, ...]] | None = None, # A dictionary mapping names to filepaths for textures. texture_paths: Mapping[str, Path | str] | None = None, depth_test: bool = False, render_primitive: int | str = moderngl.TRIANGLE_STRIP, ): self.vert_data: _ShaderData = vert_data self.vert_indices: Sequence[int] | None = vert_indices self.vert_attributes: tuple[str, ...] | None = vert_data.dtype.names self.shader_folder: Path = Path(shader_folder or "") self.uniforms: dict[str, float | tuple[float, ...]] = uniforms or {} self.texture_paths: Mapping[str, str | Path] = texture_paths or {} self.depth_test: bool = depth_test self.render_primitive: str = str(render_primitive) self.init_program_code() self.refresh_id() def copy(self): result = copy.copy(self) result.vert_data = np.array(self.vert_data) if result.vert_indices is not None: result.vert_indices = np.array(self.vert_indices) if self.uniforms: result.uniforms = dict(self.uniforms) if self.texture_paths: result.texture_paths = dict(self.texture_paths) return result def is_valid(self) -> bool: return all( [ self.vert_data is not None, self.program_code["vertex_shader"] is not None, self.program_code["fragment_shader"] is not None, ], ) def get_id(self) -> str: return self.id def get_program_id(self) -> int: return self.program_id def create_id(self): # A unique id for a shader return "|".join( map( str, [ self.program_id, self.uniforms, self.texture_paths, self.depth_test, self.render_primitive, ], ), ) def refresh_id(self) -> None: self.program_id: int = self.create_program_id() self.id: str = self.create_id() def create_program_id(self): return hash( "".join( self.program_code[f"{name}_shader"] or "" for name in ("vertex", "geometry", "fragment") ), ) def init_program_code(self): def get_code(name: str) -> str | None: return get_shader_code_from_file( self.shader_folder / f"{name}.glsl", ) self.program_code: dict[str, str | None] = { "vertex_shader": get_code("vert"), "geometry_shader": get_code("geom"), "fragment_shader": get_code("frag"), } def get_program_code(self): return self.program_code def replace_code(self, old: str, new: str) -> None: code_map = self.program_code for name, code in code_map.items(): if code: code_map[name] = re.sub(old, new, code) self.refresh_id() def combine_with(self, *shader_wrappers: "ShaderWrapper") -> Self: # noqa: UP037 # Assume they are of the same type if len(shader_wrappers) == 0: return self if self.vert_indices is not None: num_verts = len(self.vert_data) indices_list = [self.vert_indices] data_list = [self.vert_data] for sw in shader_wrappers: indices_list.append(sw.vert_indices + num_verts) data_list.append(sw.vert_data) num_verts += len(sw.vert_data) self.vert_indices = np.hstack(indices_list) self.vert_data = np.hstack(data_list) else: self.vert_data = np.hstack( [self.vert_data, *(sw.vert_data for sw in shader_wrappers)], ) return self # For caching filename_to_code_map: dict = {} def get_shader_code_from_file(filename: Path) -> str | None: if filename in filename_to_code_map: return filename_to_code_map[filename] try: filepath = find_file( filename, directories=[get_shader_dir(), Path("/")], ) except OSError: return None result = filepath.read_text() # To share functionality between shaders, some functions are read in # from other files an inserted into the relevant strings before # passing to ctx.program for compiling # Replace "#INSERT " lines with relevant code insertions = re.findall( r"^#include ../include/.*\.glsl$", result, flags=re.MULTILINE, ) for line in insertions: inserted_code = get_shader_code_from_file( Path() / "include" / line.replace("#include ../include/", ""), ) if inserted_code is None: return None result = result.replace(line, inserted_code) filename_to_code_map[filename] = result return result def get_colormap_code(rgb_list: FloatRGBLike_Array) -> str: data = ",".join("vec3({}, {}, {})".format(*rgb) for rgb in rgb_list) return f"vec3[{len(rgb_list)}]({data})" ================================================ FILE: manim/renderer/shaders/default/frag.glsl ================================================ #version 330 uniform vec4 u_color; out vec4 frag_color; void main() { frag_color = u_color; } ================================================ FILE: manim/renderer/shaders/default/vert.glsl ================================================ #version 330 in vec3 in_vert; uniform mat4 u_model_matrix; uniform mat4 u_view_matrix; uniform mat4 u_projection_matrix; void main() { gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(in_vert, 1.0); } ================================================ FILE: manim/renderer/shaders/design.frag ================================================ #version 330 out vec4 frag_color; void main() { vec2 st = gl_FragCoord.xy / vec2(854, 360); vec3 color = vec3(0.0); st *= 3.0; st = fract(st); color = vec3(st, 0.0); frag_color = vec4(color, 1.0); } ================================================ FILE: manim/renderer/shaders/design_2.frag ================================================ #version 330 uniform vec2 u_resolution; out vec4 frag_color; #define PI 3.14159265358979323846 vec2 rotate2D(vec2 _st, float _angle){ _st -= 0.5; _st = mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)) * _st; _st += 0.5; return _st; } vec2 tile(vec2 _st, float _zoom){ _st *= _zoom; return fract(_st); } float box(vec2 _st, vec2 _size, float _smoothEdges){ _size = vec2(0.5)-_size*0.5; vec2 aa = vec2(_smoothEdges*0.5); vec2 uv = smoothstep(_size,_size+aa,_st); uv *= smoothstep(_size,_size+aa,vec2(1.0)-_st); return uv.x*uv.y; } void main(void){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); // Divide the space in 4 st = tile(st,4.); // Use a matrix to rotate the space 45 degrees st = rotate2D(st,PI*0.25); // Draw a square color = vec3(box(st,vec2(0.7),0.01)); // color = vec3(st,0.0); frag_color = vec4(color,1.0); } ================================================ FILE: manim/renderer/shaders/design_3.frag ================================================ #version 330 uniform vec3 u_resolution; uniform float u_time; out vec4 frag_color; vec3 palette(float d){ return mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d); } vec2 rotate(vec2 p,float a){ float c = cos(a); float s = sin(a); return p*mat2(c,s,-s,c); } float map(vec3 p){ for( int i = 0; i<8; ++i){ float t = u_time*0.1; p.xz =rotate(p.xz,t); p.xy =rotate(p.xy,t*1.89); p.xz = abs(p.xz); p.xz-=.5; } return dot(sign(p),p)/5.; } vec4 rm (vec3 ro, vec3 rd){ float t = 0.; vec3 col = vec3(0.); float d; for(float i =0.; i<64.; i++){ vec3 p = ro + rd*t; d = map(p)*.5; if(d<0.02){ break; } if(d>100.){ break; } //col+=vec3(0.6,0.8,0.8)/(400.*(d)); col+=palette(length(p)*.1)/(400.*(d)); t+=d; } return vec4(col,1./(d*100.)); } void main(void){ vec2 uv = (gl_FragCoord.xy-(u_resolution.xy/2.))/u_resolution.x; vec3 ro = vec3(0.,0.,-50.); ro.xz = rotate(ro.xz,u_time); vec3 cf = normalize(-ro); vec3 cs = normalize(cross(cf,vec3(0.,1.,0.))); vec3 cu = normalize(cross(cf,cs)); vec3 uuv = ro+cf*3. + uv.x*cs + uv.y*cu; vec3 rd = normalize(uuv-ro); vec4 col = rm(ro,rd); frag_color = vec4(col.xyz, 1); } ================================================ FILE: manim/renderer/shaders/image/frag.glsl ================================================ #version 330 uniform sampler2D Texture; in vec2 v_im_coords; in float v_opacity; out vec4 frag_color; void main() { frag_color = texture(Texture, v_im_coords); frag_color.a = v_opacity; } ================================================ FILE: manim/renderer/shaders/image/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl uniform sampler2D Texture; in vec3 point; in vec2 im_coords; in float opacity; out vec2 v_im_coords; out float v_opacity; // Analog of import for manim only #include ../include/get_gl_Position.glsl #include ../include/position_point_into_frame.glsl void main(){ v_im_coords = im_coords; v_opacity = opacity; gl_Position = get_gl_Position(position_point_into_frame(point)); } ================================================ FILE: manim/renderer/shaders/include/NOTE.md ================================================ There seems to be no analog to #include in C++ for OpenGL shaders. While there are other options for sharing code between shaders, a lot of them aren't great, especially if the goal is to have all the logic for which specific bits of code to share handled in the shader file itself. So the way manim currently works is to replace any line which looks like #INSERT with the code from one of the files in this folder. The functions in this file often include reference to uniforms which are assumed to be part of the surrounding context into which they are inserted. ================================================ FILE: manim/renderer/shaders/include/add_light.glsl ================================================ ///// INSERT COLOR_MAP FUNCTION HERE ///// vec4 add_light(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss, float shadow){ ///// INSERT COLOR FUNCTION HERE ///// // The line above may be replaced by arbitrary code snippets, as per // the method Mobject.set_color_by_code if(gloss == 0.0 && shadow == 0.0) return color; // TODO, do we actually want this? It effectively treats surfaces as two-sided if(unit_normal.z < 0){ unit_normal *= -1; } // TODO, read this in as a uniform? float camera_distance = 6; // Assume everything has already been rotated such that camera is in the z-direction vec3 to_camera = vec3(0, 0, camera_distance) - point; vec3 to_light = light_coords - point; vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal); float dot_prod = dot(normalize(light_reflection), normalize(to_camera)); float shine = gloss * exp(-3 * pow(1 - dot_prod, 2)); float dp2 = dot(normalize(to_light), unit_normal); float darkening = mix(1, max(dp2, 0), shadow); return vec4( darkening * mix(color.rgb, vec3(1.0), shine), color.a ); } vec4 finalize_color(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss, float shadow){ // Put insertion here instead return add_light(color, point, unit_normal, light_coords, gloss, shadow); } ================================================ FILE: manim/renderer/shaders/include/camera_uniform_declarations.glsl ================================================ uniform vec2 frame_shape; uniform float anti_alias_width; uniform vec3 camera_center; uniform mat3 camera_rotation; uniform float is_fixed_in_frame; uniform float is_fixed_orientation; uniform vec3 fixed_orientation_center; uniform float focal_distance; ================================================ FILE: manim/renderer/shaders/include/finalize_color.glsl ================================================ vec3 float_to_color(float value, float min_val, float max_val, vec3[9] colormap_data){ float alpha = clamp((value - min_val) / (max_val - min_val), 0.0, 1.0); int disc_alpha = min(int(alpha * 8), 7); return mix( colormap_data[disc_alpha], colormap_data[disc_alpha + 1], 8.0 * alpha - disc_alpha ); } vec4 add_light(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss, float shadow){ if(gloss == 0.0 && shadow == 0.0) return color; // TODO, do we actually want this? It effectively treats surfaces as two-sided if(unit_normal.z < 0){ unit_normal *= -1; } // TODO, read this in as a uniform? float camera_distance = 6; // Assume everything has already been rotated such that camera is in the z-direction vec3 to_camera = vec3(0, 0, camera_distance) - point; vec3 to_light = light_coords - point; vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal); float dot_prod = dot(normalize(light_reflection), normalize(to_camera)); float shine = gloss * exp(-3 * pow(1 - dot_prod, 2)); float dp2 = dot(normalize(to_light), unit_normal); float darkening = mix(1, max(dp2, 0), shadow); return vec4( darkening * mix(color.rgb, vec3(1.0), shine), color.a ); } vec4 finalize_color(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss, float shadow){ ///// INSERT COLOR FUNCTION HERE ///// // The line above may be replaced by arbitrary code snippets, as per // the method Mobject.set_color_by_code return add_light(color, point, unit_normal, light_coords, gloss, shadow); } ================================================ FILE: manim/renderer/shaders/include/get_gl_Position.glsl ================================================ // Assumes the following uniforms exist in the surrounding context: // uniform vec2 frame_shape; // uniform float focal_distance; // uniform float is_fixed_in_frame; // uniform float is_fixed_orientation; // uniform vec3 fixed_orientation_center; const vec2 DEFAULT_FRAME_SHAPE = vec2(8.0 * 16.0 / 9.0, 8.0); float perspective_scale_factor(float z, float focal_distance){ return max(0.0, focal_distance / (focal_distance - z)); } vec4 get_gl_Position(vec3 point){ vec4 result = vec4(point, 1.0); if(!bool(is_fixed_in_frame)){ result.x *= 2.0 / frame_shape.x; result.y *= 2.0 / frame_shape.y; float psf = perspective_scale_factor(result.z, focal_distance); if (psf > 0){ result.xy *= psf; // TODO, what's the better way to do this? // This is to keep vertices too far out of frame from getting cut. result.z *= 0.01; } } else{ if (!bool(is_fixed_orientation)){ result.x *= 2.0 / DEFAULT_FRAME_SHAPE.x; result.y *= 2.0 / DEFAULT_FRAME_SHAPE.y; } else{ result.x *= 2.0 / frame_shape.x; result.y *= 2.0 / frame_shape.y; } } result.z *= -1; return result; } ================================================ FILE: manim/renderer/shaders/include/get_rotated_surface_unit_normal_vector.glsl ================================================ // Assumes the following uniforms exist in the surrounding context: // uniform vec3 camera_center; // uniform mat3 camera_rotation; vec3 get_rotated_surface_unit_normal_vector(vec3 point, vec3 du_point, vec3 dv_point){ vec3 cp = cross( (du_point - point), (dv_point - point) ); if(length(cp) == 0){ // Instead choose a normal to just dv_point - point in the direction of point vec3 v2 = dv_point - point; cp = cross(cross(v2, point), v2); } return normalize(rotate_point_into_frame(cp)); } ================================================ FILE: manim/renderer/shaders/include/get_unit_normal.glsl ================================================ vec3 get_unit_normal(in vec3[3] points){ float tol = 1e-6; vec3 v1 = normalize(points[1] - points[0]); vec3 v2 = normalize(points[2] - points[0]); vec3 cp = cross(v1, v2); float cp_norm = length(cp); if(cp_norm < tol){ // Three points form a line, so find a normal vector // to that line in the plane shared with the z-axis vec3 k_hat = vec3(0.0, 0.0, 1.0); vec3 new_cp = cross(cross(v2, k_hat), v2); float new_cp_norm = length(new_cp); if(new_cp_norm < tol){ // We only come here if all three points line up // on the z-axis. return vec3(0.0, -1.0, 0.0); // return k_hat; } return new_cp / new_cp_norm; } return cp / cp_norm; } ================================================ FILE: manim/renderer/shaders/include/position_point_into_frame.glsl ================================================ // Assumes the following uniforms exist in the surrounding context: // uniform float is_fixed_in_frame; // uniform float is_fixed_orientation; // uniform vec3 fixed_orientation_center; // uniform vec3 camera_center; // uniform mat3 camera_rotation; vec3 rotate_point_into_frame(vec3 point){ if(bool(is_fixed_in_frame)){ return point; } return camera_rotation * point; } vec3 position_point_into_frame(vec3 point){ if(bool(is_fixed_in_frame)){ return point; } if(bool(is_fixed_orientation)){ vec3 new_center = rotate_point_into_frame(fixed_orientation_center); return point + (new_center - fixed_orientation_center); } return rotate_point_into_frame(point - camera_center); } ================================================ FILE: manim/renderer/shaders/include/quadratic_bezier_distance.glsl ================================================ // Must be inserted in a context with a definition for modify_distance_for_endpoints // All of this is with respect to a curve that's been rotated/scaled // so that b0 = (0, 0) and b1 = (1, 0). That is, b2 entirely // determines the shape of the curve vec2 bezier(float t, vec2 b2){ // Quick returns for the 0 and 1 cases if (t == 0) return vec2(0, 0); else if (t == 1) return b2; // Everything else return vec2( 2 * t * (1 - t) + b2.x * t*t, b2.y * t * t ); } float cube_root(float x){ return sign(x) * pow(abs(x), 1.0 / 3.0); } int cubic_solve(float a, float b, float c, float d, out float roots[3]){ // Normalize so a = 1 b = b / a; c = c / a; d = d / a; float p = c - b*b / 3.0; float q = b * (2.0*b*b - 9.0*c) / 27.0 + d; float p3 = p*p*p; float disc = q*q + 4.0*p3 / 27.0; float offset = -b / 3.0; if(disc >= 0.0){ float z = sqrt(disc); float u = (-q + z) / 2.0; float v = (-q - z) / 2.0; u = cube_root(u); v = cube_root(v); roots[0] = offset + u + v; return 1; } float u = sqrt(-p / 3.0); float v = acos(-sqrt( -27.0 / p3) * q / 2.0) / 3.0; float m = cos(v); float n = sin(v) * 1.732050808; float all_roots[3] = float[3]( offset + u * (n - m), offset - u * (n + m), offset + u * (m + m) ); // Only accept roots with a positive derivative int n_valid_roots = 0; for(int i = 0; i < 3; i++){ float r = all_roots[i]; if(3*r*r + 2*b*r + c > 0){ roots[n_valid_roots] = r; n_valid_roots++; } } return n_valid_roots; } float dist_to_line(vec2 p, vec2 b2){ float t = clamp(p.x / b2.x, 0, 1); float dist; if(t == 0) dist = length(p); else if(t == 1) dist = distance(p, b2); else dist = abs(p.y); return modify_distance_for_endpoints(p, dist, t); } float dist_to_point_on_curve(vec2 p, float t, vec2 b2){ t = clamp(t, 0, 1); return modify_distance_for_endpoints( p, length(p - bezier(t, b2)), t ); } float min_dist_to_curve(vec2 p, vec2 b2, float degree){ // Check if curve is really a a line if(degree == 1) return dist_to_line(p, b2); // Try finding the exact sdf by solving the equation // (d/dt) dist^2(t) = 0, which amount to the following // cubic. float xm2 = uv_b2.x - 2.0; float y = uv_b2.y; float a = xm2*xm2 + y*y; float b = 3 * xm2; float c = -(p.x*xm2 + p.y*y) + 2; float d = -p.x; float roots[3]; int n = cubic_solve(a, b, c, d, roots); // At most 2 roots will have been populated. float d0 = dist_to_point_on_curve(p, roots[0], b2); if(n == 1) return d0; float d1 = dist_to_point_on_curve(p, roots[1], b2); return min(d0, d1); } ================================================ FILE: manim/renderer/shaders/include/quadratic_bezier_geometry_functions.glsl ================================================ float cross2d(vec2 v, vec2 w){ return v.x * w.y - w.x * v.y; } mat3 get_xy_to_uv(vec2 b0, vec2 b1){ mat3 shift = mat3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, -b0.x, -b0.y, 1.0 ); float sf = length(b1 - b0); vec2 I = (b1 - b0) / sf; vec2 J = vec2(-I.y, I.x); mat3 rotate = mat3( I.x, J.x, 0.0, I.y, J.y, 0.0, 0.0, 0.0, 1.0 ); return (1 / sf) * rotate * shift; } // Orthogonal matrix to convert to a uv space defined so that // b0 goes to [0, 0] and b1 goes to [1, 0] mat4 get_xyz_to_uv(vec3 b0, vec3 b1, vec3 unit_normal){ mat4 shift = mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -b0.x, -b0.y, -b0.z, 1 ); float scale_factor = length(b1 - b0); vec3 I = (b1 - b0) / scale_factor; vec3 K = unit_normal; vec3 J = cross(K, I); // Transpose (hence inverse) of matrix taking // i-hat to I, k-hat to unit_normal, and j-hat to their cross mat4 rotate = mat4( I.x, J.x, K.x, 0.0, I.y, J.y, K.y, 0.0, I.z, J.z, K.z, 0.0, 0.0, 0.0, 0.0, 1.0 ); return (1 / scale_factor) * rotate * shift; } // Returns 0 for null curve, 1 for linear, 2 for quadratic. // Populates new_points with bezier control points for the curve, // which for quadratics will be the same, but for linear and null // might change. The idea is to inform the caller of the degree, // while also passing tangency information in the linear case. // float get_reduced_control_points(vec3 b0, vec3 b1, vec3 b2, out vec3 new_points[3]){ float get_reduced_control_points(in vec3 points[3], out vec3 new_points[3]){ float length_threshold = 1e-6; float angle_threshold = 5e-2; vec3 p0 = points[0]; vec3 p1 = points[1]; vec3 p2 = points[2]; vec3 v01 = (p1 - p0); vec3 v12 = (p2 - p1); float dot_prod = clamp(dot(normalize(v01), normalize(v12)), -1, 1); bool aligned = acos(dot_prod) < angle_threshold; bool distinct_01 = length(v01) > length_threshold; // v01 is considered nonzero bool distinct_12 = length(v12) > length_threshold; // v12 is considered nonzero int n_uniques = int(distinct_01) + int(distinct_12); bool quadratic = (n_uniques == 2) && !aligned; bool linear = (n_uniques == 1) || ((n_uniques == 2) && aligned); bool constant = (n_uniques == 0); if(quadratic){ new_points[0] = p0; new_points[1] = p1; new_points[2] = p2; return 2.0; }else if(linear){ new_points[0] = p0; new_points[1] = (p0 + p2) / 2.0; new_points[2] = p2; return 1.0; }else{ new_points[0] = p0; new_points[1] = p0; new_points[2] = p0; return 0.0; } } ================================================ FILE: manim/renderer/shaders/manim_coords/frag.glsl ================================================ #version 330 uniform vec4 u_color; out vec4 frag_color; void main() { frag_color = u_color; } ================================================ FILE: manim/renderer/shaders/manim_coords/vert.glsl ================================================ #version 330 in vec4 in_vert; uniform mat4 u_model_view_matrix; uniform mat4 u_projection_matrix; void main() { vec4 camera_space_vertex = u_model_view_matrix * in_vert; vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex; gl_Position = clip_space_vertex; } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_fill/frag.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec4 color; in float fill_all; // Either 0 or 1e in float uv_anti_alias_width; in vec3 xyz_coords; in float orientation; in vec2 uv_coords; in vec2 uv_b2; in float bezier_degree; out vec4 frag_color; // Needed for quadratic_bezier_distance insertion below float modify_distance_for_endpoints(vec2 p, float dist, float t){ return dist; } #include ../include/quadratic_bezier_distance.glsl float sdf(){ if(bezier_degree < 2){ return abs(uv_coords[1]); } float u2 = uv_b2.x; float v2 = uv_b2.y; // For really flat curves, just take the distance to x-axis if(abs(v2 / u2) < 0.1 * uv_anti_alias_width){ return abs(uv_coords[1]); } // For flat-ish curves, take the curve else if(abs(v2 / u2) < 0.5 * uv_anti_alias_width){ return min_dist_to_curve(uv_coords, uv_b2, bezier_degree); } // I know, I don't love this amount of arbitrary-seeming branching either, // but a number of strange dimples and bugs pop up otherwise. // This converts uv_coords to yet another space where the bezier points sit on // (0, 0), (1/2, 0) and (1, 1), so that the curve can be expressed implicityly // as y = x^2. mat2 to_simple_space = mat2( v2, 0, 2 - u2, 4 * v2 ); vec2 p = to_simple_space * uv_coords; // Sign takes care of whether we should be filling the inside or outside of curve. float sgn = orientation * sign(v2); float Fp = (p.x * p.x - p.y); if(sgn * Fp < 0){ return 0.0; }else{ return min_dist_to_curve(uv_coords, uv_b2, bezier_degree); } } void main() { if (color.a == 0) discard; frag_color = color; if (fill_all == 1.0) return; frag_color.a *= smoothstep(1, 0, sdf() / uv_anti_alias_width); } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_fill/geom.glsl ================================================ #version 330 layout (triangles) in; layout (triangle_strip, max_vertices = 5) out; uniform float anti_alias_width; // Needed for get_gl_Position uniform vec2 frame_shape; uniform float focal_distance; uniform float is_fixed_in_frame; uniform float is_fixed_orientation; uniform vec3 fixed_orientation_center; // Needed for finalize_color uniform vec3 light_source_position; uniform float gloss; uniform float shadow; in vec3 bp[3]; in vec3 v_global_unit_normal[3]; in vec4 v_color[3]; in float v_vert_index[3]; out vec4 color; out float fill_all; out float uv_anti_alias_width; out vec3 xyz_coords; out float orientation; // uv space is where b0 = (0, 0), b1 = (1, 0), and transform is orthogonal out vec2 uv_coords; out vec2 uv_b2; out float bezier_degree; // Analog of import for manim only #include ../include/quadratic_bezier_geometry_functions.glsl #include ../include/get_gl_Position.glsl #include ../include/get_unit_normal.glsl #include ../include/finalize_color.glsl void emit_vertex_wrapper(vec3 point, int index){ color = finalize_color( v_color[index], point, v_global_unit_normal[index], light_source_position, gloss, shadow ); xyz_coords = point; gl_Position = get_gl_Position(xyz_coords); EmitVertex(); } void emit_simple_triangle(){ for(int i = 0; i < 3; i++){ emit_vertex_wrapper(bp[i], i); } EndPrimitive(); } void emit_pentagon(vec3[3] points, vec3 normal){ vec3 p0 = points[0]; vec3 p1 = points[1]; vec3 p2 = points[2]; // Tangent vectors vec3 t01 = normalize(p1 - p0); vec3 t12 = normalize(p2 - p1); // Vectors perpendicular to the curve in the plane of the curve pointing outside the curve vec3 p0_perp = cross(t01, normal); vec3 p2_perp = cross(t12, normal); bool fill_inside = orientation > 0; float aaw = anti_alias_width; vec3 corners[5]; if(fill_inside){ // Note, straight lines will also fall into this case, and since p0_perp and p2_perp // will point to the right of the curve, it's just what we want corners = vec3[5]( p0 + aaw * p0_perp, p0, p1 + 0.5 * aaw * (p0_perp + p2_perp), p2, p2 + aaw * p2_perp ); }else{ corners = vec3[5]( p0, p0 - aaw * p0_perp, p1, p2 - aaw * p2_perp, p2 ); } mat4 xyz_to_uv = get_xyz_to_uv(p0, p1, normal); uv_b2 = (xyz_to_uv * vec4(p2, 1)).xy; uv_anti_alias_width = anti_alias_width / length(p1 - p0); for(int i = 0; i < 5; i++){ vec3 corner = corners[i]; uv_coords = (xyz_to_uv * vec4(corner, 1)).xy; int j = int(sign(i - 1) + 1); // Maps i = [0, 1, 2, 3, 4] onto j = [0, 0, 1, 2, 2] emit_vertex_wrapper(corner, j); } EndPrimitive(); } void main(){ // If vert indices are sequential, don't fill all fill_all = float( (v_vert_index[1] - v_vert_index[0]) != 1.0 || (v_vert_index[2] - v_vert_index[1]) != 1.0 ); if(fill_all == 1.0){ emit_simple_triangle(); return; } vec3 new_bp[3]; bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), new_bp); vec3 local_unit_normal = get_unit_normal(new_bp); orientation = sign(dot(v_global_unit_normal[0], local_unit_normal)); if(bezier_degree >= 1){ emit_pentagon(new_bp, local_unit_normal); } // Don't emit any vertices for bezier_degree 0 } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_fill/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; in vec3 unit_normal; in vec4 color; in float vert_index; out vec3 bp; // Bezier control point out vec3 v_global_unit_normal; out vec4 v_color; out float v_vert_index; // Analog of import for manim only #include ../include/position_point_into_frame.glsl void main(){ bp = position_point_into_frame(point.xyz); v_global_unit_normal = rotate_point_into_frame(unit_normal.xyz); v_color = color; v_vert_index = vert_index; } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_stroke/frag.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec2 uv_coords; in vec2 uv_b2; in float uv_stroke_width; in vec4 color; in float uv_anti_alias_width; in float has_prev; in float has_next; in float bevel_start; in float bevel_end; in float angle_from_prev; in float angle_to_next; in float bezier_degree; out vec4 frag_color; float cross2d(vec2 v, vec2 w){ return v.x * w.y - w.x * v.y; } float modify_distance_for_endpoints(vec2 p, float dist, float t){ float buff = 0.5 * uv_stroke_width - uv_anti_alias_width; // Check the beginning of the curve if(t == 0){ // Clip the start if(has_prev == 0) return max(dist, -p.x + buff); // Bevel start if(bevel_start == 1){ float a = angle_from_prev; mat2 rot = mat2( cos(a), sin(a), -sin(a), cos(a) ); // Dist for intersection of two lines float bevel_d = max(abs(p.y), abs((rot * p).y)); // Dist for union of this intersection with the real curve // intersected with radius 2 away from curve to smooth out // really sharp corners return max(min(dist, bevel_d), dist / 2); } // Otherwise, start will be rounded off }else if(t == 1){ // Check the end of the curve // TODO, too much code repetition vec2 v21 = (bezier_degree == 2) ? vec2(1, 0) - uv_b2 : vec2(-1, 0); float len_v21 = length(v21); if(len_v21 == 0){ v21 = -uv_b2; len_v21 = length(v21); } float perp_dist = dot(p - uv_b2, v21) / len_v21; if(has_next == 0) return max(dist, -perp_dist + buff); // Bevel end if(bevel_end == 1){ float a = -angle_to_next; mat2 rot = mat2( cos(a), sin(a), -sin(a), cos(a) ); vec2 v21_unit = v21 / length(v21); float bevel_d = max( abs(cross2d(p - uv_b2, v21_unit)), abs(cross2d((rot * (p - uv_b2)), v21_unit)) ); return max(min(dist, bevel_d), dist / 2); } // Otherwise, end will be rounded off } return dist; } #include ../include/quadratic_bezier_distance.glsl void main() { if (uv_stroke_width == 0) discard; float dist_to_curve = min_dist_to_curve(uv_coords, uv_b2, bezier_degree); // An sdf for the region around the curve we wish to color. float signed_dist = abs(dist_to_curve) - 0.5 * uv_stroke_width; frag_color = color; frag_color.a *= smoothstep(0.5, -0.5, signed_dist / uv_anti_alias_width); } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_stroke/geom.glsl ================================================ #version 330 layout (triangles) in; layout (triangle_strip, max_vertices = 5) out; // Needed for get_gl_Position uniform vec2 frame_shape; uniform float focal_distance; uniform float is_fixed_in_frame; uniform float is_fixed_orientation; uniform vec3 fixed_orientation_center; uniform float anti_alias_width; uniform float flat_stroke; //Needed for lighting uniform vec3 light_source_position; uniform float joint_type; uniform float gloss; uniform float shadow; in vec3 bp[3]; in vec3 prev_bp[3]; in vec3 next_bp[3]; in vec3 v_global_unit_normal[3]; in vec4 v_color[3]; in float v_stroke_width[3]; out vec4 color; out float uv_stroke_width; out float uv_anti_alias_width; out float has_prev; out float has_next; out float bevel_start; out float bevel_end; out float angle_from_prev; out float angle_to_next; out float bezier_degree; out vec2 uv_coords; out vec2 uv_b2; // Codes for joint types const float AUTO_JOINT = 0; const float ROUND_JOINT = 1; const float BEVEL_JOINT = 2; const float MITER_JOINT = 3; const float PI = 3.141592653; #include ../include/quadratic_bezier_geometry_functions.glsl #include ../include/get_gl_Position.glsl #include ../include/get_unit_normal.glsl #include ../include/finalize_color.glsl void flatten_points(in vec3[3] points, out vec2[3] flat_points){ for(int i = 0; i < 3; i++){ float sf = perspective_scale_factor(points[i].z, focal_distance); flat_points[i] = sf * points[i].xy; } } float angle_between_vectors(vec2 v1, vec2 v2){ float v1_norm = length(v1); float v2_norm = length(v2); if(v1_norm == 0 || v2_norm == 0) return 0.0; float dp = dot(v1, v2) / (v1_norm * v2_norm); float angle = acos(clamp(dp, -1.0, 1.0)); float sn = sign(cross2d(v1, v2)); return sn * angle; } bool find_intersection(vec2 p0, vec2 v0, vec2 p1, vec2 v1, out vec2 intersection){ // Find the intersection of a line passing through // p0 in the direction v0 and one passing through p1 in // the direction p1. // That is, find a solutoin to p0 + v0 * t = p1 + v1 * s float det = -v0.x * v1.y + v1.x * v0.y; if(det == 0) return false; float t = cross2d(p0 - p1, v1) / det; intersection = p0 + v0 * t; return true; } void create_joint(float angle, vec2 unit_tan, float buff, vec2 static_c0, out vec2 changing_c0, vec2 static_c1, out vec2 changing_c1){ float shift; if(abs(angle) < 1e-3){ // No joint shift = 0; }else if(joint_type == MITER_JOINT){ shift = buff * (-1.0 - cos(angle)) / sin(angle); }else{ // For a Bevel joint shift = buff * (1.0 - cos(angle)) / sin(angle); } changing_c0 = static_c0 - shift * unit_tan; changing_c1 = static_c1 + shift * unit_tan; } // This function is responsible for finding the corners of // a bounding region around the bezier curve, which can be // emitted as a triangle fan int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 corners[5]){ vec2 p0 = controls[0]; vec2 p1 = controls[1]; vec2 p2 = controls[2]; // Unit vectors for directions between control points vec2 v10 = normalize(p0 - p1); vec2 v12 = normalize(p2 - p1); vec2 v01 = -v10; vec2 v21 = -v12; vec2 p0_perp = vec2(-v01.y, v01.x); // Pointing to the left of the curve from p0 vec2 p2_perp = vec2(-v12.y, v12.x); // Pointing to the left of the curve from p2 // aaw is the added width given around the polygon for antialiasing. // In case the normal is faced away from (0, 0, 1), the vector to the // camera, this is scaled up. float aaw = anti_alias_width; float buff0 = 0.5 * stroke_widths[0] + aaw; float buff2 = 0.5 * stroke_widths[2] + aaw; float aaw0 = (1 - has_prev) * aaw; float aaw2 = (1 - has_next) * aaw; vec2 c0 = p0 - buff0 * p0_perp + aaw0 * v10; vec2 c1 = p0 + buff0 * p0_perp + aaw0 * v10; vec2 c2 = p2 + buff2 * p2_perp + aaw2 * v12; vec2 c3 = p2 - buff2 * p2_perp + aaw2 * v12; // Account for previous and next control points if(has_prev > 0) create_joint(angle_from_prev, v01, buff0, c0, c0, c1, c1); if(has_next > 0) create_joint(angle_to_next, v21, buff2, c3, c3, c2, c2); // Linear case is the simplest if(degree == 1){ // The order of corners should be for a triangle_strip. Last entry is a dummy corners = vec2[5](c0, c1, c3, c2, vec2(0.0)); return 4; } // Otherwise, form a pentagon around the curve float orientation = sign(cross2d(v01, v12)); // Positive for ccw curves if(orientation > 0) corners = vec2[5](c0, c1, p1, c2, c3); else corners = vec2[5](c1, c0, p1, c3, c2); // Replace corner[2] with convex hull point accounting for stroke width find_intersection(corners[0], v01, corners[4], v21, corners[2]); return 5; } void set_adjascent_info(vec2 c0, vec2 tangent, int degree, vec2 adj[3], out float bevel, out float angle ){ bool linear_adj = (angle_between_vectors(adj[1] - adj[0], adj[2] - adj[1]) < 1e-3); angle = angle_between_vectors(c0 - adj[1], tangent); // Decide on joint type bool one_linear = (degree == 1 || linear_adj); bool should_bevel = ( (joint_type == AUTO_JOINT && one_linear) || joint_type == BEVEL_JOINT ); bevel = should_bevel ? 1.0 : 0.0; } void find_joint_info(vec2 controls[3], vec2 prev[3], vec2 next[3], int degree){ float tol = 1e-6; // Made as floats not bools so they can be passed to the frag shader has_prev = float(distance(prev[2], controls[0]) < tol); has_next = float(distance(next[0], controls[2]) < tol); if(bool(has_prev)){ vec2 tangent = controls[1] - controls[0]; set_adjascent_info( controls[0], tangent, degree, prev, bevel_start, angle_from_prev ); } if(bool(has_next)){ vec2 tangent = controls[1] - controls[2]; set_adjascent_info( controls[2], tangent, degree, next, bevel_end, angle_to_next ); angle_to_next *= -1; } } void main() { // Convert control points to a standard form if they are linear or null vec3 controls[3]; vec3 prev[3]; vec3 next[3]; bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), controls); if(bezier_degree == 0.0) return; // Null curve int degree = int(bezier_degree); get_reduced_control_points(vec3[3](prev_bp[0], prev_bp[1], prev_bp[2]), prev); get_reduced_control_points(vec3[3](next_bp[0], next_bp[1], next_bp[2]), next); // Adjust stroke width based on distance from the camera float scaled_strokes[3]; for(int i = 0; i < 3; i++){ float sf = perspective_scale_factor(controls[i].z, focal_distance); if(bool(flat_stroke)){ vec3 to_cam = normalize(vec3(0.0, 0.0, focal_distance) - controls[i]); sf *= abs(dot(v_global_unit_normal[i], to_cam)); } scaled_strokes[i] = v_stroke_width[i] * sf; } // Control points are projected to the xy plane before drawing, which in turn // gets translated to a uv plane. The z-coordinate information will be remembered // by what's sent out to gl_Position, and by how it affects the lighting and stroke width vec2 flat_controls[3]; vec2 flat_prev[3]; vec2 flat_next[3]; flatten_points(controls, flat_controls); flatten_points(prev, flat_prev); flatten_points(next, flat_next); find_joint_info(flat_controls, flat_prev, flat_next, degree); // Corners of a bounding region around curve vec2 corners[5]; int n_corners = get_corners(flat_controls, degree, scaled_strokes, corners); int index_map[5] = int[5](0, 0, 1, 2, 2); if(n_corners == 4) index_map[2] = 2; // Find uv conversion matrix mat3 xy_to_uv = get_xy_to_uv(flat_controls[0], flat_controls[1]); float scale_factor = length(flat_controls[1] - flat_controls[0]); uv_anti_alias_width = anti_alias_width / scale_factor; uv_b2 = (xy_to_uv * vec3(flat_controls[2], 1.0)).xy; // Emit each corner for(int i = 0; i < n_corners; i++){ uv_coords = (xy_to_uv * vec3(corners[i], 1.0)).xy; uv_stroke_width = scaled_strokes[index_map[i]] / scale_factor; // Apply some lighting to the color before sending out. // vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z); vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z); color = finalize_color( v_color[index_map[i]], xyz_coords, v_global_unit_normal[index_map[i]], light_source_position, gloss, shadow ); gl_Position = vec4( get_gl_Position(vec3(corners[i], 0.0)).xy, get_gl_Position(controls[index_map[i]]).zw ); EmitVertex(); } EndPrimitive(); } ================================================ FILE: manim/renderer/shaders/quadratic_bezier_stroke/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; in vec3 prev_point; in vec3 next_point; in vec3 unit_normal; in float stroke_width; in vec4 color; // Bezier control point out vec3 bp; out vec3 prev_bp; out vec3 next_bp; out vec3 v_global_unit_normal; out float v_stroke_width; out vec4 v_color; const float STROKE_WIDTH_CONVERSION = 0.01; #include ../include/position_point_into_frame.glsl void main(){ bp = position_point_into_frame(point); prev_bp = position_point_into_frame(prev_point); next_bp = position_point_into_frame(next_point); v_global_unit_normal = rotate_point_into_frame(unit_normal); v_stroke_width = STROKE_WIDTH_CONVERSION * stroke_width; v_color = color; } ================================================ FILE: manim/renderer/shaders/simple_vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; // Analog of import for manim only #include ../include/get_gl_Position.glsl #include ../include/position_point_into_frame.glsl void main(){ gl_Position = get_gl_Position(position_point_into_frame(point)); } ================================================ FILE: manim/renderer/shaders/surface/frag.glsl ================================================ #version 330 uniform vec3 light_source_position; uniform float gloss; uniform float shadow; in vec3 xyz_coords; in vec3 v_normal; in vec4 v_color; out vec4 frag_color; #include ../include/finalize_color.glsl void main() { frag_color = finalize_color( v_color, xyz_coords, normalize(v_normal), light_source_position, gloss, shadow ); } ================================================ FILE: manim/renderer/shaders/surface/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; in vec3 du_point; in vec3 dv_point; in vec4 color; out vec3 xyz_coords; out vec3 v_normal; out vec4 v_color; #include ../include/position_point_into_frame.glsl #include ../include/get_gl_Position.glsl #include ../include/get_rotated_surface_unit_normal_vector.glsl void main(){ xyz_coords = position_point_into_frame(point); v_normal = get_rotated_surface_unit_normal_vector(point, du_point, dv_point); v_color = color; gl_Position = get_gl_Position(xyz_coords); } ================================================ FILE: manim/renderer/shaders/test/frag.glsl ================================================ #version 330 in vec4 v_color; out vec4 frag_color; void main() { frag_color = v_color; } ================================================ FILE: manim/renderer/shaders/test/vert.glsl ================================================ #version 330 in vec2 in_vert; in vec4 in_color; out vec4 v_color; void main() { v_color = in_color; gl_Position = vec4(in_vert, 0.0, 1.0); } ================================================ FILE: manim/renderer/shaders/textured_surface/frag.glsl ================================================ #version 330 uniform sampler2D LightTexture; uniform sampler2D DarkTexture; uniform float num_textures; uniform vec3 light_source_position; uniform float gloss; uniform float shadow; in vec3 xyz_coords; in vec3 v_normal; in vec2 v_im_coords; in float v_opacity; out vec4 frag_color; #include ../include/finalize_color.glsl const float dark_shift = 0.2; void main() { vec4 color = texture(LightTexture, v_im_coords); if(num_textures == 2.0){ vec4 dark_color = texture(DarkTexture, v_im_coords); float dp = dot( normalize(light_source_position - xyz_coords), normalize(v_normal) ); float alpha = smoothstep(-dark_shift, dark_shift, dp); color = mix(dark_color, color, alpha); } frag_color = finalize_color( color, xyz_coords, normalize(v_normal), light_source_position, gloss, shadow ); frag_color.a = v_opacity; } ================================================ FILE: manim/renderer/shaders/textured_surface/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; in vec3 du_point; in vec3 dv_point; in vec2 im_coords; in float opacity; out vec3 xyz_coords; out vec3 v_normal; out vec2 v_im_coords; out float v_opacity; #include ../include/position_point_into_frame.glsl #include ../include/get_gl_Position.glsl #include ../include/get_rotated_surface_unit_normal_vector.glsl void main(){ xyz_coords = position_point_into_frame(point); v_normal = get_rotated_surface_unit_normal_vector(point, du_point, dv_point); v_im_coords = im_coords; v_opacity = opacity; gl_Position = get_gl_Position(xyz_coords); } ================================================ FILE: manim/renderer/shaders/true_dot/frag.glsl ================================================ #version 330 uniform vec3 light_source_position; uniform float gloss; uniform float shadow; uniform float anti_alias_width; in vec4 color; in float point_radius; in vec2 center; in vec2 point; out vec4 frag_color; #include ../include/finalize_color.glsl void main() { vec2 diff = point - center; float dist = length(diff); float signed_dist = dist - point_radius; if (signed_dist > 0.5 * anti_alias_width){ discard; } vec3 normal = vec3(diff / point_radius, sqrt(1 - (dist * dist) / (point_radius * point_radius))); frag_color = finalize_color( color, vec3(point.xy, 0.0), normal, light_source_position, gloss, shadow ); frag_color.a *= smoothstep(0.5, -0.5, signed_dist / anti_alias_width); } ================================================ FILE: manim/renderer/shaders/true_dot/geom.glsl ================================================ #version 330 layout (points) in; layout (triangle_strip, max_vertices = 4) out; // Needed for get_gl_Position uniform vec2 frame_shape; uniform float focal_distance; uniform float is_fixed_in_frame; uniform float is_fixed_orientation; uniform vec3 fixed_orientation_center; uniform float anti_alias_width; in vec3 v_point[1]; in float v_point_radius[1]; in vec4 v_color[1]; out vec4 color; out float point_radius; out vec2 center; out vec2 point; #include ../include/get_gl_Position.glsl void main() { color = v_color[0]; point_radius = v_point_radius[0]; center = v_point[0].xy; point_radius = v_point_radius[0] / max(1.0 - v_point[0].z / focal_distance / frame_shape.y, 0.0); float rpa = point_radius + anti_alias_width; for(int i = 0; i < 4; i++){ // To account for perspective int x_index = 2 * (i % 2) - 1; int y_index = 2 * (i / 2) - 1; vec3 corner = v_point[0] + vec3(x_index * rpa, y_index * rpa, 0.0); gl_Position = get_gl_Position(corner); point = corner.xy; EmitVertex(); } EndPrimitive(); } ================================================ FILE: manim/renderer/shaders/true_dot/vert.glsl ================================================ #version 330 #include ../include/camera_uniform_declarations.glsl in vec3 point; in vec4 color; uniform float point_radius; out vec3 v_point; out float v_point_radius; out vec4 v_color; #include ../include/position_point_into_frame.glsl void main(){ v_point = position_point_into_frame(point); v_point_radius = point_radius; v_color = color; } ================================================ FILE: manim/renderer/shaders/vectorized_mobject_fill/frag.glsl ================================================ #version 330 in vec4 v_color; in vec2 v_texture_coords; flat in int v_texture_mode; out vec4 frag_color; void main() { float curve_func = v_texture_coords[0] * v_texture_coords[0] - v_texture_coords[1]; if (v_texture_mode * curve_func >= 0.0) { frag_color = v_color; } else { discard; } } ================================================ FILE: manim/renderer/shaders/vectorized_mobject_fill/vert.glsl ================================================ #version 330 uniform mat4 u_model_view_matrix; uniform mat4 u_projection_matrix; in vec3 in_vert; in vec4 in_color; in vec2 texture_coords; in int texture_mode; out vec4 v_color; out vec2 v_texture_coords; flat out int v_texture_mode; void main() { v_color = in_color; v_texture_coords = texture_coords; v_texture_mode = texture_mode; gl_Position = u_projection_matrix * u_model_view_matrix * vec4(in_vert, 1.0); } ================================================ FILE: manim/renderer/shaders/vectorized_mobject_stroke/frag.glsl ================================================ #version 330 in float v_degree; in float v_thickness; in vec2 uv_point; in vec2[3] uv_curve; in vec4 v_color; out vec4 frag_color; // https://www.shadertoy.com/view/ltXSDB // Test if point p crosses line (a, b), returns sign of result float testCross(vec2 a, vec2 b, vec2 p) { return sign((b.y-a.y) * (p.x-a.x) - (b.x-a.x) * (p.y-a.y)); } // Determine which side we're on (using barycentric parameterization) float signBezier(vec2 A, vec2 B, vec2 C, vec2 p) { vec2 a = C - A, b = B - A, c = p - A; vec2 bary = vec2(c.x*b.y-b.x*c.y,a.x*c.y-c.x*a.y) / (a.x*b.y-b.x*a.y); vec2 d = vec2(bary.y * 0.5, 0.0) + 1.0 - bary.x - bary.y; return mix(sign(d.x * d.x - d.y), mix(-1.0, 1.0, step(testCross(A, B, p) * testCross(B, C, p), 0.0)), step((d.x - d.y), 0.0)) * testCross(A, C, B); } // Solve cubic equation for roots vec3 solveCubic(float a, float b, float c) { float p = b - a*a / 3.0, p3 = p*p*p; float q = a * (2.0*a*a - 9.0*b) / 27.0 + c; float d = q*q + 4.0*p3 / 27.0; float offset = -a / 3.0; if(d >= 0.0) { float z = sqrt(d); vec2 x = (vec2(z, -z) - q) / 2.0; vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0)); return vec3(offset + uv.x + uv.y); } float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0; float m = cos(v), n = sin(v)*1.732050808; return vec3(m + m, -n - m, n - m) * sqrt(-p / 3.0) + offset; } // Find the signed distance from a point to a bezier curve float sdBezier(vec2 A, vec2 B, vec2 C, vec2 p) { B = mix(B + vec2(1e-4), B, abs(sign(B * 2.0 - A - C))); vec2 a = B - A, b = A - B * 2.0 + C, c = a * 2.0, d = A - p; vec3 k = vec3(3.*dot(a,b),2.*dot(a,a)+dot(d,b),dot(d,a)) / dot(b,b); vec3 t = clamp(solveCubic(k.x, k.y, k.z), 0.0, 1.0); vec2 pos = A + (c + b*t.x)*t.x; float dis = length(pos - p); pos = A + (c + b*t.y)*t.y; dis = min(dis, length(pos - p)); pos = A + (c + b*t.z)*t.z; dis = min(dis, length(pos - p)); return dis * signBezier(A, B, C, p); } // https://www.shadertoy.com/view/llcfR7 float dLine(vec2 p1, vec2 p2, vec2 x) { vec4 colA = vec4(clamp (5.0 - length (x - p1), 0.0, 1.0)); vec4 colB = vec4(clamp (5.0 - length (x - p2), 0.0, 1.0)); vec2 a_p1 = x - p1; vec2 p2_p1 = p2 - p1; float h = clamp (dot (a_p1, p2_p1) / dot (p2_p1, p2_p1), 0.0, 1.0); return length (a_p1 - p2_p1 * h); } void main() { float distance; if (v_degree == 2.0) { distance = sdBezier(uv_curve[0], uv_curve[1], uv_curve[2], uv_point); } else { distance = dLine(uv_curve[0], uv_curve[2], uv_point); } if (abs(distance) < v_thickness) { frag_color = v_color; } else { discard; } } ================================================ FILE: manim/renderer/shaders/vectorized_mobject_stroke/vert.glsl ================================================ #version 330 uniform vec3 manim_unit_normal; uniform mat4 u_model_view_matrix; uniform mat4 u_projection_matrix; in vec3[3] current_curve; in vec2 tile_coordinate; in vec4 in_color; in float in_width; out float v_degree; out float v_thickness; out vec2 uv_point; out vec2[3] uv_curve; out vec4 v_color; int get_degree(in vec3 points[3], out vec3 normal) { float length_threshold = 1e-6; float angle_threshold = 5e-2; vec3 v01 = (points[1] - points[0]); vec3 v12 = (points[2] - points[1]); float dot_prod = clamp(dot(normalize(v01), normalize(v12)), -1, 1); bool aligned = acos(dot_prod) < angle_threshold; bool distinct_01 = length(v01) > length_threshold; // v01 is considered nonzero bool distinct_12 = length(v12) > length_threshold; // v12 is considered nonzero int num_distinct = int(distinct_01) + int(distinct_12); bool quadratic = (num_distinct == 2) && !aligned; bool linear = (num_distinct == 1) || ((num_distinct == 2) && aligned); bool constant = (num_distinct == 0); if (quadratic) { // If the curve is quadratic pass a normal vector to the caller. normal = normalize(cross(v01, v12)); return 2; } else if (linear) { return 1; } else { return 0; } } // https://iquilezles.org/www/articles/bezierbbox/bezierbbox.htm vec4 bboxBezier(in vec2 p0, in vec2 p1, in vec2 p2) { vec2 mi = min(p0, p2); vec2 ma = max(p0, p2); if (p1.x < mi.x || p1.x > ma.x || p1.y < mi.y || p1.y > ma.y) { vec2 t = clamp((p0 - p1) / (p0 - 2.0 * p1 + p2), 0.0, 1.0); vec2 s = 1.0 - t; vec2 q = s * s * p0 + 2.0 * s * t * p1 + t * t * p2; mi = min(mi, q); ma = max(ma, q); } return vec4(mi, ma); } vec2 convert_to_uv(vec3 x_unit, vec3 y_unit, vec3 point) { return vec2(dot(point, x_unit), dot(point, y_unit)); } vec3 convert_from_uv(vec3 translation, vec3 x_unit, vec3 y_unit, vec2 point) { vec3 untranslated_point = point[0] * x_unit + point[1] * y_unit; return untranslated_point + translation; } void main() { float thickness_multiplier = 0.004; v_color = in_color; vec3 computed_normal; v_degree = get_degree(current_curve, computed_normal); vec3 tile_x_unit = normalize(current_curve[2] - current_curve[0]); vec3 unit_normal; vec3 tile_y_unit; if (v_degree == 0) { tile_y_unit = vec3(0.0, 0.0, 0.0); } else if (v_degree == 1) { // Since the curve forms a straight line there's no way to compute a normal. unit_normal = manim_unit_normal; tile_y_unit = cross(unit_normal, tile_x_unit); } else { // Prefer to use a computed normal vector rather than the one from manim. unit_normal = computed_normal; // Ensure tile_y_unit is pointing toward p1 from p0. tile_y_unit = cross(unit_normal, tile_x_unit); if (dot(tile_y_unit, current_curve[1] - current_curve[0]) < 0) { tile_y_unit *= -1; } } // Project the curve onto the tile. for(int i = 0; i < 3; i++) { uv_curve[i] = convert_to_uv(tile_x_unit, tile_y_unit, current_curve[i]); } // Compute the curve's bounding box. vec4 uv_bounding_box = bboxBezier(uv_curve[0], uv_curve[1], uv_curve[2]); vec3 tile_translation = unit_normal * dot(current_curve[0], unit_normal); vec3 bounding_box_min = convert_from_uv(tile_translation, tile_x_unit, tile_y_unit, uv_bounding_box.xy); vec3 bounding_box_max = convert_from_uv(tile_translation, tile_x_unit, tile_y_unit, uv_bounding_box.zw); vec3 bounding_box_vec = bounding_box_max - bounding_box_min; vec3 tile_origin = bounding_box_min; vec3 tile_x_vec = tile_x_unit * dot(tile_x_unit, bounding_box_vec); vec3 tile_y_vec = tile_y_unit * dot(tile_y_unit, bounding_box_vec); // Expand the tile according to the line's thickness. v_thickness = thickness_multiplier * in_width; tile_origin = current_curve[0] - v_thickness * (tile_x_unit + tile_y_unit); tile_x_vec += 2 * v_thickness * tile_x_unit; tile_y_vec += 2 * v_thickness * tile_y_unit; vec3 tile_point = tile_origin + \ tile_coordinate[0] * tile_x_vec + \ tile_coordinate[1] * tile_y_vec; gl_Position = u_projection_matrix * u_model_view_matrix * vec4(tile_point, 1.0); uv_point = convert_to_uv(tile_x_unit, tile_y_unit, tile_point); } ================================================ FILE: manim/renderer/shaders/vertex_colors/frag.glsl ================================================ #version 330 in vec4 v_color; out vec4 frag_color; void main() { frag_color = v_color; } ================================================ FILE: manim/renderer/shaders/vertex_colors/vert.glsl ================================================ #version 330 uniform mat4 u_model_matrix; uniform mat4 u_view_matrix; uniform mat4 u_projection_matrix; in vec4 in_vert; in vec4 in_color; out vec4 v_color; void main() { v_color = in_color; gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * in_vert; } ================================================ FILE: manim/renderer/vectorized_mobject_rendering.py ================================================ from __future__ import annotations from collections import defaultdict from collections.abc import Iterable, Sequence from typing import TYPE_CHECKING import numpy as np if TYPE_CHECKING: from manim.renderer.opengl_renderer import ( OpenGLRenderer, OpenGLVMobject, ) from manim.typing import MatrixMN from ..utils import opengl from ..utils.space_ops import cross2d, earclip_triangulation from .shader import Shader __all__ = [ "render_opengl_vectorized_mobject_fill", "render_opengl_vectorized_mobject_stroke", ] def build_matrix_lists( mob: OpenGLVMobject, ) -> defaultdict[tuple[float, ...], list[OpenGLVMobject]]: root_hierarchical_matrix = mob.hierarchical_model_matrix() matrix_to_mobject_list = defaultdict(list) if mob.has_points(): matrix_to_mobject_list[tuple(root_hierarchical_matrix.ravel())].append(mob) mobject_to_hierarchical_matrix = {mob: root_hierarchical_matrix} dfs = [mob] while dfs: parent = dfs.pop() for child in parent.submobjects: child_hierarchical_matrix = ( mobject_to_hierarchical_matrix[parent] @ child.model_matrix ) mobject_to_hierarchical_matrix[child] = child_hierarchical_matrix if child.has_points(): matrix_to_mobject_list[tuple(child_hierarchical_matrix.ravel())].append( child, ) dfs.append(child) return matrix_to_mobject_list def render_opengl_vectorized_mobject_fill( renderer: OpenGLRenderer, mobject: OpenGLVMobject ) -> None: matrix_to_mobject_list = build_matrix_lists(mobject) for matrix_tuple, mobject_list in matrix_to_mobject_list.items(): model_matrix = np.array(matrix_tuple).reshape((4, 4)) render_mobject_fills_with_matrix(renderer, model_matrix, mobject_list) def render_mobject_fills_with_matrix( renderer: OpenGLRenderer, model_matrix: MatrixMN, mobjects: Iterable[OpenGLVMobject], ) -> None: # Precompute the total number of vertices for which to reserve space. # Note that triangulate_mobject() will cache its results. total_size = 0 for submob in mobjects: total_size += triangulate_mobject(submob).shape[0] attributes = np.empty( total_size, dtype=[ ("in_vert", np.float32, (3,)), ("in_color", np.float32, (4,)), ("texture_coords", np.float32, (2,)), ("texture_mode", np.int32), ], ) write_offset = 0 for submob in mobjects: if not submob.has_points(): continue mobject_triangulation = triangulate_mobject(submob) end_offset = write_offset + mobject_triangulation.shape[0] attributes[write_offset:end_offset] = mobject_triangulation attributes["in_color"][write_offset:end_offset] = np.repeat( submob.fill_rgba, mobject_triangulation.shape[0], axis=0, ) write_offset = end_offset fill_shader = Shader(renderer.context, name="vectorized_mobject_fill") fill_shader.set_uniform( "u_model_view_matrix", opengl.matrix_to_shader_input( renderer.camera.unformatted_view_matrix @ model_matrix, ), ) fill_shader.set_uniform( "u_projection_matrix", renderer.camera.projection_matrix, ) vbo = renderer.context.buffer(attributes.tobytes()) vao = renderer.context.simple_vertex_array( fill_shader.shader_program, vbo, *attributes.dtype.names, ) vao.render() vao.release() vbo.release() def triangulate_mobject(mob: OpenGLVMobject) -> np.ndarray: if not mob.needs_new_triangulation: return mob.triangulation # Figure out how to triangulate the interior to know # how to send the points as to the vertex shader. # First triangles come directly from the points # normal_vector = mob.get_unit_normal() points = mob.points b0s = points[0::3] b1s = points[1::3] b2s = points[2::3] v01s = b1s - b0s v12s = b2s - b1s crosses = cross2d(v01s, v12s) convexities = np.sign(crosses) if mob.orientation == 1: concave_parts = convexities > 0 convex_parts = convexities <= 0 else: concave_parts = convexities < 0 convex_parts = convexities >= 0 # These are the vertices to which we'll apply a polygon triangulation atol = mob.tolerance_for_point_equality end_of_loop = np.zeros(len(b0s), dtype=bool) end_of_loop[:-1] = (np.abs(b2s[:-1] - b0s[1:]) > atol).any(1) end_of_loop[-1] = True indices = np.arange(len(points), dtype=int) inner_vert_indices = np.hstack( [ indices[0::3], indices[1::3][concave_parts], indices[2::3][end_of_loop], ], ) inner_vert_indices.sort() rings = np.arange(1, len(inner_vert_indices) + 1)[inner_vert_indices % 3 == 2] # Triangulate inner_verts = points[inner_vert_indices] inner_tri_indices = inner_vert_indices[earclip_triangulation(inner_verts, rings)] bezier_triangle_indices = np.reshape(indices, (-1, 3)) concave_triangle_indices = np.reshape(bezier_triangle_indices[concave_parts], (-1)) convex_triangle_indices = np.reshape(bezier_triangle_indices[convex_parts], (-1)) points = points[ np.hstack( [ concave_triangle_indices, convex_triangle_indices, inner_tri_indices, ], ) ] texture_coords = np.tile( [ [0.0, 0.0], [0.5, 0.0], [1.0, 1.0], ], (points.shape[0] // 3, 1), ) texture_mode = np.hstack( ( np.ones(concave_triangle_indices.shape[0]), -1 * np.ones(convex_triangle_indices.shape[0]), np.zeros(inner_tri_indices.shape[0]), ), ) attributes = np.zeros( points.shape[0], dtype=[ ("in_vert", np.float32, (3,)), ("in_color", np.float32, (4,)), ("texture_coords", np.float32, (2,)), ("texture_mode", np.int32), ], ) attributes["in_vert"] = points attributes["texture_coords"] = texture_coords attributes["texture_mode"] = texture_mode mob.triangulation = attributes mob.needs_new_triangulation = False return attributes def render_opengl_vectorized_mobject_stroke( renderer: OpenGLRenderer, mobject: OpenGLVMobject ) -> None: matrix_to_mobject_list = build_matrix_lists(mobject) for matrix_tuple, mobject_list in matrix_to_mobject_list.items(): model_matrix = np.array(matrix_tuple).reshape((4, 4)) render_mobject_strokes_with_matrix(renderer, model_matrix, mobject_list) def render_mobject_strokes_with_matrix( renderer: OpenGLRenderer, model_matrix: MatrixMN, mobjects: Sequence[OpenGLVMobject], ) -> None: # Precompute the total number of vertices for which to reserve space. total_size = 0 for submob in mobjects: total_size += submob.points.shape[0] points = np.empty((total_size, 3)) colors = np.empty((total_size, 4)) widths = np.empty(total_size) write_offset = 0 for submob in mobjects: if not submob.has_points(): continue end_offset = write_offset + submob.points.shape[0] points[write_offset:end_offset] = submob.points if submob.stroke_rgba.shape[0] == points[write_offset:end_offset].shape[0]: colors[write_offset:end_offset] = submob.stroke_rgba else: colors[write_offset:end_offset] = np.repeat( submob.stroke_rgba, submob.points.shape[0], axis=0, ) widths[write_offset:end_offset] = np.repeat( submob.stroke_width, submob.points.shape[0], ) write_offset = end_offset stroke_data = np.zeros( len(points), dtype=[ # ("previous_curve", np.float32, (3, 3)), ("current_curve", np.float32, (3, 3)), # ("next_curve", np.float32, (3, 3)), ("tile_coordinate", np.float32, (2,)), ("in_color", np.float32, (4,)), ("in_width", np.float32), ], ) stroke_data["in_color"] = colors stroke_data["in_width"] = widths curves = np.reshape(points, (-1, 3, 3)) # stroke_data["previous_curve"] = np.repeat(np.roll(curves, 1, axis=0), 3, axis=0) stroke_data["current_curve"] = np.repeat(curves, 3, axis=0) # stroke_data["next_curve"] = np.repeat(np.roll(curves, -1, axis=0), 3, axis=0) # Repeat each vertex in order to make a tile. stroke_data = np.tile(stroke_data, 2) stroke_data["tile_coordinate"] = np.vstack( ( np.tile( [ [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], ], (len(points) // 3, 1), ), np.tile( [ [0.0, 0.0], [1.0, 0.0], [1.0, 1.0], ], (len(points) // 3, 1), ), ), ) shader = Shader(renderer.context, "vectorized_mobject_stroke") shader.set_uniform( "u_model_view_matrix", opengl.matrix_to_shader_input( renderer.camera.unformatted_view_matrix @ model_matrix, ), ) shader.set_uniform("u_projection_matrix", renderer.camera.projection_matrix) shader.set_uniform("manim_unit_normal", tuple(-mobjects[0].unit_normal[0])) vbo = renderer.context.buffer(stroke_data.tobytes()) vao = renderer.context.simple_vertex_array( shader.shader_program, vbo, *stroke_data.dtype.names ) renderer.frame_buffer_object.use() vao.render() vao.release() vbo.release() ================================================ FILE: manim/scene/__init__.py ================================================ ================================================ FILE: manim/scene/moving_camera_scene.py ================================================ """A scene whose camera can be moved around. .. SEEALSO:: :mod:`.moving_camera` Examples -------- .. manim:: ChangingCameraWidthAndRestore class ChangingCameraWidthAndRestore(MovingCameraScene): def construct(self): text = Text("Hello World").set_color(BLUE) self.add(text) self.camera.frame.save_state() self.play(self.camera.frame.animate.set(width=text.width * 1.2)) self.wait(0.3) self.play(Restore(self.camera.frame)) .. manim:: MovingCameraCenter class MovingCameraCenter(MovingCameraScene): def construct(self): s = Square(color=RED, fill_opacity=0.5).move_to(2 * LEFT) t = Triangle(color=GREEN, fill_opacity=0.5).move_to(2 * RIGHT) self.wait(0.3) self.add(s, t) self.play(self.camera.frame.animate.move_to(s)) self.wait(0.3) self.play(self.camera.frame.animate.move_to(t)) .. manim:: MovingAndZoomingCamera class MovingAndZoomingCamera(MovingCameraScene): def construct(self): s = Square(color=BLUE, fill_opacity=0.5).move_to(2 * LEFT) t = Triangle(color=YELLOW, fill_opacity=0.5).move_to(2 * RIGHT) self.add(s, t) self.play(self.camera.frame.animate.move_to(s).set(width=s.width*2)) self.wait(0.3) self.play(self.camera.frame.animate.move_to(t).set(width=t.width*2)) self.play(self.camera.frame.animate.move_to(ORIGIN).set(width=14)) .. manim:: MovingCameraOnGraph class MovingCameraOnGraph(MovingCameraScene): def construct(self): self.camera.frame.save_state() ax = Axes(x_range=[-1, 10], y_range=[-1, 10]) graph = ax.plot(lambda x: np.sin(x), color=WHITE, x_range=[0, 3 * PI]) dot_1 = Dot(ax.i2gp(graph.t_min, graph)) dot_2 = Dot(ax.i2gp(graph.t_max, graph)) self.add(ax, graph, dot_1, dot_2) self.play(self.camera.frame.animate.scale(0.5).move_to(dot_1)) self.play(self.camera.frame.animate.move_to(dot_2)) self.play(Restore(self.camera.frame)) self.wait() .. manim:: SlidingMultipleScenes class SlidingMultipleScenes(MovingCameraScene): def construct(self): def create_scene(number): frame = Rectangle(width=16,height=9) circ = Circle().shift(LEFT) text = Tex(f"This is Scene {str(number)}").next_to(circ, RIGHT) frame.add(circ,text) return frame group = VGroup(*(create_scene(i) for i in range(4))).arrange_in_grid(buff=4) self.add(group) self.camera.auto_zoom(group[0], animate=False) for scene in group: self.play(self.camera.auto_zoom(scene)) self.wait() self.play(self.camera.auto_zoom(group, margin=2)) """ from __future__ import annotations __all__ = ["MovingCameraScene"] from typing import Any from manim.animation.animation import Animation from manim.mobject.mobject import Mobject from ..camera.camera import Camera from ..camera.moving_camera import MovingCamera from ..scene.scene import Scene from ..utils.family import extract_mobject_family_members from ..utils.iterables import list_update class MovingCameraScene(Scene): """ This is a Scene, with special configurations and properties that make it suitable for cases where the camera must be moved around. Note: Examples are included in the moving_camera_scene module documentation, see below in the 'see also' section. .. SEEALSO:: :mod:`.moving_camera_scene` :class:`.MovingCamera` """ def __init__( self, camera_class: type[Camera] = MovingCamera, **kwargs: Any ) -> None: super().__init__(camera_class=camera_class, **kwargs) def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: """ This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed. Parameters ---------- *animations The Animations whose mobjects will be checked. """ moving_mobjects = super().get_moving_mobjects(*animations) all_moving_mobjects = extract_mobject_family_members(moving_mobjects) movement_indicators = self.renderer.camera.get_mobjects_indicating_movement() # type: ignore[union-attr] for movement_indicator in movement_indicators: if movement_indicator in all_moving_mobjects: # When one of these is moving, the camera should # consider all mobjects to be moving return list_update(self.mobjects, moving_mobjects) return moving_mobjects ================================================ FILE: manim/scene/scene.py ================================================ """Basic canvas for animations.""" from __future__ import annotations from manim.utils.parameter_parsing import flatten_iterable_parameters from ..mobject.mobject import _AnimationBuilder __all__ = ["Scene"] import copy import datetime import inspect import platform import random import threading import time from dataclasses import dataclass from pathlib import Path from queue import Queue import srt from manim.scene.section import DefaultSectionType try: import dearpygui.dearpygui as dpg dearpygui_imported = True dpg.create_context() window = dpg.generate_uuid() except ImportError: dearpygui_imported = False from collections.abc import Callable, Iterable, Sequence from typing import TYPE_CHECKING, Any import numpy as np from tqdm import tqdm from watchdog.events import DirModifiedEvent, FileModifiedEvent, FileSystemEventHandler from watchdog.observers import Observer from manim import __version__ from manim.data_structures import MethodWithArgs from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_mobject import OpenGLPoint from .. import config, logger from ..animation.animation import Animation, Wait, prepare_animation from ..camera.camera import Camera from ..constants import * from ..renderer.cairo_renderer import CairoRenderer from ..renderer.opengl_renderer import OpenGLCamera, OpenGLMobject, OpenGLRenderer from ..renderer.shader import Object3D from ..utils import opengl, space_ops from ..utils.exceptions import EndSceneEarlyException, RerunSceneException from ..utils.family import extract_mobject_family_members from ..utils.family_ops import restructure_list_to_exclude_certain_family_members from ..utils.file_ops import open_media_file from ..utils.iterables import list_difference_update, list_update from ..utils.module_ops import scene_classes_from_file if TYPE_CHECKING: from types import FrameType from typing import Self, TypeAlias from manim.typing import Point3D SceneInteractAction: TypeAlias = ( MethodWithArgs | "SceneInteractContinue" | "SceneInteractRerun" ) """The SceneInteractAction type alias is used for elements in the queue used by :meth:`.Scene.interact()`. The elements can be one of the following three: - a :class:`~.MethodWithArgs` object, which represents a :class:`Scene` method to be called along with its args and kwargs, - a :class:`~.SceneInteractContinue` object, indicating that the scene interaction is over and the scene will continue rendering after that, or - a :class:`~.SceneInteractRerun` object, indicating that the scene should render again. """ @dataclass class SceneInteractContinue: """Object which, when encountered in :meth:`.Scene.interact`, triggers the end of the scene interaction, continuing with the rest of the animations, if any. This object can be queued in :attr:`.Scene.queue` for later use in :meth:`.Scene.interact`. Attributes ---------- sender : str The name of the entity which issued the end of the scene interaction, such as ``"gui"`` or ``"keyboard"``. """ __slots__ = ["sender"] sender: str class SceneInteractRerun: """Object which, when encountered in :meth:`.Scene.interact`, triggers the rerun of the scene. This object can be queued in :attr:`.Scene.queue` for later use in :meth:`.Scene.interact`. Attributes ---------- sender : str The name of the entity which issued the rerun of the scene, such as ``"gui"``, ``"keyboard"``, ``"play"`` or ``"file"``. kwargs : dict[str, Any] Additional keyword arguments when rerunning the scene. Currently, only ``"from_animation_number"`` is being used, which determines the animation from which to start rerunning the scene. """ __slots__ = ["sender", "kwargs"] def __init__(self, sender: str, **kwargs: Any) -> None: self.sender = sender self.kwargs = kwargs class RerunSceneHandler(FileSystemEventHandler): """A class to handle rerunning a Scene after the input file is modified.""" def __init__(self, queue: Queue[SceneInteractAction]) -> None: super().__init__() self.queue = queue def on_modified(self, event: DirModifiedEvent | FileModifiedEvent) -> None: self.queue.put(SceneInteractRerun("file")) class Scene: """A Scene is the canvas of your animation. The primary role of :class:`Scene` is to provide the user with tools to manage mobjects and animations. Generally speaking, a manim script consists of a class that derives from :class:`Scene` whose :meth:`Scene.construct` method is overridden by the user's code. Mobjects are displayed on screen by calling :meth:`Scene.add` and removed from screen by calling :meth:`Scene.remove`. All mobjects currently on screen are kept in :attr:`Scene.mobjects`. Animations are played by calling :meth:`Scene.play`. A :class:`Scene` is rendered internally by calling :meth:`Scene.render`. This in turn calls :meth:`Scene.setup`, :meth:`Scene.construct`, and :meth:`Scene.tear_down`, in that order. It is not recommended to override the ``__init__`` method in user Scenes. For code that should be ran before a Scene is rendered, use :meth:`Scene.setup` instead. Examples -------- Override the :meth:`Scene.construct` method with your code. .. code-block:: python class MyScene(Scene): def construct(self): self.play(Write(Text("Hello World!"))) """ def __init__( self, renderer: CairoRenderer | OpenGLRenderer | None = None, camera_class: type[Camera] = Camera, always_update_mobjects: bool = False, random_seed: int | None = None, skip_animations: bool = False, ) -> None: self.camera_class = camera_class self.always_update_mobjects = always_update_mobjects self.random_seed = random_seed if random_seed is not None else config.seed self.skip_animations = skip_animations self.animations: list[Animation] | None = None self.stop_condition: Callable[[], bool] | None = None self.moving_mobjects: list[Mobject] = [] self.static_mobjects: list[Mobject] = [] self.time_progression: tqdm[float] | None = None self.duration: float = 0.0 self.last_t = 0.0 self.queue: Queue[SceneInteractAction] = Queue() self.skip_animation_preview = False self.meshes: list[Object3D] = [] self.camera_target = ORIGIN self.widgets: list[dict[str, Any]] = [] self.dearpygui_imported = dearpygui_imported self.updaters: list[Callable[[float], None]] = [] self.key_to_function_map: dict[str, Callable[[], None]] = {} self.mouse_press_callbacks: list[Callable[[], None]] = [] self.interactive_mode = False if config.renderer == RendererType.OPENGL: # Items associated with interaction self.mouse_point = OpenGLPoint() self.mouse_drag_point = OpenGLPoint() if renderer is None: renderer = OpenGLRenderer() if renderer is None: self.renderer: CairoRenderer | OpenGLRenderer = CairoRenderer( # TODO: Is it a suitable approach to make an instance of # the self.camera_class here? camera_class=self.camera_class, skip_animations=self.skip_animations, ) else: self.renderer = renderer self.renderer.init_scene(self) self.mobjects: list[Mobject] = [] # TODO, remove need for foreground mobjects self.foreground_mobjects: list[Mobject] = [] random.seed(self.random_seed) np.random.seed(self.random_seed) # noqa: NPY002 (only way to set seed globally) @property def camera(self) -> Camera | OpenGLCamera: return self.renderer.camera @property def time(self) -> float: """The time since the start of the scene.""" return self.renderer.time def __deepcopy__(self, clone_from_id: dict[int, Any]) -> Scene: cls = self.__class__ result = cls.__new__(cls) clone_from_id[id(self)] = result for k, v in self.__dict__.items(): if k in ["renderer", "time_progression"]: continue if k == "camera_class": setattr(result, k, v) setattr(result, k, copy.deepcopy(v, clone_from_id)) return result def render(self, preview: bool = False) -> bool: """ Renders this Scene. Parameters --------- preview If true, opens scene in a file viewer. """ self.setup() try: self.construct() except EndSceneEarlyException: pass except RerunSceneException: self.remove(*self.mobjects) # TODO: The CairoRenderer does not have the method clear_screen() self.renderer.clear_screen() # type: ignore[union-attr] self.renderer.num_plays = 0 return True self.tear_down() # We have to reset these settings in case of multiple renders. self.renderer.scene_finished(self) # Show info only if animations are rendered or to get image if ( self.renderer.num_plays or config["format"] == "png" or config["save_last_frame"] ): logger.info( f"Rendered {str(self)}\nPlayed {self.renderer.num_plays} animations", ) # If preview open up the render after rendering. if preview: config["preview"] = True if config["preview"] or config["show_in_file_browser"]: open_media_file(self.renderer.file_writer) return False def setup(self) -> None: """ This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup involved before the construct method is called. """ pass def tear_down(self) -> None: """ This is meant to be implemented by any scenes which are commonly subclassed, and have some common method to be invoked before the scene ends. """ pass def construct(self) -> None: """Add content to the Scene. From within :meth:`Scene.construct`, display mobjects on screen by calling :meth:`Scene.add` and remove them from screen by calling :meth:`Scene.remove`. All mobjects currently on screen are kept in :attr:`Scene.mobjects`. Play animations by calling :meth:`Scene.play`. Notes ----- Initialization code should go in :meth:`Scene.setup`. Termination code should go in :meth:`Scene.tear_down`. Examples -------- A typical manim script includes a class derived from :class:`Scene` with an overridden :meth:`Scene.construct` method: .. code-block:: python class MyScene(Scene): def construct(self): self.play(Write(Text("Hello World!"))) See Also -------- :meth:`Scene.setup` :meth:`Scene.render` :meth:`Scene.tear_down` """ pass # To be implemented in subclasses def next_section( self, name: str = "unnamed", section_type: str = DefaultSectionType.NORMAL, skip_animations: bool = False, ) -> None: """Create separation here; the last section gets finished and a new one gets created. ``skip_animations`` skips the rendering of all animations in this section. Refer to :doc:`the documentation` on how to use sections. """ self.renderer.file_writer.next_section(name, section_type, skip_animations) def __str__(self) -> str: return self.__class__.__name__ def get_attrs(self, *keys: str) -> list[Any]: """ Gets attributes of a scene given the attribute's identifier/name. Parameters ---------- *keys Name(s) of the argument(s) to return the attribute of. Returns ------- list List of attributes of the passed identifiers. """ return [getattr(self, key) for key in keys] def update_mobjects(self, dt: float) -> None: """ Begins updating all mobjects in the Scene. Parameters ---------- dt Change in time between updates. Defaults (mostly) to 1/frames_per_second """ for mobj in self.mobjects: mobj.update(dt) def update_meshes(self, dt: float) -> None: for obj in self.meshes: for mesh in obj.get_family(): mesh.update(dt) def update_self(self, dt: float) -> None: """Run all scene updater functions. Among all types of update functions (mobject updaters, mesh updaters, scene updaters), scene update functions are called last. Parameters ---------- dt Scene time since last update. See Also -------- :meth:`.Scene.add_updater` :meth:`.Scene.remove_updater` """ for func in self.updaters: func(dt) def should_update_mobjects(self) -> bool: """ Returns True if the mobjects of this scene should be updated. In particular, this checks whether - the :attr:`always_update_mobjects` attribute of :class:`.Scene` is set to ``True``, - the :class:`.Scene` itself has time-based updaters attached, - any mobject in this :class:`.Scene` has time-based updaters attached. This is only called when a single Wait animation is played. """ assert self.animations is not None wait_animation = self.animations[0] assert isinstance(wait_animation, Wait) if wait_animation.is_static_wait is None: should_update = ( self.always_update_mobjects or self.updaters or wait_animation.stop_condition is not None or any( mob.has_time_based_updater() for mob in self.get_mobject_family_members() ) ) wait_animation.is_static_wait = not should_update return not wait_animation.is_static_wait def get_top_level_mobjects(self) -> list[Mobject]: """ Returns all mobjects which are not submobjects. Returns ------- list List of top level mobjects. """ # Return only those which are not in the family # of another mobject from the scene families = [m.get_family() for m in self.mobjects] def is_top_level(mobject: Mobject) -> bool: num_families = sum((mobject in family) for family in families) return num_families == 1 return list(filter(is_top_level, self.mobjects)) def get_mobject_family_members(self) -> list[Mobject]: """ Returns list of family-members of all mobjects in scene. If a Circle() and a VGroup(Rectangle(),Triangle()) were added, it returns not only the Circle(), Rectangle() and Triangle(), but also the VGroup() object. Returns ------- list List of mobject family members. """ if config.renderer == RendererType.OPENGL: family_members = [] for mob in self.mobjects: family_members.extend(mob.get_family()) return family_members else: assert config.renderer == RendererType.CAIRO return extract_mobject_family_members( self.mobjects, use_z_index=self.renderer.camera.use_z_index, ) def add(self, *mobjects: Mobject | OpenGLMobject) -> Self: """ Mobjects will be displayed, from background to foreground in the order with which they are added. Parameters --------- *mobjects Mobjects to add. Returns ------- Scene The same scene after adding the Mobjects in. """ if config.renderer == RendererType.OPENGL: new_mobjects = [] new_meshes: list[Object3D] = [] for mobject_or_mesh in mobjects: if isinstance(mobject_or_mesh, Object3D): new_meshes.append(mobject_or_mesh) else: new_mobjects.append(mobject_or_mesh) self.remove(*new_mobjects) # type: ignore[arg-type] self.mobjects += new_mobjects # type: ignore[arg-type] self.remove(*new_meshes) # type: ignore[arg-type] self.meshes += new_meshes else: assert config.renderer == RendererType.CAIRO new_and_foreground_mobjects: list[Mobject] = [ *mobjects, # type: ignore[list-item] *self.foreground_mobjects, ] self.restructure_mobjects(to_remove=new_and_foreground_mobjects) self.mobjects += new_and_foreground_mobjects if self.moving_mobjects: self.restructure_mobjects( to_remove=new_and_foreground_mobjects, mobject_list_name="moving_mobjects", ) self.moving_mobjects += new_and_foreground_mobjects return self def add_mobjects_from_animations(self, animations: list[Animation]) -> None: curr_mobjects = self.get_mobject_family_members() for animation in animations: if animation.is_introducer(): continue # Anything animated that's not already in the # scene gets added to the scene mob = animation.mobject if mob is not None and mob not in curr_mobjects: self.add(mob) curr_mobjects += mob.get_family() # type: ignore[arg-type] def remove(self, *mobjects: Mobject) -> Self: """ Removes mobjects in the passed list of mobjects from the scene and the foreground, by removing them from "mobjects" and "foreground_mobjects" Parameters ---------- *mobjects The mobjects to remove. """ if config.renderer == RendererType.OPENGL: mobjects_to_remove = [] meshes_to_remove: set[Object3D] = set() mobject_or_mesh: Mobject for mobject_or_mesh in mobjects: if isinstance(mobject_or_mesh, Object3D): meshes_to_remove.add(mobject_or_mesh) else: mobjects_to_remove.append(mobject_or_mesh) self.mobjects = restructure_list_to_exclude_certain_family_members( self.mobjects, mobjects_to_remove, ) def lambda_function(mesh: Object3D) -> bool: return mesh not in set(meshes_to_remove) self.meshes = list( filter(lambda_function, self.meshes), ) return self else: assert config.renderer == RendererType.CAIRO for list_name in "mobjects", "foreground_mobjects": self.restructure_mobjects(mobjects, list_name, False) return self def replace(self, old_mobject: Mobject, new_mobject: Mobject) -> None: """Replace one mobject in the scene with another, preserving draw order. If ``old_mobject`` is a submobject of some other Mobject (e.g. a :class:`.Group`), the new_mobject will replace it inside the group, without otherwise changing the parent mobject. Parameters ---------- old_mobject The mobject to be replaced. Must be present in the scene. new_mobject A mobject which must not already be in the scene. """ if old_mobject is None or new_mobject is None: raise ValueError("Specified mobjects cannot be None") def replace_in_list( mobj_list: list[Mobject], old_m: Mobject, new_m: Mobject ) -> bool: # Avoid duplicate references to the same object in self.mobjects if new_m in mobj_list: if old_m is new_m: # In this case, one could say that the old Mobject was already found. # No replacement is needed, since old_m is new_m, so no action is required. # This might be unexpected, so raise a warning. logger.warning( f"Attempted to replace {type(old_m).__name__} " "with itself in Scene.mobjects." ) return True mobj_list.remove(new_m) # We use breadth-first search because some Mobjects get very deep and # we expect top-level elements to be the most common targets for replace. for i in range(0, len(mobj_list)): # Is this the old mobject? if mobj_list[i] == old_m: # If so, write the new object to the same spot and stop looking. mobj_list[i] = new_m return True # Now check all the children of all these mobs. for mob in mobj_list: # noqa: SIM110 if replace_in_list(mob.submobjects, old_m, new_m): # If we found it in a submobject, stop looking. return True # If we did not find the mobject in the mobject list or any submobjects, # (or the list was empty), indicate we did not make the replacement. return False # Make use of short-circuiting conditionals to check mobjects and then # foreground_mobjects replaced = replace_in_list( self.mobjects, old_mobject, new_mobject ) or replace_in_list(self.foreground_mobjects, old_mobject, new_mobject) if not replaced: raise ValueError(f"Could not find {old_mobject} in scene") def add_updater(self, func: Callable[[float], None]) -> None: """Add an update function to the scene. The scene updater functions are run every frame, and they are the last type of updaters to run. .. WARNING:: When using the Cairo renderer, scene updaters that modify mobjects are not detected in the same way that mobject updaters are. To be more concrete, a mobject only modified via a scene updater will not necessarily be added to the list of *moving mobjects* and thus might not be updated every frame. TL;DR: Use mobject updaters to update mobjects. Parameters ---------- func The updater function. It takes a float, which is the time difference since the last update (usually equal to the frame rate). See also -------- :meth:`.Scene.remove_updater` :meth:`.Scene.update_self` """ self.updaters.append(func) def remove_updater(self, func: Callable[[float], None]) -> None: """Remove an update function from the scene. Parameters ---------- func The updater function to be removed. See also -------- :meth:`.Scene.add_updater` :meth:`.Scene.update_self` """ self.updaters = [f for f in self.updaters if f is not func] def restructure_mobjects( self, to_remove: Sequence[Mobject], mobject_list_name: str = "mobjects", extract_families: bool = True, ) -> Scene: """ tl:wr If your scene has a Group(), and you removed a mobject from the Group, this dissolves the group and puts the rest of the mobjects directly in self.mobjects or self.foreground_mobjects. In cases where the scene contains a group, e.g. Group(m1, m2, m3), but one of its submobjects is removed, e.g. scene.remove(m1), the list of mobjects will be edited to contain other submobjects, but not m1, e.g. it will now insert m2 and m3 to where the group once was. Parameters ---------- to_remove The Mobject to remove. mobject_list_name The list of mobjects ("mobjects", "foreground_mobjects" etc) to remove from. extract_families Whether the mobject's families should be recursively extracted. Returns ------- Scene The Scene mobject with restructured Mobjects. """ if extract_families: to_remove = extract_mobject_family_members( to_remove, use_z_index=self.renderer.camera.use_z_index, ) _list = getattr(self, mobject_list_name) new_list = self.get_restructured_mobject_list(_list, to_remove) setattr(self, mobject_list_name, new_list) return self def get_restructured_mobject_list( self, mobjects: Iterable[Mobject], to_remove: Iterable[Mobject] ) -> list[Mobject]: """ Given a list of mobjects and a list of mobjects to be removed, this filters out the removable mobjects from the list of mobjects. Parameters ---------- mobjects The Mobjects to check. to_remove The list of mobjects to remove. Returns ------- list The list of mobjects with the mobjects to remove removed. """ new_mobjects: list[Mobject] = [] def add_safe_mobjects_from_list( list_to_examine: Iterable[Mobject], set_to_remove: set[Mobject] ) -> None: for mob in list_to_examine: if mob in set_to_remove: continue intersect = set_to_remove.intersection(mob.get_family()) if intersect: add_safe_mobjects_from_list(mob.submobjects, intersect) else: new_mobjects.append(mob) add_safe_mobjects_from_list(mobjects, set(to_remove)) return new_mobjects # TODO, remove this, and calls to this def add_foreground_mobjects(self, *mobjects: Mobject) -> Scene: """ Adds mobjects to the foreground, and internally to the list foreground_mobjects, and mobjects. Parameters ---------- *mobjects The Mobjects to add to the foreground. Returns ------ Scene The Scene, with the foreground mobjects added. """ self.foreground_mobjects = list_update(self.foreground_mobjects, mobjects) self.add(*mobjects) return self def add_foreground_mobject(self, mobject: Mobject) -> Scene: """ Adds a single mobject to the foreground, and internally to the list foreground_mobjects, and mobjects. Parameters ---------- mobject The Mobject to add to the foreground. Returns ------ Scene The Scene, with the foreground mobject added. """ return self.add_foreground_mobjects(mobject) def remove_foreground_mobjects(self, *to_remove: Mobject) -> Scene: """ Removes mobjects from the foreground, and internally from the list foreground_mobjects. Parameters ---------- *to_remove The mobject(s) to remove from the foreground. Returns ------ Scene The Scene, with the foreground mobjects removed. """ self.restructure_mobjects(to_remove, "foreground_mobjects") return self def remove_foreground_mobject(self, mobject: Mobject) -> Scene: """ Removes a single mobject from the foreground, and internally from the list foreground_mobjects. Parameters ---------- mobject The mobject to remove from the foreground. Returns ------ Scene The Scene, with the foreground mobject removed. """ return self.remove_foreground_mobjects(mobject) def bring_to_front(self, *mobjects: Mobject) -> Scene: """ Adds the passed mobjects to the scene again, pushing them to he front of the scene. Parameters ---------- *mobjects The mobject(s) to bring to the front of the scene. Returns ------ Scene The Scene, with the mobjects brought to the front of the scene. """ self.add(*mobjects) return self def bring_to_back(self, *mobjects: Mobject) -> Scene: """ Removes the mobject from the scene and adds them to the back of the scene. Parameters ---------- *mobjects The mobject(s) to push to the back of the scene. Returns ------ Scene The Scene, with the mobjects pushed to the back of the scene. """ self.remove(*mobjects) self.mobjects = list(mobjects) + self.mobjects return self def clear(self) -> Self: """ Removes all mobjects present in self.mobjects and self.foreground_mobjects from the scene. Returns ------ Scene The Scene, with all of its mobjects in self.mobjects and self.foreground_mobjects removed. """ self.mobjects = [] self.foreground_mobjects = [] return self def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: """ Gets all moving mobjects in the passed animation(s). Parameters ---------- *animations The animations to check for moving mobjects. Returns ------ list The list of mobjects that could be moving in the Animation(s) """ # Go through mobjects from start to end, and # as soon as there's one that needs updating of # some kind per frame, return the list from that # point forward. # Imported inside the method to avoid cyclic import. from ..animation.composition import AnimationGroup def _collect_animation_mobjects( nested_animations: Iterable[Animation], ) -> list[Mobject | OpenGLMobject]: animation_mobjects: list[Mobject | OpenGLMobject] = [] for anim in nested_animations: if isinstance(anim, AnimationGroup): animation_mobjects.extend( _collect_animation_mobjects(anim.animations), ) else: animation_mobjects.extend(anim.mobject.get_family()) return animation_mobjects animation_mobjects = _collect_animation_mobjects(animations) mobjects = self.get_mobject_family_members() for i, mob in enumerate(mobjects): update_possibilities = [ mob in animation_mobjects, len(mob.get_family_updaters()) > 0, mob in self.foreground_mobjects, ] if any(update_possibilities): return mobjects[i:] return [] def get_moving_and_static_mobjects( self, animations: Iterable[Animation] ) -> tuple[list[Mobject], list[Mobject]]: all_mobjects = list_update(self.mobjects, self.foreground_mobjects) all_mobject_families = extract_mobject_family_members( all_mobjects, use_z_index=self.renderer.camera.use_z_index, only_those_with_points=True, ) moving_mobjects = self.get_moving_mobjects(*animations) all_moving_mobject_families = extract_mobject_family_members( moving_mobjects, use_z_index=self.renderer.camera.use_z_index, ) static_mobjects = list_difference_update( all_mobject_families, all_moving_mobject_families, ) return all_moving_mobject_families, static_mobjects def compile_animations( self, *args: Animation | Mobject | _AnimationBuilder, **kwargs: Any, ) -> list[Animation]: """ Creates _MethodAnimations from any _AnimationBuilders and updates animation kwargs with kwargs passed to play(). Parameters ---------- *args Animations to be played. **kwargs Configuration for the call to play(). Returns ------- Tuple[:class:`Animation`] Animations to be played. """ animations = [] arg_anims = flatten_iterable_parameters(args) # Allow passing a generator to self.play instead of comma separated arguments for arg in arg_anims: try: animations.append(prepare_animation(arg)) # type: ignore[arg-type] except TypeError as e: if inspect.ismethod(arg): raise TypeError( "Passing Mobject methods to Scene.play is no longer" " supported. Use Mobject.animate instead.", ) from e else: raise TypeError( f"Unexpected argument {arg} passed to Scene.play().", ) from e for animation in animations: for k, v in kwargs.items(): setattr(animation, k, v) return animations def _get_animation_time_progression( self, animations: list[Animation], duration: float ) -> tqdm[float]: """ You will hardly use this when making your own animations. This method is for Manim's internal use. Uses :func:`~.get_time_progression` to obtain a CommandLine ProgressBar whose ``fill_time`` is dependent on the qualities of the passed Animation, Parameters ---------- animations The list of animations to get the time progression for. duration duration of wait time Returns ------- time_progression The CommandLine Progress Bar. """ if len(animations) == 1 and isinstance(animations[0], Wait): stop_condition = animations[0].stop_condition if stop_condition is not None: time_progression = self.get_time_progression( duration, f"Waiting for {stop_condition.__name__}", n_iterations=-1, # So it doesn't show % progress override_skip_animations=True, ) else: time_progression = self.get_time_progression( duration, f"Waiting {self.renderer.num_plays}", ) else: time_progression = self.get_time_progression( duration, "".join( [ f"Animation {self.renderer.num_plays}: ", str(animations[0]), (", etc." if len(animations) > 1 else ""), ], ), ) return time_progression def get_time_progression( self, run_time: float, description: str, n_iterations: int | None = None, override_skip_animations: bool = False, ) -> tqdm[float]: """ You will hardly use this when making your own animations. This method is for Manim's internal use. Returns a CommandLine ProgressBar whose ``fill_time`` is dependent on the ``run_time`` of an animation, the iterations to perform in that animation and a bool saying whether or not to consider the skipped animations. Parameters ---------- run_time The ``run_time`` of the animation. n_iterations The number of iterations in the animation. override_skip_animations Whether or not to show skipped animations in the progress bar. Returns ------- time_progression The CommandLine Progress Bar. """ if self.renderer.skip_animations and not override_skip_animations: times: Iterable[float] = [run_time] else: step = 1 / config["frame_rate"] times = np.arange(0, run_time, step) time_progression = tqdm( times, desc=description, total=n_iterations, leave=config["progress_bar"] == "leave", ascii=True if platform.system() == "Windows" else None, disable=config["progress_bar"] == "none", ) return time_progression @classmethod def validate_run_time( cls, run_time: float, method: Callable[[Any], Any], parameter_name: str = "run_time", ) -> float: method_name = f"{cls.__name__}.{method.__name__}()" if run_time <= 0: raise ValueError( f"{method_name} has a {parameter_name} of " f"{run_time:g} <= 0 seconds which Manim cannot render. " f"The {parameter_name} must be a positive number." ) # config.frame_rate holds the number of frames per second fps = config.frame_rate seconds_per_frame = 1 / fps if run_time < seconds_per_frame: logger.warning( f"The original {parameter_name} of {method_name}, " f"{run_time:g} seconds, is too short for the current frame " f"rate of {fps:g} FPS. Rendering with the shortest possible " f"{parameter_name} of {seconds_per_frame:g} seconds instead." ) run_time = seconds_per_frame return run_time def get_run_time(self, animations: list[Animation]) -> float: """ Gets the total run time for a list of animations. Parameters ---------- animations A list of the animations whose total ``run_time`` is to be calculated. Returns ------- float The total ``run_time`` of all of the animations in the list. """ run_time = max(animation.run_time for animation in animations) run_time = self.validate_run_time(run_time, self.play, "total run_time") return run_time def play( self, *args: Animation | Mobject | _AnimationBuilder, subcaption: str | None = None, subcaption_duration: float | None = None, subcaption_offset: float = 0, **kwargs: Any, ) -> None: r"""Plays an animation in this scene. Parameters ---------- args Animations to be played. subcaption The content of the external subcaption that should be added during the animation. subcaption_duration The duration for which the specified subcaption is added. If ``None`` (the default), the run time of the animation is taken. subcaption_offset An offset (in seconds) for the start time of the added subcaption. kwargs All other keywords are passed to the renderer. """ # If we are in interactive embedded mode, make sure this is running on the main thread (required for OpenGL) if ( self.interactive_mode and config.renderer == RendererType.OPENGL and threading.current_thread().name != "MainThread" ): # TODO: are these actually being used? kwargs.update( { "subcaption": subcaption, "subcaption_duration": subcaption_duration, "subcaption_offset": subcaption_offset, } ) self.queue.put(SceneInteractRerun("play", **kwargs)) return start_time = self.time self.renderer.play(self, *args, **kwargs) run_time = self.time - start_time if subcaption: if subcaption_duration is None: subcaption_duration = run_time # The start of the subcaption needs to be offset by the # run_time of the animation because it is added after # the animation has already been played (and Scene.time # has already been updated). self.add_subcaption( content=subcaption, duration=subcaption_duration, offset=-run_time + subcaption_offset, ) def wait( self, duration: float = DEFAULT_WAIT_TIME, stop_condition: Callable[[], bool] | None = None, frozen_frame: bool | None = None, ) -> None: """Plays a "no operation" animation. Parameters ---------- duration The run time of the animation. stop_condition A function without positional arguments that is evaluated every time a frame is rendered. The animation only stops when the return value of the function is truthy, or when the time specified in ``duration`` passes. frozen_frame If True, updater functions are not evaluated, and the animation outputs a frozen frame. If False, updater functions are called and frames are rendered as usual. If None (the default), the scene tries to determine whether or not the frame is frozen on its own. See also -------- :class:`.Wait`, :meth:`.should_mobjects_update` """ duration = self.validate_run_time(duration, self.wait, "duration") self.play( Wait( run_time=duration, stop_condition=stop_condition, frozen_frame=frozen_frame, ) ) def pause(self, duration: float = DEFAULT_WAIT_TIME) -> None: """Pauses the scene (i.e., displays a frozen frame). This is an alias for :meth:`.wait` with ``frozen_frame`` set to ``True``. Parameters ---------- duration The duration of the pause. See also -------- :meth:`.wait`, :class:`.Wait` """ duration = self.validate_run_time(duration, self.pause, "duration") self.wait(duration=duration, frozen_frame=True) def wait_until( self, stop_condition: Callable[[], bool], max_time: float = 60 ) -> None: """Wait until a condition is satisfied, up to a given maximum duration. Parameters ---------- stop_condition A function with no arguments that determines whether or not the scene should keep waiting. max_time The maximum wait time in seconds. """ max_time = self.validate_run_time(max_time, self.wait_until, "max_time") self.wait(max_time, stop_condition=stop_condition) def compile_animation_data( self, *animations: Animation | Mobject | _AnimationBuilder, **play_kwargs: Any, ) -> Self | None: """Given a list of animations, compile the corresponding static and moving mobjects, and gather the animation durations. This also begins the animations. Parameters ---------- animations Animation or mobject with mobject method and params play_kwargs Named parameters affecting what was passed in ``animations``, e.g. ``run_time``, ``lag_ratio`` and so on. Returns ------- self, None None if there is nothing to play, or self otherwise. """ # NOTE TODO : returns statement of this method are wrong. It should return nothing, as it makes a little sense to get any information from this method. # The return are kept to keep webgl renderer from breaking. if len(animations) == 0: raise ValueError("Called Scene.play with no animations") self.animations = self.compile_animations(*animations, **play_kwargs) self.add_mobjects_from_animations(self.animations) self.last_t = 0 self.stop_condition = None self.moving_mobjects = [] self.static_mobjects = [] self.duration = self.get_run_time(self.animations) if len(self.animations) == 1 and isinstance(self.animations[0], Wait): if self.should_update_mobjects(): self.update_mobjects(dt=0) # Any problems with this? self.stop_condition = self.animations[0].stop_condition else: # Static image logic when the wait is static is done by the renderer, not here. self.animations[0].is_static_wait = True return None return self def begin_animations(self) -> None: """Start the animations of the scene.""" assert self.animations is not None for animation in self.animations: animation._setup_scene(self) animation.begin() if config.renderer == RendererType.CAIRO: # Paint all non-moving objects onto the screen, so they don't # have to be rendered every frame ( self.moving_mobjects, self.static_mobjects, ) = self.get_moving_and_static_mobjects(self.animations) def is_current_animation_frozen_frame(self) -> bool: """Returns whether the current animation produces a static frame (generally a Wait).""" assert self.animations is not None return ( isinstance(self.animations[0], Wait) and len(self.animations) == 1 and self.animations[0].is_static_wait ) def play_internal(self, skip_rendering: bool = False) -> None: """ This method is used to prep the animations for rendering, apply the arguments and parameters required to them, render them, and write them to the video file. Parameters ---------- skip_rendering Whether the rendering should be skipped, by default False """ assert self.animations is not None self.duration = self.get_run_time(self.animations) self.time_progression = self._get_animation_time_progression( self.animations, self.duration, ) for t in self.time_progression: self.update_to_time(t) if not skip_rendering and not self.skip_animation_preview: self.renderer.render(self, t, self.moving_mobjects) if self.stop_condition is not None and self.stop_condition(): self.time_progression.close() break for animation in self.animations: animation.finish() animation.clean_up_from_scene(self) if not self.renderer.skip_animations: self.update_mobjects(0) # TODO: The OpenGLRenderer does not have the property static.image. self.renderer.static_image = None # type: ignore[union-attr] # Closing the progress bar at the end of the play. self.time_progression.close() def check_interactive_embed_is_valid(self) -> bool: assert isinstance(self.renderer, OpenGLRenderer) if config["force_window"]: return True if self.skip_animation_preview: logger.warning( "Disabling interactive embed as 'skip_animation_preview' is enabled", ) return False elif config["write_to_movie"]: logger.warning("Disabling interactive embed as 'write_to_movie' is enabled") return False elif config["format"]: logger.warning( "Disabling interactive embed as '--format' is set as " + config["format"], ) return False elif not self.renderer.window: logger.warning("Disabling interactive embed as no window was created") return False elif config.dry_run: logger.warning("Disabling interactive embed as dry_run is enabled") return False return True def interactive_embed(self) -> None: """Like embed(), but allows for screen interaction.""" assert isinstance(self.camera, OpenGLCamera) assert isinstance(self.renderer, OpenGLRenderer) if not self.check_interactive_embed_is_valid(): return self.interactive_mode = True from IPython.terminal.embed import InteractiveShellEmbed def ipython(shell: InteractiveShellEmbed, namespace: dict[str, Any]) -> None: import manim.opengl def load_module_into_namespace( module: Any, namespace: dict[str, Any] ) -> None: for name in dir(module): namespace[name] = getattr(module, name) load_module_into_namespace(manim, namespace) load_module_into_namespace(manim.opengl, namespace) def embedded_rerun(*args: Any, **kwargs: Any) -> None: self.queue.put(SceneInteractRerun("keyboard")) shell.exiter() namespace["rerun"] = embedded_rerun shell(local_ns=namespace) self.queue.put(SceneInteractContinue("keyboard")) def get_embedded_method(method_name: str) -> Callable[..., None]: method = getattr(self, method_name) def embedded_method(*args: Any, **kwargs: Any) -> None: self.queue.put(MethodWithArgs(method, args, kwargs)) return embedded_method currentframe: FrameType = inspect.currentframe() # type: ignore[assignment] local_namespace = currentframe.f_back.f_locals # type: ignore[union-attr] for method in ("play", "wait", "add", "remove"): embedded_method = get_embedded_method(method) # Allow for calling scene methods without prepending 'self.'. local_namespace[method] = embedded_method from sqlite3 import connect from IPython.core.getipython import get_ipython from traitlets.config import Config cfg = Config() cfg.TerminalInteractiveShell.confirm_exit = False if get_ipython() is None: shell = InteractiveShellEmbed.instance(config=cfg) else: shell = InteractiveShellEmbed(config=cfg) hist = get_ipython().history_manager hist.db = connect(hist.hist_file, check_same_thread=False) keyboard_thread = threading.Thread( target=ipython, args=(shell, local_namespace), ) # run as daemon to kill thread when main thread exits if not shell.pt_app: keyboard_thread.daemon = True keyboard_thread.start() if self.dearpygui_imported and config["enable_gui"]: if not dpg.is_dearpygui_running(): gui_thread = threading.Thread( target=self._configure_pygui, kwargs={"update": False}, ) gui_thread.start() else: self._configure_pygui(update=True) self.camera.model_matrix = self.camera.default_model_matrix self.interact(shell, keyboard_thread) # from IPython.terminal.embed import InteractiveShellEmbed def interact(self, shell: Any, keyboard_thread: threading.Thread) -> None: assert isinstance(self.renderer, OpenGLRenderer) event_handler = RerunSceneHandler(self.queue) file_observer = Observer() file_observer.schedule(event_handler, config["input_file"], recursive=True) file_observer.start() self.quit_interaction = False keyboard_thread_needs_join = shell.pt_app is not None assert self.queue.qsize() == 0 last_time = time.time() while not ( (self.renderer.window is not None and self.renderer.window.is_closing) or self.quit_interaction ): if not self.queue.empty(): action = self.queue.get_nowait() if isinstance(action, SceneInteractRerun): # Intentionally skip calling join() on the file thread to save time. if action.sender != "keyboard": if shell.pt_app: shell.pt_app.app.exit(exception=EOFError) file_observer.unschedule_all() raise RerunSceneException keyboard_thread.join() if "from_animation_number" in action.kwargs: config["from_animation_number"] = action.kwargs[ "from_animation_number" ] # # TODO: This option only makes sense if interactive_embed() is run at the # # end of a scene by default. # if "upto_animation_number" in action.kwargs: # config["upto_animation_number"] = action.kwargs[ # "upto_animation_number" # ] keyboard_thread.join() file_observer.unschedule_all() raise RerunSceneException elif isinstance(action, SceneInteractContinue): # Intentionally skip calling join() on the file thread to save time. if action.sender != "keyboard" and shell.pt_app: shell.pt_app.app.exit(exception=EOFError) keyboard_thread.join() # Remove exit_keyboard from the queue if necessary. while self.queue.qsize() > 0: self.queue.get() keyboard_thread_needs_join = False break else: action.method(*action.args, **action.kwargs) else: self.renderer.animation_start_time = 0 dt = time.time() - last_time last_time = time.time() self.renderer.render(self, dt, self.moving_mobjects) self.update_mobjects(dt) self.update_meshes(dt) self.update_self(dt) # Join the keyboard thread if necessary. if shell is not None and keyboard_thread_needs_join: shell.pt_app.app.exit(exception=EOFError) keyboard_thread.join() # Remove exit_keyboard from the queue if necessary. while self.queue.qsize() > 0: self.queue.get() file_observer.stop() file_observer.join() if self.dearpygui_imported and config["enable_gui"]: dpg.stop_dearpygui() if self.renderer.window is not None and self.renderer.window.is_closing: self.renderer.window.destroy() def embed(self) -> None: assert isinstance(self.renderer, OpenGLRenderer) if not config["preview"]: logger.warning("Called embed() while no preview window is available.") return if config["write_to_movie"]: logger.warning("embed() is skipped while writing to a file.") return self.renderer.animation_start_time = 0 self.renderer.render(self, -1, self.moving_mobjects) # Configure IPython shell. from IPython.terminal.embed import InteractiveShellEmbed shell = InteractiveShellEmbed() # Have the frame update after each command shell.events.register( "post_run_cell", lambda *a, **kw: self.renderer.render(self, -1, self.moving_mobjects), ) # Use the locals of the caller as the local namespace # once embedded, and add a few custom shortcuts. current_frame = inspect.currentframe() assert isinstance(current_frame, FrameType) local_ns = current_frame.f_back.f_locals # type: ignore[union-attr] # local_ns["touch"] = self.interact for method in ( "play", "wait", "add", "remove", "interact", # "clear", # "save_state", # "restore", ): local_ns[method] = getattr(self, method) shell(local_ns=local_ns, stack_depth=2) # End scene when exiting an embed. raise Exception("Exiting scene.") def _configure_pygui(self, update: bool = True) -> None: if not self.dearpygui_imported: raise RuntimeError("Attempted to use DearPyGUI when it isn't imported.") if update: dpg.delete_item(window) else: dpg.create_viewport() dpg.setup_dearpygui() dpg.show_viewport() dpg.set_viewport_title(title=f"Manim Community v{__version__}") dpg.set_viewport_width(1015) dpg.set_viewport_height(540) def rerun_callback(sender: Any, data: Any) -> None: self.queue.put(SceneInteractRerun("gui")) def continue_callback(sender: Any, data: Any) -> None: self.queue.put(SceneInteractContinue("gui")) def scene_selection_callback(sender: Any, data: Any) -> None: config["scene_names"] = (dpg.get_value(sender),) self.queue.put(SceneInteractRerun("gui")) scene_classes = scene_classes_from_file( Path(config["input_file"]), full_list=True ) # type: ignore[call-overload] scene_names = [scene_class.__name__ for scene_class in scene_classes] with dpg.window( id=window, label="Manim GUI", pos=[config["gui_location"][0], config["gui_location"][1]], width=1000, height=500, ): dpg.set_global_font_scale(2) dpg.add_button(label="Rerun", callback=rerun_callback) dpg.add_button(label="Continue", callback=continue_callback) dpg.add_combo( label="Selected scene", items=scene_names, callback=scene_selection_callback, default_value=config["scene_names"][0], ) dpg.add_separator() if len(self.widgets) != 0: with dpg.collapsing_header( label=f"{config['scene_names'][0]} widgets", default_open=True, ): for widget_config in self.widgets: widget_config_copy = widget_config.copy() name = widget_config_copy["name"] widget = widget_config_copy["widget"] if widget != "separator": del widget_config_copy["name"] del widget_config_copy["widget"] getattr(dpg, f"add_{widget}")( label=name, **widget_config_copy ) else: dpg.add_separator() if not update: dpg.start_dearpygui() def update_to_time(self, t: float) -> None: dt = t - self.last_t self.last_t = t assert self.animations is not None for animation in self.animations: animation.update_mobjects(dt) alpha = t / animation.run_time animation.interpolate(alpha) self.update_mobjects(dt) self.update_meshes(dt) self.update_self(dt) def add_subcaption( self, content: str, duration: float = 1, offset: float = 0 ) -> None: r"""Adds an entry in the corresponding subcaption file at the current time stamp. The current time stamp is obtained from ``Scene.time``. Parameters ---------- content The subcaption content. duration The duration (in seconds) for which the subcaption is shown. offset This offset (in seconds) is added to the starting time stamp of the subcaption. Examples -------- This example illustrates both possibilities for adding subcaptions to Manimations:: class SubcaptionExample(Scene): def construct(self): square = Square() circle = Circle() # first option: via the add_subcaption method self.add_subcaption("Hello square!", duration=1) self.play(Create(square)) # second option: within the call to Scene.play self.play( Transform(square, circle), subcaption="The square transforms." ) """ subtitle = srt.Subtitle( index=len(self.renderer.file_writer.subcaptions), content=content, start=datetime.timedelta(seconds=float(self.time + offset)), end=datetime.timedelta(seconds=float(self.time + offset + duration)), ) self.renderer.file_writer.subcaptions.append(subtitle) def add_sound( self, sound_file: str, time_offset: float = 0, gain: float | None = None, **kwargs: Any, ) -> None: """ This method is used to add a sound to the animation. Parameters ---------- sound_file The path to the sound file. time_offset The offset in the sound file after which the sound can be played. gain Amplification of the sound. Examples -------- .. manim:: SoundExample :no_autoplay: class SoundExample(Scene): # Source of sound under Creative Commons 0 License. https://freesound.org/people/Druminfected/sounds/250551/ def construct(self): dot = Dot().set_color(GREEN) self.add_sound("click.wav") self.add(dot) self.wait() self.add_sound("click.wav") dot.set_color(BLUE) self.wait() self.add_sound("click.wav") dot.set_color(RED) self.wait() Download the resource for the previous example `here `_ . """ if self.renderer.skip_animations: return time = self.time + time_offset self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs) def on_mouse_motion(self, point: Point3D, d_point: Point3D) -> None: assert isinstance(self.camera, OpenGLCamera) assert isinstance(self.renderer, OpenGLRenderer) self.mouse_point.move_to(point) if SHIFT_VALUE in self.renderer.pressed_keys: shift = -d_point shift[0] *= self.camera.get_width() / 2 shift[1] *= self.camera.get_height() / 2 transform = self.camera.inverse_rotation_matrix shift = np.dot(np.transpose(transform), shift) self.camera.shift(shift) def on_mouse_scroll(self, point: Point3D, offset: Point3D) -> None: assert isinstance(self.camera, OpenGLCamera) if not config.use_projection_stroke_shaders: factor = 1 + np.arctan(-2.1 * offset[1]) self.camera.scale(factor, about_point=self.camera_target) self.mouse_scroll_orbit_controls(point, offset) def on_key_press(self, symbol: int, modifiers: int) -> None: assert isinstance(self.camera, OpenGLCamera) try: char = chr(symbol) except OverflowError: logger.warning("The value of the pressed key is too large.") return if char == "r": self.camera.to_default_state() self.camera_target = np.array([0, 0, 0], dtype=np.float32) elif char == "q": self.quit_interaction = True else: if char in self.key_to_function_map: self.key_to_function_map[char]() def on_key_release(self, symbol: int, modifiers: int) -> None: pass def on_mouse_drag( self, point: Point3D, d_point: Point3D, buttons: int, modifiers: int, ) -> None: assert isinstance(self.camera, OpenGLCamera) self.mouse_drag_point.move_to(point) if buttons == 1: self.camera.increment_theta(-d_point[0]) self.camera.increment_phi(d_point[1]) elif buttons == 4: camera_x_axis = self.camera.model_matrix[:3, 0] horizontal_shift_vector = -d_point[0] * camera_x_axis vertical_shift_vector = -d_point[1] * np.cross(OUT, camera_x_axis) total_shift_vector = horizontal_shift_vector + vertical_shift_vector self.camera.shift(1.1 * total_shift_vector) self.mouse_drag_orbit_controls(point, d_point, buttons, modifiers) def mouse_scroll_orbit_controls(self, point: Point3D, offset: Point3D) -> None: assert isinstance(self.camera, OpenGLCamera) camera_to_target = self.camera_target - self.camera.get_position() camera_to_target *= np.sign(offset[1]) shift_vector = 0.01 * camera_to_target self.camera.model_matrix = ( opengl.translation_matrix(*shift_vector) @ self.camera.model_matrix ) def mouse_drag_orbit_controls( self, point: Point3D, d_point: Point3D, buttons: int, modifiers: int, ) -> None: assert isinstance(self.camera, OpenGLCamera) # Left click drag. if buttons == 1: # Translate to target the origin and rotate around the z axis. self.camera.model_matrix = ( opengl.rotation_matrix(z=-d_point[0]) @ opengl.translation_matrix(*-self.camera_target) @ self.camera.model_matrix ) # Rotation off of the z axis. camera_position = self.camera.get_position() camera_y_axis = self.camera.model_matrix[:3, 1] axis_of_rotation = space_ops.normalize( np.cross(camera_y_axis, camera_position), ) rotation_matrix = space_ops.rotation_matrix( d_point[1], axis_of_rotation, homogeneous=True, ) maximum_polar_angle = self.camera.maximum_polar_angle minimum_polar_angle = self.camera.minimum_polar_angle potential_camera_model_matrix = rotation_matrix @ self.camera.model_matrix potential_camera_location = potential_camera_model_matrix[:3, 3] potential_camera_y_axis = potential_camera_model_matrix[:3, 1] sign = ( np.sign(potential_camera_y_axis[2]) if potential_camera_y_axis[2] != 0 else 1 ) potential_polar_angle = sign * np.arccos( potential_camera_location[2] / np.linalg.norm(potential_camera_location), ) if minimum_polar_angle <= potential_polar_angle <= maximum_polar_angle: self.camera.model_matrix = potential_camera_model_matrix else: sign = np.sign(camera_y_axis[2]) if camera_y_axis[2] != 0 else 1 current_polar_angle = sign * np.arccos( camera_position[2] / np.linalg.norm(camera_position), ) if potential_polar_angle > maximum_polar_angle: polar_angle_delta = maximum_polar_angle - current_polar_angle else: polar_angle_delta = minimum_polar_angle - current_polar_angle rotation_matrix = space_ops.rotation_matrix( polar_angle_delta, axis_of_rotation, homogeneous=True, ) self.camera.model_matrix = rotation_matrix @ self.camera.model_matrix # Translate to target the original target. self.camera.model_matrix = ( opengl.translation_matrix(*self.camera_target) @ self.camera.model_matrix ) # Right click drag. elif buttons == 4: camera_x_axis = self.camera.model_matrix[:3, 0] horizontal_shift_vector = -d_point[0] * camera_x_axis vertical_shift_vector = -d_point[1] * np.cross(OUT, camera_x_axis) total_shift_vector = horizontal_shift_vector + vertical_shift_vector self.camera.model_matrix = ( opengl.translation_matrix(*total_shift_vector) @ self.camera.model_matrix ) self.camera_target += total_shift_vector def set_key_function(self, char: str, func: Callable[[], Any]) -> None: self.key_to_function_map[char] = func def on_mouse_press(self, point: Point3D, button: str, modifiers: int) -> None: for func in self.mouse_press_callbacks: func() ================================================ FILE: manim/scene/scene_file_writer.py ================================================ """The interface between scenes and ffmpeg.""" from __future__ import annotations __all__ = ["SceneFileWriter"] import json import shutil import warnings from fractions import Fraction from pathlib import Path from queue import Queue from tempfile import NamedTemporaryFile, _TemporaryFileWrapper from threading import Thread from typing import TYPE_CHECKING, Any import av import numpy as np import srt from PIL import Image # Manim handles audio conversion through PyAV directly. Importing pydub emits a # RuntimeWarning if ffmpeg/avconv is not on PATH, even when only WAV code paths # are used (which do not need ffmpeg). Silence this specific warning. with warnings.catch_warnings(): warnings.filterwarnings( "ignore", message=r".*ffmpeg or avconv.*", category=RuntimeWarning, ) from pydub import AudioSegment from manim import __version__ from .. import config, logger from .._config.logger_utils import set_file_logger from ..constants import RendererType from ..utils.file_ops import ( add_extension_if_not_present, add_version_before_extension, guarantee_existence, is_gif_format, is_png_format, modify_atime, write_to_movie, ) from ..utils.sounds import get_full_sound_file_path from .section import DefaultSectionType, Section if TYPE_CHECKING: from av.container.output import OutputContainer from av.stream import Stream from manim.renderer.cairo_renderer import CairoRenderer from manim.renderer.opengl_renderer import OpenGLRenderer from manim.typing import PixelArray, StrPath def to_av_frame_rate(fps: float) -> Fraction: epsilon1 = 1e-4 epsilon2 = 0.02 if isinstance(fps, int): (num, denom) = (fps, 1) elif abs(fps - round(fps)) < epsilon1: (num, denom) = (round(fps), 1) else: denom = 1001 num = round(fps * denom / 1000) * 1000 if abs(fps - num / denom) >= epsilon2: raise ValueError("invalid frame rate") return Fraction(num, denom) def convert_audio( input_path: Path, output_path: Path | _TemporaryFileWrapper[bytes], codec_name: str ) -> None: with ( av.open(input_path) as input_audio, av.open(output_path, "w") as output_audio, ): input_audio_stream = input_audio.streams.audio[0] output_audio_stream = output_audio.add_stream(codec_name) for frame in input_audio.decode(input_audio_stream): for packet in output_audio_stream.encode(frame): output_audio.mux(packet) for packet in output_audio_stream.encode(): output_audio.mux(packet) class SceneFileWriter: """SceneFileWriter is the object that actually writes the animations played, into video files, using FFMPEG. This is mostly for Manim's internal use. You will rarely, if ever, have to use the methods for this class, unless tinkering with the very fabric of Manim's reality. Attributes ---------- sections : list of :class:`.Section` used to segment scene sections_output_dir : :class:`pathlib.Path` where are section videos stored output_name : str name of movie without extension and basis for section video names Some useful attributes are: "write_to_movie" (bool=False) Whether or not to write the animations into a video file. "movie_file_extension" (str=".mp4") The file-type extension of the outputted video. "partial_movie_files" List of all the partial-movie files. """ force_output_as_scene_name = False def __init__( self, renderer: CairoRenderer | OpenGLRenderer, scene_name: str, **kwargs: Any, ) -> None: self.renderer = renderer self.init_output_directories(scene_name) self.init_audio() self.frame_count = 0 self.partial_movie_files: list[str | None] = [] self.subcaptions: list[srt.Subtitle] = [] self.sections: list[Section] = [] # first section gets automatically created for convenience # if you need the first section to be skipped, add a first section by hand, it will replace this one self.next_section( name="autocreated", type_=DefaultSectionType.NORMAL, skip_animations=False ) def init_output_directories(self, scene_name: str) -> None: """Initialise output directories. Notes ----- The directories are read from ``config``, for example ``config['media_dir']``. If the target directories don't already exist, they will be created. """ if config["dry_run"]: # in dry-run mode there is no output return module_name = config.get_dir("input_file").stem if config["input_file"] else "" if SceneFileWriter.force_output_as_scene_name: self.output_name = Path(scene_name) elif config["output_file"] and not config["write_all"]: self.output_name = config.get_dir("output_file") else: self.output_name = Path(scene_name) if config["media_dir"]: image_dir = guarantee_existence( config.get_dir( "images_dir", module_name=module_name, scene_name=scene_name ), ) self.image_file_path = image_dir / add_extension_if_not_present( self.output_name, ".png" ) if write_to_movie(): movie_dir = guarantee_existence( config.get_dir( "video_dir", module_name=module_name, scene_name=scene_name ), ) self.movie_file_path = movie_dir / add_extension_if_not_present( self.output_name, config["movie_file_extension"] ) # TODO: /dev/null would be good in case sections_output_dir is used without being set (doesn't work on Windows), everyone likes defensive programming, right? self.sections_output_dir = Path("") if config.save_sections: self.sections_output_dir = guarantee_existence( config.get_dir( "sections_dir", module_name=module_name, scene_name=scene_name ) ) if is_gif_format(): self.gif_file_path = add_extension_if_not_present( self.output_name, ".gif" ) if not config["output_file"]: self.gif_file_path = add_version_before_extension( self.gif_file_path ) self.gif_file_path = movie_dir / self.gif_file_path self.partial_movie_directory = guarantee_existence( config.get_dir( "partial_movie_dir", scene_name=scene_name, module_name=module_name, ), ) if config["log_to_file"]: log_dir = guarantee_existence(config.get_dir("log_dir")) set_file_logger( scene_name=scene_name, module_name=module_name, log_dir=log_dir ) def finish_last_section(self) -> None: """Delete current section if it is empty.""" if len(self.sections) and self.sections[-1].is_empty(): self.sections.pop() def next_section(self, name: str, type_: str, skip_animations: bool) -> None: """Create segmentation cut here.""" self.finish_last_section() # images don't support sections section_video: str | None = None # don't save when None if ( not config.dry_run and write_to_movie() and config.save_sections and not skip_animations ): # relative to index file section_video = f"{self.output_name}_{len(self.sections):04}_{name}{config.movie_file_extension}" self.sections.append( Section( type_, section_video, name, skip_animations, ), ) def add_partial_movie_file(self, hash_animation: str | None) -> None: """Adds a new partial movie file path to ``scene.partial_movie_files`` and current section from a hash. This method will compute the path from the hash. In addition to that it adds the new animation to the current section. Parameters ---------- hash_animation Hash of the animation. """ if not hasattr(self, "partial_movie_directory") or not write_to_movie(): return # None has to be added to partial_movie_files to keep the right index with scene.num_plays. # i.e if an animation is skipped, scene.num_plays is still incremented and we add an element to partial_movie_file be even with num_plays. if hash_animation is None: self.partial_movie_files.append(None) self.sections[-1].partial_movie_files.append(None) else: new_partial_movie_file = str( self.partial_movie_directory / f"{hash_animation}{config['movie_file_extension']}" ) self.partial_movie_files.append(new_partial_movie_file) self.sections[-1].partial_movie_files.append(new_partial_movie_file) def get_resolution_directory(self) -> str: """Get the name of the resolution directory directly containing the video file. This method gets the name of the directory that immediately contains the video file. This name is ``p``. For example, if you are rendering an 854x480 px animation at 15fps, the name of the directory that immediately contains the video, file will be ``480p15``. The file structure should look something like:: MEDIA_DIR |--Tex |--texts |--videos |-- |--p |--partial_movie_files |--.mp4 |--.srt Returns ------- :class:`str` The name of the directory. """ pixel_height = config["pixel_height"] frame_rate = config["frame_rate"] return f"{pixel_height}p{frame_rate}" # Sound def init_audio(self) -> None: """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.""" self.audio_segment = AudioSegment.silent() def add_audio_segment( self, new_segment: AudioSegment, time: float | None = None, gain_to_background: float | None = None, ) -> None: """This method adds an audio segment from an AudioSegment type object and suitable parameters. Parameters ---------- new_segment The audio segment to add time the timestamp at which the sound should be added. gain_to_background The gain of the segment from the background. """ if not self.includes_sound: self.includes_sound = True self.create_audio_segment() segment = self.audio_segment curr_end = segment.duration_seconds if time is None: time = curr_end if time < 0: raise ValueError("Adding sound at timestamp < 0") new_end = time + new_segment.duration_seconds diff = new_end - curr_end if diff > 0: segment = segment.append( AudioSegment.silent(int(np.ceil(diff * 1000))), crossfade=0, ) self.audio_segment = segment.overlay( new_segment, position=int(1000 * time), gain_during_overlay=gain_to_background, ) def add_sound( self, sound_file: StrPath, time: float | None = None, gain: float | None = None, **kwargs: Any, ) -> None: """This method adds an audio segment from a sound file. Parameters ---------- sound_file The path to the sound file. time The timestamp at which the audio should be added. gain The gain of the given audio segment. **kwargs This method uses add_audio_segment, so any keyword arguments used there can be referenced here. """ file_path = get_full_sound_file_path(sound_file) # we assume files with .wav / .raw suffix are actually # .wav and .raw files, respectively. if file_path.suffix not in (".wav", ".raw"): # we need to pass delete=False to work on Windows # TODO: figure out a way to cache the wav file generated (benchmark needed) with NamedTemporaryFile(suffix=".wav", delete=False) as wav_file_path: convert_audio(file_path, wav_file_path, "pcm_s16le") new_segment = AudioSegment.from_file(wav_file_path.name) logger.info(f"Automatically converted {file_path} to .wav") Path(wav_file_path.name).unlink() else: new_segment = AudioSegment.from_file(file_path) if gain: new_segment = new_segment.apply_gain(gain) self.add_audio_segment(new_segment, time, **kwargs) # Writers def begin_animation( self, allow_write: bool = False, file_path: StrPath | None = None ) -> None: """Used internally by manim to stream the animation to FFMPEG for displaying or writing to a file. Parameters ---------- allow_write Whether or not to write to a video file. """ if write_to_movie() and allow_write: self.open_partial_movie_stream(file_path=file_path) def end_animation(self, allow_write: bool = False) -> None: """Internally used by Manim to stop streaming to FFMPEG gracefully. Parameters ---------- allow_write Whether or not to write to a video file. """ if write_to_movie() and allow_write: self.close_partial_movie_stream() def listen_and_write(self) -> None: """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: break self.encode_and_write_frame(frame_data, num_frames) def encode_and_write_frame(self, frame: PixelArray, num_frames: int) -> None: """For internal use only: takes a given frame in ``np.ndarray`` format and writes it to the stream """ for _ in range(num_frames): # Notes: precomputing reusing packets does not work! # I.e., you cannot do `packets = encode(...)` # and reuse it, as it seems that `mux(...)` # consumes the packet. # The same issue applies for `av_frame`, # reusing it renders weird-looking frames. av_frame = av.VideoFrame.from_ndarray(frame, format="rgba") for packet in self.video_stream.encode(av_frame): self.video_container.mux(packet) def write_frame( self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1 ) -> None: """Used internally by Manim to write a frame to the FFMPEG input buffer. Parameters ---------- frame_or_renderer Pixel array of the frame. num_frames The number of times to write frame. """ if write_to_movie(): if isinstance(frame_or_renderer, np.ndarray): frame = frame_or_renderer else: frame = ( frame_or_renderer.get_frame() if config.renderer == RendererType.OPENGL else frame_or_renderer ) msg = (num_frames, frame) self.queue.put(msg) if is_png_format() and not config["dry_run"]: if isinstance(frame_or_renderer, np.ndarray): image = Image.fromarray(frame_or_renderer) else: image = ( frame_or_renderer.get_image() if config.renderer == RendererType.OPENGL else Image.fromarray(frame_or_renderer) ) target_dir = self.image_file_path.parent / self.image_file_path.stem extension = self.image_file_path.suffix self.output_image( image, target_dir, extension, config["zero_pad"], ) def output_image( self, image: Image.Image, target_dir: StrPath, ext: str, zero_pad: int ) -> None: if zero_pad: image.save(f"{target_dir}{str(self.frame_count).zfill(zero_pad)}{ext}") else: image.save(f"{target_dir}{self.frame_count}{ext}") self.frame_count += 1 def save_image(self, image: Image.Image) -> None: """This method saves the image passed to it in the default image directory. Parameters ---------- image The pixel array of the image to save. """ if config["dry_run"]: return if not config["output_file"]: self.image_file_path = add_version_before_extension(self.image_file_path) image.save(self.image_file_path) self.print_file_ready_message(self.image_file_path) def finish(self) -> None: """Finishes writing to the FFMPEG buffer or writing images to output directory. Combines the partial movie files into the whole scene. If save_last_frame is True, saves the last frame in the default image directory. """ if write_to_movie(): self.combine_to_movie() if config.save_sections: self.combine_to_section_videos() if config["flush_cache"]: self.flush_cache_directory() else: self.clean_cache() elif is_png_format() and not config["dry_run"]: target_dir = self.image_file_path.parent / self.image_file_path.stem logger.info("\n%i images ready at %s\n", self.frame_count, str(target_dir)) if self.subcaptions: self.write_subcaption_file() def open_partial_movie_stream(self, file_path: StrPath | None = None) -> None: """Open a container holding a video stream. This is used internally by Manim initialize the container holding the video stream of a partial movie file. """ if file_path is None: file_path = self.partial_movie_files[self.renderer.num_plays] self.partial_movie_file_path = file_path fps = to_av_frame_rate(config.frame_rate) partial_movie_file_codec = "libx264" partial_movie_file_pix_fmt = "yuv420p" av_options = { "an": "1", # ffmpeg: -an, no audio "crf": "23", # ffmpeg: -crf, constant rate factor (improved bitrate) } if config.movie_file_extension == ".webm": partial_movie_file_codec = "libvpx-vp9" av_options["-auto-alt-ref"] = "1" if config.transparent: partial_movie_file_pix_fmt = "yuva420p" elif config.transparent: partial_movie_file_codec = "qtrle" partial_movie_file_pix_fmt = "argb" video_container = av.open(file_path, mode="w") stream = video_container.add_stream( partial_movie_file_codec, rate=fps, options=av_options, ) stream.pix_fmt = partial_movie_file_pix_fmt stream.width = config.pixel_width stream.height = config.pixel_height self.video_container: OutputContainer = video_container self.video_stream: Stream = stream self.queue: Queue[tuple[int, PixelArray | None]] = Queue() self.writer_thread = Thread(target=self.listen_and_write, args=()) self.writer_thread.start() def close_partial_movie_stream(self) -> None: """Close the currently opened video container. Used internally by Manim to first flush the remaining packages in the video stream holding a partial file, and then close the corresponding container. """ self.queue.put((-1, None)) self.writer_thread.join() for packet in self.video_stream.encode(): self.video_container.mux(packet) self.video_container.close() logger.info( f"Animation {self.renderer.num_plays} : Partial movie file written in %(path)s", {"path": f"'{self.partial_movie_file_path}'"}, ) def is_already_cached(self, hash_invocation: str) -> bool: """Will check if a file named with `hash_invocation` exists. Parameters ---------- hash_invocation The hash corresponding to an invocation to either `scene.play` or `scene.wait`. Returns ------- :class:`bool` Whether the file exists. """ if not hasattr(self, "partial_movie_directory") or not write_to_movie(): return False path = ( self.partial_movie_directory / f"{hash_invocation}{config['movie_file_extension']}" ) return path.exists() def combine_files( self, input_files: list[str], output_file: Path, create_gif: bool = False, includes_sound: bool = False, ) -> None: file_list = self.partial_movie_directory / "partial_movie_file_list.txt" logger.debug( f"Partial movie files to combine ({len(input_files)} files): %(p)s", {"p": input_files[:5]}, ) with file_list.open("w", encoding="utf-8") as fp: fp.write("# This file is used internally by FFMPEG.\n") for pf_path in input_files: pf_path = Path(pf_path).as_posix() fp.write(f"file 'file:{pf_path}'\n") av_options = { "safe": "0", # needed to read files } if not includes_sound: av_options["an"] = "1" partial_movies_input = av.open( str(file_list), options=av_options, format="concat" ) partial_movies_stream = partial_movies_input.streams.video[0] output_container = av.open(str(output_file), mode="w") output_container.metadata["comment"] = ( f"Rendered with Manim Community v{__version__}" ) if create_gif: """The following solution was largely inspired from this comment https://github.com/imageio/imageio/issues/995#issuecomment-1580533018, and the following code https://github.com/imageio/imageio/blob/65d79140018bb7c64c0692ea72cb4093e8d632a0/imageio/plugins/pyav.py#L927-L996. """ output_stream = output_container.add_stream( codec_name="gif", ) output_stream.pix_fmt = "rgb8" if config.transparent: output_stream.pix_fmt = "pal8" output_stream.width = config.pixel_width output_stream.height = config.pixel_height output_stream.rate = to_av_frame_rate(config.frame_rate) graph = av.filter.Graph() input_buffer = graph.add_buffer(template=partial_movies_stream) split = graph.add("split") palettegen = graph.add("palettegen", "stats_mode=diff") paletteuse = graph.add( "paletteuse", "dither=bayer:bayer_scale=5:diff_mode=rectangle" ) output_sink = graph.add("buffersink") input_buffer.link_to(split) split.link_to(palettegen, 0, 0) # 1st input of split -> input of palettegen split.link_to(paletteuse, 1, 0) # 2nd output of split -> 1st input palettegen.link_to(paletteuse, 0, 1) # output of palettegen -> 2nd input paletteuse.link_to(output_sink) graph.configure() for frame in partial_movies_input.decode(video=0): graph.push(frame) graph.push(None) # EOF: https://github.com/PyAV-Org/PyAV/issues/886. frames_written = 0 while True: try: frame = graph.pull() if output_stream.codec_context.time_base is not None: frame.time_base = output_stream.codec_context.time_base frame.pts = frames_written frames_written += 1 output_container.mux(output_stream.encode(frame)) except av.error.EOFError: break for packet in output_stream.encode(): output_container.mux(packet) else: output_stream = output_container.add_stream_from_template( template=partial_movies_stream, ) if config.transparent and config.movie_file_extension == ".webm": output_stream.pix_fmt = "yuva420p" for packet in partial_movies_input.demux(partial_movies_stream): # We need to skip the "flushing" packets that `demux` generates. if packet.dts is None: continue packet.dts = None # This seems to be needed, as dts from consecutive # files may not be monotically increasing, so we let libav compute it. # We need to assign the packet to the new stream. packet.stream = output_stream output_container.mux(packet) partial_movies_input.close() output_container.close() def combine_to_movie(self) -> None: """Used internally by Manim to combine the separate partial movie files that make up a Scene into a single video file for that Scene. """ partial_movie_files = [el for el in self.partial_movie_files if el is not None] # NOTE: Here we should do a check and raise an exception if partial # movie file is empty. We can't, as a lot of stuff (in particular, in # tests) use scene initialization, and this error would be raised as # it's just an empty scene initialized. # determine output path movie_file_path = self.movie_file_path if is_gif_format(): movie_file_path = self.gif_file_path if len(partial_movie_files) == 0: # Prevent calling concat on empty list logger.info("No animations are contained in this scene.") return logger.info("Combining to Movie file.") self.combine_files( partial_movie_files, movie_file_path, is_gif_format(), self.includes_sound, ) # handle sound if self.includes_sound and config.format != "gif": sound_file_path = movie_file_path.with_suffix(".wav") # Makes sure sound file length will match video file self.add_audio_segment(AudioSegment.silent(0)) self.audio_segment.export( sound_file_path, format="wav", bitrate="312k", ) # Audio added to a VP9 encoded (webm) video file needs # to be encoded as vorbis or opus. Directly exporting # self.audio_segment with such a codec works in principle, # but tries to call ffmpeg via its CLI -- which we want # to avoid. This is why we need to do the conversion # manually. if config.movie_file_extension == ".webm": ogg_sound_file_path = sound_file_path.with_suffix(".ogg") convert_audio(sound_file_path, ogg_sound_file_path, "libvorbis") sound_file_path = ogg_sound_file_path elif config.movie_file_extension == ".mp4": # Similarly, pyav may reject wav audio in an .mp4 file; # convert to AAC. aac_sound_file_path = sound_file_path.with_suffix(".aac") convert_audio(sound_file_path, aac_sound_file_path, "aac") sound_file_path = aac_sound_file_path temp_file_path = movie_file_path.with_name( f"{movie_file_path.stem}_temp{movie_file_path.suffix}" ) av_options = { "shortest": "1", "metadata": f"comment=Rendered with Manim Community v{__version__}", } with ( av.open(movie_file_path) as video_input, av.open(sound_file_path) as audio_input, ): video_stream = video_input.streams.video[0] audio_stream = audio_input.streams.audio[0] output_container = av.open( str(temp_file_path), mode="w", options=av_options ) output_video_stream = output_container.add_stream_from_template( template=video_stream ) output_audio_stream = output_container.add_stream_from_template( template=audio_stream ) for packet in video_input.demux(video_stream): # We need to skip the "flushing" packets that `demux` generates. if packet.dts is None: continue # We need to assign the packet to the new stream. packet.stream = output_video_stream output_container.mux(packet) for packet in audio_input.demux(audio_stream): # We need to skip the "flushing" packets that `demux` generates. if packet.dts is None: continue # We need to assign the packet to the new stream. packet.stream = output_audio_stream output_container.mux(packet) output_container.close() shutil.move(str(temp_file_path), str(movie_file_path)) sound_file_path.unlink() self.print_file_ready_message(str(movie_file_path)) if write_to_movie(): for file_path in partial_movie_files: # We have to modify the accessed time so if we have to clean the cache we remove the one used the longest. modify_atime(file_path) 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: # only if section does want to be saved if section.video is not None: logger.info(f"Combining partial files for section '{section.name}'") self.combine_files( section.get_clean_partial_movie_files(), self.sections_output_dir / section.video, ) sections_index.append(section.get_dict(self.sections_output_dir)) with (self.sections_output_dir / f"{self.output_name}.json").open("w") as file: json.dump(sections_index, file, indent=4) def clean_cache(self) -> None: """Will clean the cache by removing the oldest partial_movie_files.""" cached_partial_movies = [ (self.partial_movie_directory / file_name) for file_name in self.partial_movie_directory.iterdir() if file_name != "partial_movie_file_list.txt" ] if len(cached_partial_movies) > config["max_files_cached"]: number_files_to_delete = ( len(cached_partial_movies) - config["max_files_cached"] ) oldest_files_to_delete = sorted( cached_partial_movies, key=lambda path: path.stat().st_atime, )[:number_files_to_delete] for file_to_delete in oldest_files_to_delete: file_to_delete.unlink() logger.info( f"The partial movie directory is full (> {config['max_files_cached']} files). Therefore, manim has removed the {number_files_to_delete} oldest file(s)." " You can change this behaviour by changing max_files_cached in config.", ) def flush_cache_directory(self) -> None: """Delete all the cached partial movie files""" cached_partial_movies = [ self.partial_movie_directory / file_name for file_name in self.partial_movie_directory.iterdir() if file_name != "partial_movie_file_list.txt" ] for f in cached_partial_movies: f.unlink() logger.info( f"Cache flushed. {len(cached_partial_movies)} file(s) deleted in %(par_dir)s.", {"par_dir": self.partial_movie_directory}, ) def write_subcaption_file(self) -> None: """Writes the subcaption file.""" if config.output_file is None: return subcaption_file = Path(config.output_file).with_suffix(".srt") subcaption_file.write_text(srt.compose(self.subcaptions), encoding="utf-8") logger.info(f"Subcaption file has been written as {subcaption_file}") def print_file_ready_message(self, file_path: StrPath) -> None: """Prints the "File Ready" message to STDOUT.""" config["output_file"] = file_path logger.info("\nFile ready at %(file_path)s\n", {"file_path": f"'{file_path}'"}) ================================================ FILE: manim/scene/section.py ================================================ """building blocks of segmented video API""" from __future__ import annotations from enum import Enum from pathlib import Path from typing import Any from manim import get_video_metadata __all__ = ["Section", "DefaultSectionType"] class DefaultSectionType(str, Enum): """The type of a section can be used for third party applications. A presentation system could for example use the types to created loops. Examples -------- This class can be reimplemented for more types:: class PresentationSectionType(str, Enum): # start, end, wait for continuation by user NORMAL = "presentation.normal" # start, end, immediately continue to next section SKIP = "presentation.skip" # start, end, restart, immediately continue to next section when continued by user LOOP = "presentation.loop" # start, end, restart, finish animation first when user continues COMPLETE_LOOP = "presentation.complete_loop" """ NORMAL = "default.normal" class Section: r"""A :class:`.Scene` can be segmented into multiple Sections. Refer to :doc:`the documentation` for more info. It consists of multiple animations. Attributes ---------- type\_ Can be used by a third party applications to classify different types of sections. video Path to video file with animations belonging to section relative to sections directory. If ``None``, then the section will not be saved. name Human readable, non-unique name for this section. skip_animations Skip rendering the animations in this section when ``True``. partial_movie_files Animations belonging to this section. See Also -------- :class:`.DefaultSectionType` :meth:`.CairoRenderer.update_skipping_status` :meth:`.OpenGLRenderer.update_skipping_status` """ def __init__( self, type_: str, video: str | None, name: str, skip_animations: bool ) -> None: self.type_ = type_ # None when not to be saved -> still keeps section alive self.video: str | None = video self.name = name self.skip_animations = skip_animations self.partial_movie_files: list[str | None] = [] def is_empty(self) -> bool: """Check whether this section is empty. Note that animations represented by ``None`` are also counted. """ return len(self.partial_movie_files) == 0 def get_clean_partial_movie_files(self) -> list[str]: """Return all partial movie files that are not ``None``.""" return [el for el in self.partial_movie_files if el is not None] def get_dict(self, sections_dir: Path) -> dict[str, Any]: """Get dictionary representation with metadata of output video. The output from this function is used from every section to build the sections index file. The output video must have been created in the ``sections_dir`` before executing this method. This is the main part of the Segmented Video API. """ if self.video is None: raise ValueError( f"Section '{self.name}' cannot be exported as dict, it does not have a video path assigned to it" ) video_metadata = get_video_metadata(sections_dir / self.video) return dict( { "name": self.name, "type": self.type_, "video": self.video, }, **video_metadata, ) def __repr__(self) -> str: return f"
" ================================================ FILE: manim/scene/three_d_scene.py ================================================ """A scene suitable for rendering three-dimensional objects and animations.""" from __future__ import annotations __all__ = ["ThreeDScene", "SpecialThreeDScene"] import warnings from collections.abc import Iterable, Sequence import numpy as np from manim.mobject.geometry.line import Line from manim.mobject.graphing.coordinate_systems import ThreeDAxes from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.three_d.three_dimensions import Sphere from manim.mobject.value_tracker import ValueTracker from .. import config from ..animation.animation import Animation from ..animation.transform import Transform from ..camera.three_d_camera import ThreeDCamera from ..constants import DEGREES, RendererType from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VectorizedPoint, VGroup from ..renderer.opengl_renderer import OpenGLCamera from ..scene.scene import Scene from ..utils.config_ops import merge_dicts_recursively class ThreeDScene(Scene): """ This is a Scene, with special configurations and properties that make it suitable for Three Dimensional Scenes. """ def __init__( self, camera_class=ThreeDCamera, ambient_camera_rotation=None, default_angled_camera_orientation_kwargs=None, **kwargs, ): self.ambient_camera_rotation = ambient_camera_rotation if default_angled_camera_orientation_kwargs is None: default_angled_camera_orientation_kwargs = { "phi": 70 * DEGREES, "theta": -135 * DEGREES, } self.default_angled_camera_orientation_kwargs = ( default_angled_camera_orientation_kwargs ) super().__init__(camera_class=camera_class, **kwargs) def set_camera_orientation( self, phi: float | None = None, theta: float | None = None, gamma: float | None = None, zoom: float | None = None, focal_distance: float | None = None, frame_center: Mobject | Sequence[float] | None = None, **kwargs, ): """ This method sets the orientation of the camera in the scene. Parameters ---------- phi The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians. theta The azimuthal angle i.e the angle that spins the camera around the Z_AXIS. focal_distance The focal_distance of the Camera. gamma The rotation of the camera about the vector from the ORIGIN to the Camera. zoom The zoom factor of the scene. frame_center 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: self.renderer.camera.set_theta(theta) if focal_distance is not None: self.renderer.camera.set_focal_distance(focal_distance) if gamma is not None: self.renderer.camera.set_gamma(gamma) if zoom is not None: self.renderer.camera.set_zoom(zoom) if frame_center is not None: self.renderer.camera._frame_center.move_to(frame_center) def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = "theta"): """ This method begins an ambient rotation of the camera about the Z_AXIS, in the anticlockwise direction Parameters ---------- rate The rate at which the camera should rotate about the Z_AXIS. Negative rate means clockwise rotation. about one of 3 options: ["theta", "phi", "gamma"]. defaults to theta. """ # TODO, use a ValueTracker for rate, so that it # can begin and end smoothly about: str = about.lower() try: if config.renderer == RendererType.CAIRO: trackers = { "theta": self.camera.theta_tracker, "phi": self.camera.phi_tracker, "gamma": self.camera.gamma_tracker, } x: ValueTracker = trackers[about] x.add_updater(lambda m, dt: x.increment_value(rate * dt)) self.add(x) elif config.renderer == RendererType.OPENGL: cam: OpenGLCamera = self.camera methods = { "theta": cam.increment_theta, "phi": cam.increment_phi, "gamma": cam.increment_gamma, } cam.add_updater(lambda m, dt: methods[about](rate * dt)) self.add(self.camera) except Exception as e: raise ValueError("Invalid ambient rotation angle.") from e def stop_ambient_camera_rotation(self, about="theta"): """This method stops all ambient camera rotation.""" about: str = about.lower() try: if config.renderer == RendererType.CAIRO: trackers = { "theta": self.camera.theta_tracker, "phi": self.camera.phi_tracker, "gamma": self.camera.gamma_tracker, } x: ValueTracker = trackers[about] x.clear_updaters() self.remove(x) elif config.renderer == RendererType.OPENGL: self.camera.clear_updaters() except Exception as e: raise ValueError("Invalid ambient rotation angle.") from e def begin_3dillusion_camera_rotation( self, rate: float = 1, origin_phi: float | None = None, origin_theta: float | None = None, ): """ This method creates a 3D camera rotation illusion around the current camera orientation. Parameters ---------- rate The rate at which the camera rotation illusion should operate. origin_phi The polar angle the camera should move around. Defaults to the current phi angle. origin_theta The azimutal angle the camera should move around. Defaults to the current theta angle. """ if origin_theta is None: origin_theta = self.renderer.camera.theta_tracker.get_value() if origin_phi is None: origin_phi = self.renderer.camera.phi_tracker.get_value() val_tracker_theta = ValueTracker(0) def update_theta(m, dt): val_tracker_theta.increment_value(dt * rate) val_for_left_right = 0.2 * np.sin(val_tracker_theta.get_value()) return m.set_value(origin_theta + val_for_left_right) self.renderer.camera.theta_tracker.add_updater(update_theta) self.add(self.renderer.camera.theta_tracker) val_tracker_phi = ValueTracker(0) def update_phi(m, dt): val_tracker_phi.increment_value(dt * rate) val_for_up_down = 0.1 * np.cos(val_tracker_phi.get_value()) - 0.1 return m.set_value(origin_phi + val_for_up_down) self.renderer.camera.phi_tracker.add_updater(update_phi) self.add(self.renderer.camera.phi_tracker) def stop_3dillusion_camera_rotation(self): """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() self.remove(self.renderer.camera.phi_tracker) def move_camera( self, phi: float | None = None, theta: float | None = None, gamma: float | None = None, zoom: float | None = None, focal_distance: float | None = None, frame_center: Mobject | Sequence[float] | None = None, added_anims: Iterable[Animation] = [], **kwargs, ): """ This method animates the movement of the camera to the given spherical coordinates. Parameters ---------- phi The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians. theta The azimuthal angle i.e the angle that spins the camera around the Z_AXIS. focal_distance The radial focal_distance between ORIGIN and Camera. gamma The rotation of the camera about the vector from the ORIGIN to the Camera. zoom The zoom factor of the camera. frame_center The new center of the camera frame in cartesian coordinates. added_anims Any other animations to be played at the same time. """ anims = [] if config.renderer == RendererType.CAIRO: self.camera: ThreeDCamera value_tracker_pairs = [ (phi, self.camera.phi_tracker), (theta, self.camera.theta_tracker), (focal_distance, self.camera.focal_distance_tracker), (gamma, self.camera.gamma_tracker), (zoom, self.camera.zoom_tracker), ] for value, tracker in value_tracker_pairs: if value is not None: anims.append(tracker.animate.set_value(value)) if frame_center is not None: anims.append(self.camera._frame_center.animate.move_to(frame_center)) elif config.renderer == RendererType.OPENGL: cam: OpenGLCamera = self.camera cam2 = cam.copy() methods = { "theta": cam2.set_theta, "phi": cam2.set_phi, "gamma": cam2.set_gamma, "zoom": cam2.scale, "frame_center": cam2.move_to, } if frame_center is not None: if isinstance(frame_center, OpenGLMobject): frame_center = frame_center.get_center() frame_center = list(frame_center) zoom_value = None if zoom is not None: zoom_value = config.frame_height / (zoom * cam.height) for value, method in [ [theta, "theta"], [phi, "phi"], [gamma, "gamma"], [zoom_value, "zoom"], [frame_center, "frame_center"], ]: if value is not None: methods[method](value) if focal_distance is not None: warnings.warn( "focal distance of OpenGLCamera can not be adjusted.", stacklevel=2, ) anims += [Transform(cam, cam2)] self.play(*anims + added_anims, **kwargs) # These lines are added to improve performance. If manim thinks that frame_center is moving, # it is required to redraw every object. These lines remove frame_center from the Scene once # its animation is done, ensuring that manim does not think that it is moving. Since the # frame_center is never actually drawn, this shouldn't break anything. if frame_center is not None and config.renderer == RendererType.CAIRO: self.remove(self.camera._frame_center) def get_moving_mobjects(self, *animations: Animation): """ This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed. Parameters ---------- *animations The animations whose mobjects will be checked. """ moving_mobjects = super().get_moving_mobjects(*animations) camera_mobjects = self.renderer.camera.get_value_trackers() + [ self.renderer.camera._frame_center, ] if any(cm in moving_mobjects for cm in camera_mobjects): return self.mobjects return moving_mobjects def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs): """ This method is used to prevent the rotation and tilting of mobjects as the camera moves around. The mobject can still move in the x,y,z directions, but will always be at the angle (relative to the camera) that it was at when it was passed through this method.) Parameters ---------- *mobjects The Mobject(s) whose orientation must be fixed. **kwargs Some valid kwargs are use_static_center_func : bool center_func : function """ if config.renderer == RendererType.CAIRO: self.add(*mobjects) self.renderer.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs) elif config.renderer == RendererType.OPENGL: for mob in mobjects: mob: OpenGLMobject mob.fix_orientation() self.add(mob) def add_fixed_in_frame_mobjects(self, *mobjects: Mobject): """ This method is used to prevent the rotation and movement of mobjects as the camera moves around. The mobject is essentially overlaid, and is not impacted by the camera's movement in any way. Parameters ---------- *mobjects The Mobjects whose orientation must be fixed. """ if config.renderer == RendererType.CAIRO: self.add(*mobjects) self.camera: ThreeDCamera self.camera.add_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: for mob in mobjects: mob: OpenGLMobject mob.fix_in_frame() self.add(mob) def remove_fixed_orientation_mobjects(self, *mobjects: Mobject): """ This method "unfixes" the orientation of the mobjects passed, meaning they will no longer be at the same angle relative to the camera. This only makes sense if the mobject was passed through add_fixed_orientation_mobjects first. Parameters ---------- *mobjects The Mobjects whose orientation must be unfixed. """ if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_orientation_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: for mob in mobjects: mob: OpenGLMobject mob.unfix_orientation() self.remove(mob) def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject): """ This method undoes what add_fixed_in_frame_mobjects does. It allows the mobject to be affected by the movement of the camera. Parameters ---------- *mobjects The Mobjects whose position and orientation must be unfixed. """ if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: for mob in mobjects: mob: OpenGLMobject mob.unfix_from_frame() self.remove(mob) ## def set_to_default_angled_camera_orientation(self, **kwargs): """ This method sets the default_angled_camera_orientation to the keyword arguments passed, and sets the camera to that orientation. Parameters ---------- **kwargs Some recognised kwargs are phi, theta, focal_distance, gamma, which have the same meaning as the parameters in set_camera_orientation. """ config = dict( self.default_camera_orientation_kwargs, ) # Where doe this come from? config.update(kwargs) self.set_camera_orientation(**config) class SpecialThreeDScene(ThreeDScene): """An extension of :class:`ThreeDScene` with more settings. It has some extra configuration for axes, spheres, and an override for low quality rendering. Further key differences are: * The camera shades applicable 3DMobjects by default, except if rendering in low quality. * Some default params for Spheres and Axes have been added. """ def __init__( self, cut_axes_at_radius=True, camera_config={"should_apply_shading": True, "exponential_projection": True}, three_d_axes_config={ "num_axis_pieces": 1, "axis_config": { "unit_size": 2, "tick_frequency": 1, "numbers_with_elongated_ticks": [0, 1, 2], "stroke_width": 2, }, }, sphere_config={"radius": 2, "resolution": (24, 48)}, default_angled_camera_position={ "phi": 70 * DEGREES, "theta": -110 * DEGREES, }, # When scene is extracted with -l flag, this # configuration will override the above configuration. low_quality_config={ "camera_config": {"should_apply_shading": False}, "three_d_axes_config": {"num_axis_pieces": 1}, "sphere_config": {"resolution": (12, 24)}, }, **kwargs, ): self.cut_axes_at_radius = cut_axes_at_radius self.camera_config = camera_config self.three_d_axes_config = three_d_axes_config self.sphere_config = sphere_config self.default_angled_camera_position = default_angled_camera_position self.low_quality_config = low_quality_config if self.renderer.camera_config["pixel_width"] == config["pixel_width"]: _config = {} else: _config = self.low_quality_config _config = merge_dicts_recursively(_config, kwargs) super().__init__(**_config) def get_axes(self): """Return a set of 3D axes. Returns ------- :class:`.ThreeDAxes` A set of 3D axes. """ axes = ThreeDAxes(**self.three_d_axes_config) for axis in axes: if self.cut_axes_at_radius: p0 = axis.get_start() p1 = axis.number_to_point(-1) p2 = axis.number_to_point(1) p3 = axis.get_end() new_pieces = VGroup(Line(p0, p1), Line(p1, p2), Line(p2, p3)) for piece in new_pieces: piece.shade_in_3d = True new_pieces.match_style(axis.pieces) axis.pieces.submobjects = new_pieces.submobjects for tick in axis.tick_marks: tick.add(VectorizedPoint(1.5 * tick.get_center())) return axes def get_sphere(self, **kwargs): """ Returns a sphere with the passed keyword arguments as properties. Parameters ---------- **kwargs Any valid parameter of :class:`~.Sphere` or :class:`~.Surface`. Returns ------- :class:`~.Sphere` The sphere object. """ config = merge_dicts_recursively(self.sphere_config, kwargs) return Sphere(**config) def get_default_camera_position(self): """ Returns the default_angled_camera position. Returns ------- dict Dictionary of phi, theta, focal_distance, and gamma. """ return self.default_angled_camera_position def set_camera_to_default_position(self): """Sets the camera to its default position.""" self.set_camera_orientation(**self.default_angled_camera_position) ================================================ FILE: manim/scene/vector_space_scene.py ================================================ """A scene suitable for vector spaces.""" from __future__ import annotations __all__ = ["VectorScene", "LinearTransformationScene"] from collections.abc import Callable, Iterable from typing import TYPE_CHECKING, Any, cast import numpy as np from manim.animation.creation import DrawBorderThenFill, Group from manim.camera.camera import Camera from manim.mobject.geometry.arc import Dot from manim.mobject.geometry.line import Arrow, Line, Vector from manim.mobject.geometry.polygram import Rectangle from manim.mobject.graphing.coordinate_systems import Axes, NumberPlane from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.text.tex_mobject import MathTex, Tex from manim.utils.config_ops import update_dict_recursively from .. import config from ..animation.animation import Animation from ..animation.creation import Create, Write from ..animation.fading import FadeOut from ..animation.growing import GrowArrow from ..animation.transform import ApplyFunction, ApplyPointwiseFunction, Transform from ..constants import * from ..mobject.matrix import Matrix from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VGroup, VMobject from ..scene.scene import Scene from ..utils.color import ( BLACK, BLUE_D, GREEN_C, GREY, PURE_YELLOW, RED_C, WHITE, ManimColor, ParsableManimColor, ) from ..utils.rate_functions import rush_from, rush_into from ..utils.space_ops import angle_of_vector if TYPE_CHECKING: from typing import Self from manim.typing import ( MappingFunction, Point3D, Point3DLike, Vector2DLike, Vector3D, Vector3DLike, ) X_COLOR = GREEN_C Y_COLOR = RED_C Z_COLOR = BLUE_D # TODO: Much of this scene type seems dependent on the coordinate system chosen. # That is, being centered at the origin with grid units corresponding to the # arbitrary space units. Change it! # # Also, methods I would have thought of as getters, like coords_to_vector, are # actually doing a lot of animating. class VectorScene(Scene): def __init__(self, basis_vector_stroke_width: float = 6.0, **kwargs: Any) -> None: super().__init__(**kwargs) self.basis_vector_stroke_width = basis_vector_stroke_width def add_plane(self, animate: bool = False, **kwargs: Any) -> NumberPlane: """ Adds a NumberPlane object to the background. Parameters ---------- animate Whether or not to animate the addition of the plane via Create. **kwargs Any valid keyword arguments accepted by NumberPlane. Returns ------- NumberPlane The NumberPlane object. """ plane = NumberPlane(**kwargs) if animate: self.play(Create(plane, lag_ratio=0.5)) self.add(plane) return plane def add_axes( self, animate: bool = False, color: ParsableManimColor | Iterable[ParsableManimColor] = WHITE, ) -> Axes: """ Adds a pair of Axes to the Scene. Parameters ---------- animate Whether or not to animate the addition of the axes through Create. color The color of the axes. Defaults to WHITE. """ axes = Axes(color=color, axis_config={"unit_size": 1}) if animate: self.play(Create(axes)) self.add(axes) return axes def lock_in_faded_grid( self, dimness: float = 0.7, axes_dimness: float = 0.5 ) -> None: """ This method freezes the NumberPlane and Axes that were already in the background, and adds new, manipulatable ones to the foreground. Parameters ---------- dimness The required dimness of the NumberPlane axes_dimness The required dimness of the Axes. """ plane = self.add_plane() axes = plane.get_axes() plane.fade(dimness) axes.set_color(WHITE) axes.fade(axes_dimness) self.add(axes) # TODO # error: Missing positional argument "scene" in call to "update_frame" of "CairoRenderer" [call-arg] self.renderer.update_frame() # type: ignore[call-arg] self.renderer.camera = Camera(self.renderer.get_frame()) self.clear() def get_vector(self, numerical_vector: Vector3DLike, **kwargs: Any) -> Arrow: """ Returns an arrow on the Plane given an input numerical vector. Parameters ---------- numerical_vector The Vector to plot. **kwargs Any valid keyword argument of Arrow. Returns ------- Arrow The Arrow representing the Vector. """ return Arrow( # TODO # error: "VectorScene" has no attribute "plane" [attr-defined] self.plane.coords_to_point(0, 0), # type: ignore[attr-defined] self.plane.coords_to_point(*numerical_vector[:2]), # type: ignore[attr-defined] buff=0, **kwargs, ) def add_vector( self, vector: Arrow | Vector3DLike, color: ParsableManimColor | Iterable[ParsableManimColor] = PURE_YELLOW, animate: bool = True, **kwargs: Any, ) -> Arrow: """ Returns the Vector after adding it to the Plane. Parameters ---------- vector It can be a pre-made graphical vector, or the coordinates of one. color The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW. animate Whether or not to animate the addition of the vector by using GrowArrow **kwargs Any valid keyword argument of Arrow. These are only considered if vector is not an Arrow. Returns ------- Arrow The arrow representing the vector. """ if not isinstance(vector, Arrow): vector = Vector(np.asarray(vector), color=color, **kwargs) if animate: self.play(GrowArrow(vector)) self.add(vector) return vector def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix: """ Returns a column matrix indicating the vector coordinates, after writing them to the screen. Parameters ---------- vector The arrow representing the vector. **kwargs Any valid keyword arguments of :meth:`~.Vector.coordinate_label`: Returns ------- :class:`.Matrix` The column matrix representing the vector. """ coords: Matrix = vector.coordinate_label(**kwargs) self.play(Write(coords)) return coords def get_basis_vectors( self, i_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = X_COLOR, j_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = Y_COLOR, ) -> VGroup: """ Returns a VGroup of the Basis Vectors (1,0) and (0,1) Parameters ---------- i_hat_color The hex colour to use for the basis vector in the x direction j_hat_color The hex colour to use for the basis vector in the y direction Returns ------- VGroup VGroup of the Vector Mobjects representing the basis vectors. """ return VGroup( *( Vector( np.asarray(vect), color=color, stroke_width=self.basis_vector_stroke_width, ) for vect, color in [([1, 0], i_hat_color), ([0, 1], j_hat_color)] ) ) def get_basis_vector_labels(self, **kwargs: Any) -> VGroup: """ Returns naming labels for the basis vectors. Parameters ---------- **kwargs Any valid keyword arguments of get_vector_label: vector, label (str,MathTex) at_tip (bool=False), direction (str="left"), rotate (bool), color (str), label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float), """ i_hat = self.get_basis_vectors().submobjects[0] j_hat = self.get_basis_vectors().submobjects[1] return VGroup( *( self.get_vector_label( vect, label, color=color, label_scale_factor=1, **kwargs ) for vect, label, color in [ # Casting i_hat and j_hat to Vector, as the VGroup from # self.get_basis_vectors() contains two vectors, but the # type checker is currently not aware of that. (cast(Vector, i_hat), "\\hat{\\imath}", X_COLOR), (cast(Vector, j_hat), "\\hat{\\jmath}", Y_COLOR), ] ) ) def get_vector_label( self, vector: Vector, label: MathTex | str, at_tip: bool = False, direction: str = "left", rotate: bool = False, color: ParsableManimColor | None = None, label_scale_factor: float = LARGE_BUFF - 0.2, ) -> MathTex: """ Returns naming labels for the passed vector. Parameters ---------- vector Vector Object for which to get the label. at_tip Whether or not to place the label at the tip of the vector. direction If the label should be on the "left" or right of the vector. rotate Whether or not to rotate it to align it with the vector. color The color to give the label. label_scale_factor How much to scale the label by. Returns ------- MathTex The MathTex of the label. """ if not isinstance(label, MathTex): if len(label) == 1: label = "\\vec{\\textbf{%s}}" % label # noqa: UP031 label = MathTex(label) if color is None: prepared_color: ParsableManimColor = vector.get_color() else: prepared_color = color label.set_color(prepared_color) assert isinstance(label, MathTex) label.scale(label_scale_factor) label.add_background_rectangle() if at_tip: vect = vector.get_vector() vect /= np.linalg.norm(vect) label.next_to(vector.get_end(), vect, buff=SMALL_BUFF) else: angle = vector.get_angle() if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": temp_shift_1: Vector3D = np.asarray(label.get_bottom()) label.shift(-temp_shift_1 + 0.1 * UP) else: temp_shift_2: Vector3D = np.asarray(label.get_top()) label.shift(-temp_shift_2 + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label def label_vector( self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs: Any ) -> MathTex: """ Shortcut method for creating, and animating the addition of a label for the vector. Parameters ---------- vector The vector for which the label must be added. label The MathTex/string of the label. animate Whether or not to animate the labelling w/ Write **kwargs Any valid keyword argument of get_vector_label Returns ------- :class:`~.MathTex` The MathTex of the label. """ mathtex_label = self.get_vector_label(vector, label, **kwargs) if animate: self.play(Write(mathtex_label, run_time=1)) self.add(mathtex_label) return mathtex_label def position_x_coordinate( self, x_coord: MathTex, x_line: Line, vector: Vector3DLike, ) -> MathTex: # TODO Write DocStrings for this. x_coord.next_to(x_line, -np.sign(vector[1]) * UP) x_coord.set_color(X_COLOR) return x_coord def position_y_coordinate( self, y_coord: MathTex, y_line: Line, vector: Vector3DLike, ) -> MathTex: # TODO Write DocStrings for this. y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT) y_coord.set_color(Y_COLOR) return y_coord def coords_to_vector( self, vector: Vector2DLike, coords_start: Point3DLike = 2 * RIGHT + 2 * UP, clean_up: bool = True, ) -> None: """ This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding lines that make up the x and y components of the vector. Then, an Vector() based vector is created between the lines on the Screen. Parameters ---------- vector The vector to show. coords_start The starting point of the location of the label of the vector that shows it numerically. Defaults to 2 * RIGHT + 2 * UP or (2,2) clean_up Whether or not to remove whatever this method did after it's done. """ starting_mobjects = list(self.mobjects) array = Matrix(vector) array.shift(coords_start) arrow = Vector(vector) x_line = Line(ORIGIN, vector[0] * RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.set_color(X_COLOR) y_line.set_color(Y_COLOR) mob_matrix = array.get_mob_matrix() x_coord = mob_matrix[0][0] y_coord = mob_matrix[1][0] self.play(Write(array, run_time=1)) self.wait() self.play( ApplyFunction( lambda x: self.position_x_coordinate(x, x_line, vector), # type: ignore[arg-type] x_coord, ), ) self.play(Create(x_line)) animations = [ ApplyFunction( lambda y: self.position_y_coordinate(y, y_line, vector), # type: ignore[arg-type] y_coord, ), FadeOut(array.get_brackets()), ] self.play(*animations) # TODO: Can we delete the line below? I don't think it have any purpose. # y_coord, _ = (anim.mobject for anim in animations) self.play(Create(y_line)) self.play(Create(arrow)) self.wait() if clean_up: self.clear() self.add(*starting_mobjects) def vector_to_coords( self, vector: Vector3DLike, integer_labels: bool = True, clean_up: bool = True, ) -> tuple[Matrix, Line, Line]: """ This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector. Then, a column matrix (henceforth called the label) is created near the head of the Vector. Parameters ---------- vector The vector to show. integer_labels Whether or not to round the value displayed. in the vector's label to the nearest integer clean_up Whether or not to remove whatever this method did after it's done. """ starting_mobjects = list(self.mobjects) show_creation = False if isinstance(vector, Arrow): arrow = vector vector = arrow.get_end()[:2] else: arrow = Vector(vector) show_creation = True array = arrow.coordinate_label(integer_labels=integer_labels) x_line = Line(ORIGIN, vector[0] * RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.set_color(X_COLOR) y_line.set_color(Y_COLOR) temp = array.get_entries() x_coord = temp.submobjects[0] y_coord = temp.submobjects[1] x_coord_start = self.position_x_coordinate(x_coord.copy(), x_line, vector) y_coord_start = self.position_y_coordinate(y_coord.copy(), y_line, vector) brackets = array.get_brackets() if show_creation: self.play(Create(arrow)) self.play(Create(x_line), Write(x_coord_start), run_time=1) self.play(Create(y_line), Write(y_coord_start), run_time=1) self.wait() self.play( Transform(x_coord_start, x_coord, lag_ratio=0), Transform(y_coord_start, y_coord, lag_ratio=0), Write(brackets, run_time=1), ) self.wait() self.remove(x_coord_start, y_coord_start, brackets) self.add(array) if clean_up: self.clear() self.add(*starting_mobjects) return array, x_line, y_line def show_ghost_movement(self, vector: Arrow | Vector2DLike | Vector3DLike) -> None: """ This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to convey the idea of mentally moving the entire plane in a direction, without actually moving the plane. Parameters ---------- vector The vector which indicates the direction of movement. """ if isinstance(vector, Arrow): vector = vector.get_end() - vector.get_start() else: vector = np.asarray(vector) if len(vector) == 2: vector = np.append(np.array(vector), 0.0) vector_cleaned: Vector3D = vector x_max = int(config["frame_x_radius"] + abs(vector_cleaned[0])) y_max = int(config["frame_y_radius"] + abs(vector_cleaned[1])) # TODO: # I think that this should be a VGroup instead of a VMobject. dots = VMobject( *( # type: ignore[arg-type] Dot(x * RIGHT + y * UP) for x in range(-x_max, x_max) for y in range(-y_max, y_max) ) ) dots.set_fill(BLACK, opacity=0) dots_halfway = dots.copy().shift(vector_cleaned / 2).set_fill(WHITE, 1) dots_end = dots.copy().shift(vector_cleaned) self.play(Transform(dots, dots_halfway, rate_func=rush_into)) self.play(Transform(dots, dots_end, rate_func=rush_from)) self.remove(dots) class LinearTransformationScene(VectorScene): """ This scene contains special methods that make it especially suitable for showing linear transformations. Parameters ---------- include_background_plane Whether or not to include the background plane in the scene. include_foreground_plane Whether or not to include the foreground plane in the scene. background_plane_kwargs Parameters to be passed to :class:`NumberPlane` to adjust the background plane. foreground_plane_kwargs Parameters to be passed to :class:`NumberPlane` to adjust the foreground plane. show_coordinates Whether or not to include the coordinates for the background plane. show_basis_vectors Whether to show the basis x_axis -> ``i_hat`` and y_axis -> ``j_hat`` vectors. basis_vector_stroke_width The ``stroke_width`` of the basis vectors. i_hat_color The color of the ``i_hat`` vector. j_hat_color The color of the ``j_hat`` vector. leave_ghost_vectors Indicates the previous position of the basis vectors following a transformation. Examples ------- .. manim:: LinearTransformationSceneExample class LinearTransformationSceneExample(LinearTransformationScene): def __init__(self, **kwargs): LinearTransformationScene.__init__( self, show_coordinates=True, leave_ghost_vectors=True, **kwargs ) def construct(self): matrix = [[1, 1], [0, 1]] self.apply_matrix(matrix) self.wait() """ def __init__( self, include_background_plane: bool = True, include_foreground_plane: bool = True, background_plane_kwargs: dict[str, Any] | None = None, foreground_plane_kwargs: dict[str, Any] | None = None, show_coordinates: bool = False, show_basis_vectors: bool = True, basis_vector_stroke_width: float = 6, i_hat_color: ParsableManimColor = X_COLOR, j_hat_color: ParsableManimColor = Y_COLOR, leave_ghost_vectors: bool = False, **kwargs: Any, ) -> None: super().__init__(**kwargs) self.include_background_plane = include_background_plane self.include_foreground_plane = include_foreground_plane self.show_coordinates = show_coordinates self.show_basis_vectors = show_basis_vectors self.basis_vector_stroke_width = basis_vector_stroke_width self.i_hat_color = ManimColor(i_hat_color) self.j_hat_color = ManimColor(j_hat_color) self.leave_ghost_vectors = leave_ghost_vectors self.background_plane_kwargs: dict[str, Any] = { "color": GREY, "axis_config": { "color": GREY, }, "background_line_style": { "stroke_color": GREY, "stroke_width": 1, }, } self.ghost_vectors = VGroup() self.foreground_plane_kwargs: dict[str, Any] = { "x_range": np.array([-config["frame_width"], config["frame_width"], 1.0]), "y_range": np.array([-config["frame_width"], config["frame_width"], 1.0]), "faded_line_ratio": 1, } self.update_default_configs( (self.foreground_plane_kwargs, self.background_plane_kwargs), (foreground_plane_kwargs, background_plane_kwargs), ) @staticmethod def update_default_configs( default_configs: Iterable[dict[str, Any]], passed_configs: Iterable[dict[str, Any] | None], ) -> None: for default_config, passed_config in zip( default_configs, passed_configs, strict=False ): if passed_config is not None: update_dict_recursively(default_config, passed_config) def setup(self) -> None: # The has_already_setup attr is to not break all the old Scenes if hasattr(self, "has_already_setup"): return self.has_already_setup = True self.background_mobjects: list[Mobject] = [] self.foreground_mobjects: list[Mobject] = [] self.transformable_mobjects: list[Mobject] = [] self.moving_vectors: list[Mobject] = [] self.transformable_labels: list[MathTex] = [] self.moving_mobjects: list[Mobject] = [] self.background_plane = NumberPlane(**self.background_plane_kwargs) if self.show_coordinates: self.background_plane.add_coordinates() if self.include_background_plane: self.add_background_mobject(self.background_plane) if self.include_foreground_plane: self.plane = NumberPlane(**self.foreground_plane_kwargs) self.add_transformable_mobject(self.plane) if self.show_basis_vectors: self.basis_vectors = self.get_basis_vectors( i_hat_color=self.i_hat_color, j_hat_color=self.j_hat_color, ) self.moving_vectors += list(self.basis_vectors) self.i_hat, self.j_hat = self.basis_vectors self.add(self.basis_vectors) def add_special_mobjects( self, mob_list: list[Mobject], *mobs_to_add: Mobject ) -> None: """ Adds mobjects to a separate list that can be tracked, if these mobjects have some extra importance. Parameters ---------- mob_list The special list to which you want to add these mobjects. *mobs_to_add The mobjects to add. """ for mobject in mobs_to_add: if mobject not in mob_list: mob_list.append(mobject) self.add(mobject) def add_background_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list self.background_mobjects. Parameters ---------- *mobjects The mobjects to add to the list. """ self.add_special_mobjects(self.background_mobjects, *mobjects) # TODO, this conflicts with Scene.add_foreground_mobject # Please be aware that there is also the method Scene.add_foreground_mobjects. def add_foreground_mobject(self, *mobjects: Mobject) -> None: # type: ignore[override] """ Adds the mobjects to the special list self.foreground_mobjects. Parameters ---------- *mobjects The mobjects to add to the list """ self.add_special_mobjects(self.foreground_mobjects, *mobjects) def add_transformable_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list self.transformable_mobjects. Parameters ---------- *mobjects The mobjects to add to the list. """ self.add_special_mobjects(self.transformable_mobjects, *mobjects) def add_moving_mobject( self, mobject: Mobject, target_mobject: Mobject | None = None ) -> None: """ Adds the mobject to the special list self.moving_mobject, and adds a property to the mobject called mobject.target, which keeps track of what the mobject will move to or become etc. Parameters ---------- mobject The mobjects to add to the list target_mobject What the moving_mobject goes to, etc. """ mobject.target = target_mobject self.add_special_mobjects(self.moving_mobjects, mobject) def get_ghost_vectors(self) -> VGroup: """ Returns all ghost vectors ever added to ``self``. Each element is a ``VGroup`` of two ghost vectors. """ return self.ghost_vectors def get_unit_square( self, color: ParsableManimColor | Iterable[ParsableManimColor] = PURE_YELLOW, opacity: float = 0.3, stroke_width: float = 3, ) -> Rectangle: """ Returns a unit square for the current NumberPlane. Parameters ---------- color The string of the hex color code of the color wanted. opacity The opacity of the square stroke_width The stroke_width in pixels of the border of the square Returns ------- Square """ square = self.square = Rectangle( color=color, width=self.plane.get_x_unit_size(), height=self.plane.get_y_unit_size(), stroke_color=color, stroke_width=stroke_width, fill_color=color, fill_opacity=opacity, ) square.move_to(self.plane.coords_to_point(0, 0), DL) return square def add_unit_square(self, animate: bool = False, **kwargs: Any) -> Self: """ Adds a unit square to the scene via self.get_unit_square. Parameters ---------- animate Whether or not to animate the addition with DrawBorderThenFill. **kwargs Any valid keyword arguments of self.get_unit_square() Returns ------- Square The unit square. """ square = self.get_unit_square(**kwargs) if animate: self.play( DrawBorderThenFill(square), Animation(Group(*self.moving_vectors)), ) self.add_transformable_mobject(square) self.bring_to_front(*self.moving_vectors) self.square = square return self def add_vector( self, vector: Arrow | list | tuple | np.ndarray, color: ParsableManimColor = PURE_YELLOW, animate: bool = False, **kwargs: Any, ) -> Arrow: """ Adds a vector to the scene, and puts it in the special list self.moving_vectors. Parameters ---------- vector It can be a pre-made graphical vector, or the coordinates of one. color The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW. **kwargs Any valid keyword argument of VectorScene.add_vector. Returns ------- Arrow The arrow representing the vector. """ vector = super().add_vector(vector, color=color, animate=animate, **kwargs) self.moving_vectors.append(vector) return vector def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix: """ Returns a column matrix indicating the vector coordinates, after writing them to the screen, and adding them to the special list self.foreground_mobjects Parameters ---------- vector The arrow representing the vector. **kwargs Any valid keyword arguments of VectorScene.write_vector_coordinates Returns ------- Matrix The column matrix representing the vector. """ coords = super().write_vector_coordinates(vector, **kwargs) self.add_foreground_mobject(coords) return coords def add_transformable_label( self, vector: Vector, label: MathTex | str, transformation_name: str | MathTex = "L", new_label: str | MathTex | None = None, **kwargs: Any, ) -> MathTex: """ Method for creating, and animating the addition of a transformable label for the vector. Parameters ---------- vector The vector for which the label must be added. label The MathTex/string of the label. transformation_name The name to give the transformation as a label. new_label What the label should display after a Linear Transformation **kwargs Any valid keyword argument of get_vector_label Returns ------- :class:`~.MathTex` The MathTex of the label. """ # TODO: Clear up types in this function. This is currently a mess. label_mob = self.label_vector(vector, label, **kwargs) if new_label: label_mob.target_text = new_label # type: ignore[attr-defined] else: label_mob.target_text = ( # type: ignore[attr-defined] f"{transformation_name}({label_mob.get_tex_string()})" ) label_mob.vector = vector # type: ignore[attr-defined] label_mob.kwargs = kwargs # type: ignore[attr-defined] if "animate" in label_mob.kwargs: label_mob.kwargs.pop("animate") self.transformable_labels.append(label_mob) return cast(MathTex, label_mob) def add_title( self, title: str | MathTex | Tex, scale_factor: float = 1.5, animate: bool = False, ) -> Self: """ Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding it as a local variable of self. Returns the Scene. Parameters ---------- title What the title should be. scale_factor How much the title should be scaled by. animate Whether or not to animate the addition. Returns ------- LinearTransformationScene The scene with the title added to it. """ if not isinstance(title, (Mobject, OpenGLMobject)): title = Tex(title).scale(scale_factor) title.to_edge(UP) title.add_background_rectangle() if animate: self.play(Write(title)) self.add_foreground_mobject(title) self.title = title return self def get_matrix_transformation( self, matrix: np.ndarray | list | tuple ) -> Callable[[Point3D], Point3D]: """ Returns a function corresponding to the linear transformation represented by the matrix passed. Parameters ---------- matrix The matrix. """ return self.get_transposed_matrix_transformation(np.array(matrix).T) def get_transposed_matrix_transformation( self, transposed_matrix: np.ndarray | list | tuple ) -> Callable[[Point3D], Point3D]: """ Returns a function corresponding to the linear transformation represented by the transposed matrix passed. Parameters ---------- transposed_matrix The matrix. """ transposed_matrix = np.array(transposed_matrix) if transposed_matrix.shape == (2, 2): new_matrix = np.identity(3) new_matrix[:2, :2] = transposed_matrix transposed_matrix = new_matrix elif transposed_matrix.shape != (3, 3): raise ValueError("Matrix has bad dimensions") return lambda point: np.dot(point, transposed_matrix) def get_piece_movement(self, pieces: Iterable[Mobject]) -> Transform: """ This method returns an animation that moves an arbitrary mobject in "pieces" to its corresponding .target value. If self.leave_ghost_vectors is True, ghosts of the original positions/mobjects are left on screen Parameters ---------- pieces The pieces for which the movement must be shown. Returns ------- 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)) # don't add empty VGroups if self.leave_ghost_vectors and start.submobjects: # start.copy() gives a VGroup of Vectors self.ghost_vectors.add(start.copy().fade(0.7)) self.add(self.ghost_vectors[-1]) return Transform(start, target, lag_ratio=0) def get_moving_mobject_movement(self, func: MappingFunction) -> Transform: """ This method returns an animation that moves a mobject in "self.moving_mobjects" to its corresponding .target value. func is a function that determines where the .target goes. Parameters ---------- func The function that determines where the .target of the moving mobject goes. Returns ------- Animation The animation of the movement. """ for m in self.moving_mobjects: if m.target is None: m.target = m.copy() temp: Point3D = m.get_center() target_point = func(temp) m.target.move_to(target_point) return self.get_piece_movement(self.moving_mobjects) def get_vector_movement(self, func: MappingFunction) -> Transform: """ This method returns an animation that moves a mobject in "self.moving_vectors" to its corresponding .target value. func is a function that determines where the .target goes. Parameters ---------- func The function that determines where the .target of the moving mobject goes. Returns ------- Animation The animation of the movement. """ for v in self.moving_vectors: v.target = Vector(func(v.get_end()), color=v.get_color()) norm = float(np.linalg.norm(v.target.get_end())) if norm < 0.1: v.target.get_tip().scale(norm) return self.get_piece_movement(self.moving_vectors) def get_transformable_label_movement(self) -> Transform: """ This method returns an animation that moves all labels in "self.transformable_labels" to its corresponding .target . Returns ------- Animation The animation of the movement. """ for label in self.transformable_labels: # TODO: This location and lines 933 and 335 are the only locations in # the code where the target_text property is referenced. target_text: MathTex | str = label.target_text # type: ignore[assignment] label.target = self.get_vector_label( label.vector.target, # type: ignore[attr-defined] target_text, **label.kwargs, # type: ignore[arg-type] ) return self.get_piece_movement(self.transformable_labels) def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None: """ Applies the transformation represented by the given matrix to the number plane, and each vector/similar mobject on it. Parameters ---------- matrix The matrix. **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: Any) -> None: """ This method applies the linear transformation represented by the inverse of the passed matrix to the number plane, and each vector/similar mobject on it. Parameters ---------- matrix The matrix whose inverse is to be applied. **kwargs Any valid keyword argument of self.apply_matrix() """ self.apply_matrix(np.linalg.inv(matrix), **kwargs) def apply_transposed_matrix( self, transposed_matrix: np.ndarray | list | tuple, **kwargs: Any ) -> None: """ Applies the transformation represented by the given transposed matrix to the number plane, and each vector/similar mobject on it. Parameters ---------- transposed_matrix The matrix. **kwargs Any valid keyword argument of self.apply_function() """ func = self.get_transposed_matrix_transformation(transposed_matrix) if "path_arc" not in kwargs: net_rotation = np.mean( [angle_of_vector(func(RIGHT)), angle_of_vector(func(UP)) - np.pi / 2], ) kwargs["path_arc"] = net_rotation self.apply_function(func, **kwargs) def apply_inverse_transpose( self, t_matrix: np.ndarray | list | tuple, **kwargs: Any ) -> None: """ Applies the inverse of the transformation represented by the given transposed matrix to the number plane and each vector/similar mobject on it. Parameters ---------- t_matrix The matrix. **kwargs Any valid keyword argument of self.apply_transposed_matrix() """ t_inv = np.linalg.inv(np.array(t_matrix).T).T self.apply_transposed_matrix(t_inv, **kwargs) def apply_nonlinear_transformation( self, function: Callable[[np.ndarray], np.ndarray], **kwargs: Any ) -> None: """ Applies the non-linear transformation represented by the given function to the number plane and each vector/similar mobject on it. Parameters ---------- function The function. **kwargs Any valid keyword argument of self.apply_function() """ self.plane.prepare_for_nonlinear_transform() self.apply_function(function, **kwargs) def apply_function( self, function: MappingFunction, added_anims: list[Animation] = [], **kwargs: Any, ) -> None: """ Applies the given function to each of the mobjects in self.transformable_mobjects, and plays the animation showing this. Parameters ---------- function The function that affects each point of each mobject in self.transformable_mobjects. added_anims Any other animations that need to be played simultaneously with this. **kwargs Any valid keyword argument of a self.play() call. """ if "run_time" not in kwargs: kwargs["run_time"] = 3 anims = ( [ ApplyPointwiseFunction(function, t_mob) # type: ignore[arg-type] for t_mob in self.transformable_mobjects ] + [ self.get_vector_movement(function), self.get_transformable_label_movement(), self.get_moving_mobject_movement(function), ] + [Animation(f_mob) for f_mob in self.foreground_mobjects] + added_anims ) self.play(*anims, **kwargs) ================================================ FILE: manim/scene/zoomed_scene.py ================================================ """A scene supporting zooming in on a specified section. Examples -------- .. manim:: UseZoomedScene class UseZoomedScene(ZoomedScene): def construct(self): dot = Dot().set_color(GREEN) self.add(dot) self.wait(1) self.activate_zooming(animate=False) self.wait(1) self.play(dot.animate.shift(LEFT)) .. manim:: ChangingZoomScale class ChangingZoomScale(ZoomedScene): def __init__(self, **kwargs): ZoomedScene.__init__( self, zoom_factor=0.3, zoomed_display_height=1, zoomed_display_width=3, image_frame_stroke_width=20, zoomed_camera_config={ "default_frame_stroke_width": 3, }, **kwargs ) def construct(self): dot = Dot().set_color(GREEN) sq = Circle(fill_opacity=1, radius=0.2).next_to(dot, RIGHT) self.add(dot, sq) self.wait(1) self.activate_zooming(animate=False) self.wait(1) self.play(dot.animate.shift(LEFT * 0.3)) self.play(self.zoomed_camera.frame.animate.scale(4)) self.play(self.zoomed_camera.frame.animate.shift(0.5 * DOWN)) """ from __future__ import annotations __all__ = ["ZoomedScene"] from typing import TYPE_CHECKING, Any from ..animation.transform import ApplyMethod from ..camera.camera import Camera from ..camera.moving_camera import MovingCamera from ..camera.multi_camera import MultiCamera from ..constants import * from ..mobject.types.image_mobject import ImageMobjectFromCamera from ..renderer.opengl_renderer import OpenGLCamera from ..scene.moving_camera_scene import MovingCameraScene if TYPE_CHECKING: from manim.typing import Point3DLike, Vector3D # Note, any scenes from old videos using ZoomedScene will almost certainly # break, as it was restructured. class ZoomedScene(MovingCameraScene): """This is a Scene with special configurations made for when a particular part of the scene must be zoomed in on and displayed separately. """ def __init__( self, camera_class: type[Camera] = MultiCamera, zoomed_display_height: float = 3, zoomed_display_width: float = 3, zoomed_display_center: Point3DLike | None = None, zoomed_display_corner: Vector3D = UP + RIGHT, zoomed_display_corner_buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER, zoomed_camera_config: dict[str, Any] = { "default_frame_stroke_width": 2, "background_opacity": 1, }, zoomed_camera_image_mobject_config: dict[str, Any] = {}, zoomed_camera_frame_starting_position: Point3DLike = ORIGIN, zoom_factor: float = 0.15, image_frame_stroke_width: float = 3, zoom_activated: bool = False, **kwargs: Any, ) -> None: self.zoomed_display_height = zoomed_display_height self.zoomed_display_width = zoomed_display_width self.zoomed_display_center = zoomed_display_center self.zoomed_display_corner = zoomed_display_corner self.zoomed_display_corner_buff = zoomed_display_corner_buff self.zoomed_camera_config = zoomed_camera_config self.zoomed_camera_image_mobject_config = zoomed_camera_image_mobject_config self.zoomed_camera_frame_starting_position = ( zoomed_camera_frame_starting_position ) self.zoom_factor = zoom_factor self.image_frame_stroke_width = image_frame_stroke_width self.zoom_activated = zoom_activated super().__init__(camera_class=camera_class, **kwargs) def setup(self) -> None: """This method is used internally by Manim to setup the scene for proper use. """ super().setup() # Initialize camera and display zoomed_camera = MovingCamera(**self.zoomed_camera_config) zoomed_display = ImageMobjectFromCamera( zoomed_camera, **self.zoomed_camera_image_mobject_config ) zoomed_display.add_display_frame() for mob in zoomed_camera.frame, zoomed_display: mob.stretch_to_fit_height(self.zoomed_display_height) mob.stretch_to_fit_width(self.zoomed_display_width) zoomed_camera.frame.scale(self.zoom_factor) # Position camera and display zoomed_camera.frame.move_to(self.zoomed_camera_frame_starting_position) if self.zoomed_display_center is not None: zoomed_display.move_to(self.zoomed_display_center) else: zoomed_display.to_corner( self.zoomed_display_corner, buff=self.zoomed_display_corner_buff, ) self.zoomed_camera = zoomed_camera self.zoomed_display = zoomed_display def activate_zooming(self, animate: bool = False) -> None: """This method is used to activate the zooming for the zoomed_camera. Parameters ---------- animate Whether or not to animate the activation of the zoomed camera. """ self.zoom_activated = True self.renderer.camera.add_image_mobject_from_camera(self.zoomed_display) # type: ignore[union-attr] if animate: self.play(self.get_zoom_in_animation()) self.play(self.get_zoomed_display_pop_out_animation()) self.add_foreground_mobjects( self.zoomed_camera.frame, self.zoomed_display, ) def get_zoom_in_animation(self, run_time: float = 2, **kwargs: Any) -> ApplyMethod: """Returns the animation of camera zooming in. Parameters ---------- run_time The run_time of the animation of the camera zooming in. **kwargs Any valid keyword arguments of ApplyMethod() Returns ------- ApplyMethod The animation of the camera zooming in. """ frame = self.zoomed_camera.frame if isinstance(self.camera, OpenGLCamera): full_frame_width, full_frame_height = self.camera.frame_shape else: full_frame_height = self.camera.frame_height full_frame_width = self.camera.frame_width frame.save_state() frame.stretch_to_fit_width(full_frame_width) frame.stretch_to_fit_height(full_frame_height) frame.center() frame.set_stroke(width=0) return ApplyMethod(frame.restore, run_time=run_time, **kwargs) def get_zoomed_display_pop_out_animation(self, **kwargs: Any) -> ApplyMethod: """This is the animation of the popping out of the mini-display that shows the content of the zoomed camera. Returns ------- ApplyMethod The Animation of the Zoomed Display popping out. """ display = self.zoomed_display display.save_state() display.replace(self.zoomed_camera.frame, stretch=True) return ApplyMethod(display.restore) def get_zoom_factor(self) -> float: """Returns the Zoom factor of the Zoomed camera. Defined as the ratio between the height of the zoomed camera and the height of the zoomed mini display. Returns ------- float The zoom factor. """ zoom_factor: float = ( self.zoomed_camera.frame.height / self.zoomed_display.height ) return zoom_factor ================================================ FILE: manim/templates/Axes.mtp ================================================ class AxesTemplate(Scene): def construct(self): graph = Axes( x_range=[-1,10,1], y_range=[-1,10,1], x_length=9, y_length=6, axis_config={"include_tip":False} ) labels = graph.get_axis_labels() self.add(graph, labels) ================================================ FILE: manim/templates/Default.mtp ================================================ class DefaultTemplate(Scene): def construct(self): circle = Circle() # create a circle circle.set_fill(PINK, opacity=0.5) # set color and transparency square = Square() # create a square square.flip(RIGHT) # flip horizontally square.rotate(-3 * TAU / 8) # rotate a certain amount self.play(Create(square)) # animate the creation of the square self.play(Transform(square, circle)) # interpolate the square into the circle self.play(FadeOut(square)) # fade out animation ================================================ FILE: manim/templates/MovingCamera.mtp ================================================ class MovingCameraTemplate(MovingCameraScene): def construct(self): text = Text("Hello World").set_color(BLUE) self.add(text) self.camera.frame.save_state() self.play(self.camera.frame.animate.set(width=text.width * 1.2)) self.wait(0.3) self.play(Restore(self.camera.frame)) ================================================ FILE: manim/templates/template.cfg ================================================ [CLI] frame_rate = 30 pixel_height = 480 pixel_width = 854 background_color = BLACK background_opacity = 1 scene_names = DefaultScene ================================================ FILE: manim/typing.py ================================================ """Custom type definitions used in Manim. .. admonition:: Note for developers :class: important Around the source code there are multiple strings which look like this: .. code-block:: ''' [CATEGORY] ''' All type aliases defined under those strings will be automatically classified under that category. If you need to define a new category, respect the format described above. """ from __future__ import annotations from collections.abc import Callable, Sequence from os import PathLike from typing import TypeAlias import numpy as np import numpy.typing as npt __all__ = [ "ManimFloat", "ManimInt", "ManimColorDType", "FloatRGB", "FloatRGBLike", "FloatRGB_Array", "FloatRGBLike_Array", "IntRGB", "IntRGBLike", "FloatRGBA", "FloatRGBALike", "FloatRGBA_Array", "FloatRGBALike_Array", "IntRGBA", "IntRGBALike", "FloatHSV", "FloatHSVLike", "FloatHSL", "FloatHSLLike", "FloatHSVA", "FloatHSVALike", "ManimColorInternal", "PointDType", "Point2D", "Point2DLike", "Point2D_Array", "Point2DLike_Array", "Point3D", "Point3DLike", "Point3D_Array", "Point3DLike_Array", "PointND", "PointNDLike", "PointND_Array", "PointNDLike_Array", "Vector2D", "Vector2DLike", "Vector2D_Array", "Vector2DLike_Array", "Vector3D", "Vector3DLike", "Vector3D_Array", "Vector3DLike_Array", "VectorND", "VectorNDLike", "VectorND_Array", "VectorNDLike_Array", "RowVector", "ColVector", "MatrixMN", "Zeros", "QuadraticBezierPoints", "QuadraticBezierPointsLike", "QuadraticBezierPoints_Array", "QuadraticBezierPointsLike_Array", "QuadraticBezierPath", "QuadraticBezierPathLike", "QuadraticSpline", "QuadraticSplineLike", "CubicBezierPoints", "CubicBezierPointsLike", "CubicBezierPoints_Array", "CubicBezierPointsLike_Array", "CubicBezierPath", "CubicBezierPathLike", "CubicSpline", "CubicSplineLike", "BezierPoints", "BezierPointsLike", "BezierPoints_Array", "BezierPointsLike_Array", "BezierPath", "BezierPathLike", "Spline", "SplineLike", "FlatBezierPoints", "FunctionOverride", "PathFuncType", "MappingFunction", "MultiMappingFunction", "PixelArray", "GrayscalePixelArray", "RGBPixelArray", "RGBAPixelArray", "StrPath", "StrOrBytesPath", ] """ [CATEGORY] Primitive data types """ ManimFloat: TypeAlias = np.float64 """A double-precision floating-point value (64 bits, or 8 bytes), according to the IEEE 754 standard. """ ManimInt: TypeAlias = np.int64 r"""A long integer (64 bits, or 8 bytes). It can take values between :math:`-2^{63}` and :math:`+2^{63} - 1`, which expressed in base 10 is a range between around :math:`-9.223 \cdot 10^{18}` and :math:`+9.223 \cdot 10^{18}`. """ """ [CATEGORY] Color types """ ManimColorDType: TypeAlias = ManimFloat """Data type used in :class:`~.ManimColorInternal`: a double-precision float between 0 and 1. """ FloatRGB: TypeAlias = npt.NDArray[ManimColorDType] """``shape: (3,)`` A :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a color in RGB format. Its components describe, in order, the intensity of Red, Green, and Blue in the represented color. """ FloatRGBLike: TypeAlias = FloatRGB | tuple[float, float, float] """``shape: (3,)`` An array of 3 floats between 0 and 1, representing a color in RGB format. This represents anything which can be converted to a :class:`.FloatRGB` NumPy array. """ FloatRGB_Array: TypeAlias = npt.NDArray[ManimColorDType] """``shape: (M, 3)`` A :class:`numpy.ndarray` of many rows of 3 floats representing RGB colors. """ FloatRGBLike_Array: TypeAlias = FloatRGB_Array | Sequence[FloatRGBLike] """``shape: (M, 3)`` An array of many rows of 3 floats representing RGB colors. This represents anything which can be converted to a :class:`.FloatRGB_Array` NumPy array. """ IntRGB: TypeAlias = npt.NDArray[ManimInt] """``shape: (3,)`` A :class:`numpy.ndarray` of 3 integers between 0 and 255, representing a color in RGB format. Its components describe, in order, the intensity of Red, Green, and Blue in the represented color. """ IntRGBLike: TypeAlias = IntRGB | tuple[int, int, int] """``shape: (3,)`` An array of 3 integers between 0 and 255, representing a color in RGB format. This represents anything which can be converted to an :class:`.IntRGB` NumPy array. """ FloatRGBA: TypeAlias = npt.NDArray[ManimColorDType] """``shape: (4,)`` A :class:`numpy.ndarray` of 4 floats between 0 and 1, representing a color in RGBA format. Its components describe, in order, the intensity of Red, Green, Blue and Alpha (opacity) in the represented color. """ FloatRGBALike: TypeAlias = FloatRGBA | tuple[float, float, float, float] """``shape: (4,)`` An array of 4 floats between 0 and 1, representing a color in RGBA format. This represents anything which can be converted to a :class:`.FloatRGBA` NumPy array. """ FloatRGBA_Array: TypeAlias = npt.NDArray[ManimColorDType] """``shape: (M, 4)`` A :class:`numpy.ndarray` of many rows of 4 floats representing RGBA colors. """ FloatRGBALike_Array: TypeAlias = FloatRGBA_Array | Sequence[FloatRGBALike] """``shape: (M, 4)`` An array of many rows of 4 floats representing RGBA colors. This represents anything which can be converted to a :class:`.FloatRGBA_Array` NumPy array. """ IntRGBA: TypeAlias = npt.NDArray[ManimInt] """``shape: (4,)`` A :class:`numpy.ndarray` of 4 integers between 0 and 255, representing a color in RGBA format. Its components describe, in order, the intensity of Red, Green, Blue and Alpha (opacity) in the represented color. """ IntRGBALike: TypeAlias = IntRGBA | tuple[int, int, int, int] """``shape: (4,)`` An array of 4 integers between 0 and 255, representing a color in RGBA format. This represents anything which can be converted to an :class:`.IntRGBA` NumPy array. """ FloatHSV: TypeAlias = FloatRGB """``shape: (3,)`` A :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a color in HSV (or HSB) format. Its components describe, in order, the Hue, Saturation and Value (or Brightness) in the represented color. """ FloatHSVLike: TypeAlias = FloatRGBLike """``shape: (3,)`` An array of 3 floats between 0 and 1, representing a color in HSV (or HSB) format. This represents anything which can be converted to a :class:`.FloatHSV` NumPy array. """ FloatHSVA: TypeAlias = FloatRGBA """``shape: (4,)`` A :class:`numpy.ndarray` of 4 floats between 0 and 1, representing a color in HSVA (or HSBA) format. Its components describe, in order, the Hue, Saturation and Value (or Brightness) in the represented color. """ FloatHSVALike: TypeAlias = FloatRGBALike """``shape: (4,)`` An array of 4 floats between 0 and 1, representing a color in HSVA (or HSBA) format. This represents anything which can be converted to a :class:`.FloatHSVA` NumPy array. """ FloatHSL: TypeAlias = FloatRGB """``shape: (3,)`` A :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a color in HSL format. Its components describe, in order, the Hue, Saturation and Lightness in the represented color. """ FloatHSLLike: TypeAlias = FloatRGBLike """``shape: (3,)`` An array of 3 floats between 0 and 1, representing a color in HSL format. This represents anything which can be converted to a :class:`.FloatHSL` NumPy array. """ ManimColorInternal: TypeAlias = FloatRGBA """``shape: (4,)`` Internal color representation used by :class:`~.ManimColor`, following the RGBA format. It is a :class:`numpy.ndarray` consisting of 4 floats between 0 and 1, describing respectively the intensities of Red, Green, Blue and Alpha (opacity) in the represented color. """ """ [CATEGORY] Point types """ PointDType: TypeAlias = ManimFloat """Default type for arrays representing points: a double-precision floating point value. """ Point2D: TypeAlias = npt.NDArray[PointDType] """``shape: (2,)`` A NumPy array representing a 2-dimensional point: ``[float, float]``. """ Point2DLike: TypeAlias = Point2D | tuple[float, float] """``shape: (2,)`` A 2-dimensional point: ``[float, float]``. This represents anything which can be converted to a :class:`.Point2D` NumPy array. """ Point2D_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (M, 2)`` A NumPy array representing a sequence of :class:`.Point2D` objects: ``[[float, float], ...]``. """ Point2DLike_Array: TypeAlias = Point2D_Array | Sequence[Point2DLike] """``shape: (M, 2)`` An array of :class:`.Point2DLike` objects: ``[[float, float], ...]``. This represents anything which can be converted to a :class:`.Point2D_Array` NumPy array. Please refer to the documentation of the function you are using for further type information. """ Point3D: TypeAlias = npt.NDArray[PointDType] """``shape: (3,)`` A NumPy array representing a 3-dimensional point: ``[float, float, float]``. """ Point3DLike: TypeAlias = Point3D | tuple[float, float, float] """``shape: (3,)`` A 3-dimensional point: ``[float, float, float]``. This represents anything which can be converted to a :class:`.Point3D` NumPy array. """ Point3D_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (M, 3)`` A NumPy array representing a sequence of :class:`.Point3D` objects: ``[[float, float, float], ...]``. """ Point3DLike_Array: TypeAlias = Point3D_Array | Sequence[Point3DLike] """``shape: (M, 3)`` An array of :class:`.Point3DLike` objects: ``[[float, float, float], ...]``. This represents anything which can be converted to a :class:`.Point3D_Array` NumPy array. Please refer to the documentation of the function you are using for further type information. """ PointND: TypeAlias = npt.NDArray[PointDType] """``shape: (N,)`` A NumPy array representing an N-dimensional point: ``[float, ...]``. """ PointNDLike: TypeAlias = PointND | Sequence[float] """``shape: (N,)`` An N-dimensional point: ``[float, ...]``. This represents anything which can be converted to a :class:`.PointND` NumPy array. """ PointND_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (M, N)`` A NumPy array representing a sequence of :class:`.PointND` objects: ``[[float, ...], ...]``. """ PointNDLike_Array: TypeAlias = PointND_Array | Sequence[PointNDLike] """``shape: (M, N)`` An array of :class:`.PointNDLike` objects: ``[[float, ...], ...]``. This represents anything which can be converted to a :class:`.PointND_Array` NumPy array. Please refer to the documentation of the function you are using for further type information. """ """ [CATEGORY] Vector types """ Vector2D: TypeAlias = npt.NDArray[PointDType] """``shape: (2,)`` A NumPy array representing a 2-dimensional vector: ``[float, float]``. .. caution:: Do not confuse with the :class:`~.Vector` or :class:`~.Arrow` VMobjects! """ Vector2DLike: TypeAlias = npt.NDArray[PointDType] | tuple[float, float] """``shape: (2,)`` A 2-dimensional vector: ``[float, float]``. This represents anything which can be converted to a :class:`.Vector2D` NumPy array. .. caution:: Do not confuse with the :class:`~.Vector` or :class:`~.Arrow` VMobjects! """ Vector2D_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (M, 2)`` A NumPy array representing a sequence of :class:`.Vector2D` objects: ``[[float, float], ...]``. """ Vector2DLike_Array: TypeAlias = Vector2D_Array | Sequence[Vector2DLike] """``shape: (M, 2)`` An array of :class:`.Vector2DLike` objects: ``[[float, float], ...]``. This represents anything which can be converted to a :class:`.Vector2D_Array` NumPy array. """ Vector3D: TypeAlias = npt.NDArray[PointDType] """``shape: (3,)`` A NumPy array representing a 3-dimensional vector: ``[float, float, float]``. .. caution:: Do not confuse with the :class:`~.Vector` or :class:`~.Arrow3D` VMobjects! """ Vector3DLike: TypeAlias = npt.NDArray[PointDType] | tuple[float, float, float] """``shape: (3,)`` A 3-dimensional vector: ``[float, float, float]``. This represents anything which can be converted to a :class:`.Vector3D` NumPy array. .. caution:: Do not confuse with the :class:`~.Vector` or :class:`~.Arrow3D` VMobjects! """ Vector3D_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (M, 3)`` An NumPy array representing a sequence of :class:`.Vector3D` objects: ``[[float, float, float], ...]``. """ Vector3DLike_Array: TypeAlias = npt.NDArray[PointDType] | Sequence[Vector3DLike] """``shape: (M, 3)`` An array of :class:`.Vector3DLike` objects: ``[[float, float, float], ...]``. This represents anything which can be converted to a :class:`.Vector3D_Array` NumPy array. """ VectorND: TypeAlias = npt.NDArray[PointDType] """``shape (N,)`` A NumPy array representing an :math:`N`-dimensional vector: ``[float, ...]``. .. caution:: Do not confuse with the :class:`~.Vector` VMobject! This type alias is named "VectorND" instead of "Vector" to avoid potential name collisions. """ VectorNDLike: TypeAlias = npt.NDArray[PointDType] | Sequence[float] """``shape (N,)`` An :math:`N`-dimensional vector: ``[float, ...]``. This represents anything which can be converted to a :class:`.VectorND` NumPy array. .. caution:: Do not confuse with the :class:`~.Vector` VMobject! This type alias is named "VectorND" instead of "Vector" to avoid potential name collisions. """ VectorND_Array: TypeAlias = npt.NDArray[PointDType] """``shape (M, N)`` A NumPy array representing a sequence of :class:`.VectorND` objects: ``[[float, ...], ...]``. """ VectorNDLike_Array: TypeAlias = npt.NDArray[PointDType] | Sequence[VectorNDLike] """``shape (M, N)`` An array of :class:`.VectorNDLike` objects: ``[[float, ...], ...]``. This represents anything which can be converted to a :class:`.VectorND_Array` NumPy array. """ RowVector: TypeAlias = npt.NDArray[PointDType] """``shape: (1, N)`` A row vector: ``[[float, ...]]``. """ ColVector: TypeAlias = npt.NDArray[PointDType] """``shape: (N, 1)`` A column vector: ``[[float], [float], ...]``. """ """ [CATEGORY] Matrix types """ MatrixMN: TypeAlias = npt.NDArray[PointDType] """``shape: (M, N)`` A matrix: ``[[float, ...], [float, ...], ...]``. """ Zeros: TypeAlias = MatrixMN """``shape: (M, N)`` A :class:`.MatrixMN` filled with zeros, typically created with ``numpy.zeros((M, N))``. """ """ [CATEGORY] Bézier types """ QuadraticBezierPoints: TypeAlias = Point3D_Array """``shape: (3, 3)`` A :class:`.Point3D_Array` of three 3D control points for a single quadratic Bézier curve: ``[[float, float, float], [float, float, float], [float, float, float]]``. """ QuadraticBezierPointsLike: TypeAlias = ( QuadraticBezierPoints | tuple[Point3DLike, Point3DLike, Point3DLike] ) """``shape: (3, 3)`` A :class:`.Point3DLike_Array` of three 3D control points for a single quadratic Bézier curve: ``[[float, float, float], [float, float, float], [float, float, float]]``. This represents anything which can be converted to a :class:`.QuadraticBezierPoints` NumPy array. """ QuadraticBezierPoints_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (N, 3, 3)`` A NumPy array containing :math:`N` :class:`.QuadraticBezierPoints` objects: ``[[[float, float, float], [float, float, float], [float, float, float]], ...]``. """ QuadraticBezierPointsLike_Array: TypeAlias = ( QuadraticBezierPoints_Array | Sequence[QuadraticBezierPointsLike] ) """``shape: (N, 3, 3)`` A sequence of :math:`N` :class:`.QuadraticBezierPointsLike` objects: ``[[[float, float, float], [float, float, float], [float, float, float]], ...]``. This represents anything which can be converted to a :class:`.QuadraticBezierPoints_Array` NumPy array. """ QuadraticBezierPath: TypeAlias = Point3D_Array """``shape: (3*N, 3)`` A :class:`.Point3D_Array` of :math:`3N` points, where each one of the :math:`N` consecutive blocks of 3 points represents a quadratic Bézier curve: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ QuadraticBezierPathLike: TypeAlias = Point3DLike_Array """``shape: (3*N, 3)`` A :class:`.Point3DLike_Array` of :math:`3N` points, where each one of the :math:`N` consecutive blocks of 3 points represents a quadratic Bézier curve: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.QuadraticBezierPath` NumPy array. Please refer to the documentation of the function you are using for further type information. """ QuadraticSpline: TypeAlias = QuadraticBezierPath """``shape: (3*N, 3)`` A special case of :class:`.QuadraticBezierPath` where all the :math:`N` quadratic Bézier curves are connected, forming a quadratic spline: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ QuadraticSplineLike: TypeAlias = QuadraticBezierPathLike """``shape: (3*N, 3)`` A special case of :class:`.QuadraticBezierPathLike` where all the :math:`N` quadratic Bézier curves are connected, forming a quadratic spline: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.QuadraticSpline` NumPy array. Please refer to the documentation of the function you are using for further type information. """ CubicBezierPoints: TypeAlias = Point3D_Array """``shape: (4, 3)`` A :class:`.Point3D_Array` of four 3D control points for a single cubic Bézier curve: ``[[float, float, float], [float, float, float], [float, float, float], [float, float, float]]``. """ CubicBezierPointsLike: TypeAlias = ( CubicBezierPoints | tuple[Point3DLike, Point3DLike, Point3DLike, Point3DLike] ) """``shape: (4, 3)`` A :class:`.Point3DLike_Array` of 4 control points for a single cubic Bézier curve: ``[[float, float, float], [float, float, float], [float, float, float], [float, float, float]]``. This represents anything which can be converted to a :class:`.CubicBezierPoints` NumPy array. """ CubicBezierPoints_Array: TypeAlias = npt.NDArray[PointDType] """``shape: (N, 4, 3)`` A NumPy array containing :math:`N` :class:`.CubicBezierPoints` objects: ``[[[float, float, float], [float, float, float], [float, float, float], [float, float, float]], ...]``. """ CubicBezierPointsLike_Array: TypeAlias = ( CubicBezierPoints_Array | Sequence[CubicBezierPointsLike] ) """``shape: (N, 4, 3)`` A sequence of :math:`N` :class:`.CubicBezierPointsLike` objects: ``[[[float, float, float], [float, float, float], [float, float, float], [float, float, float]], ...]``. This represents anything which can be converted to a :class:`.CubicBezierPoints_Array` NumPy array. """ CubicBezierPath: TypeAlias = Point3D_Array """``shape: (4*N, 3)`` A :class:`.Point3D_Array` of :math:`4N` points, where each one of the :math:`N` consecutive blocks of 4 points represents a cubic Bézier curve: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ CubicBezierPathLike: TypeAlias = Point3DLike_Array """``shape: (4*N, 3)`` A :class:`.Point3DLike_Array` of :math:`4N` points, where each one of the :math:`N` consecutive blocks of 4 points represents a cubic Bézier curve: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.CubicBezierPath` NumPy array. Please refer to the documentation of the function you are using for further type information. """ CubicSpline: TypeAlias = CubicBezierPath """``shape: (4*N, 3)`` A special case of :class:`.CubicBezierPath` where all the :math:`N` cubic Bézier curves are connected, forming a quadratic spline: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ CubicSplineLike: TypeAlias = CubicBezierPathLike """``shape: (4*N, 3)`` A special case of :class:`.CubicBezierPath` where all the :math:`N` cubic Bézier curves are connected, forming a quadratic spline: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.CubicSpline` NumPy array. Please refer to the documentation of the function you are using for further type information. """ BezierPoints: TypeAlias = Point3D_Array r"""``shape: (PPC, 3)`` A :class:`.Point3D_Array` of :math:`\text{PPC}` control points (:math:`\text{PPC: Points Per Curve} = n + 1`) for a single :math:`n`-th degree Bézier curve: ``[[float, float, float], ...]``. Please refer to the documentation of the function you are using for further type information. """ BezierPointsLike: TypeAlias = Point3DLike_Array r"""``shape: (PPC, 3)`` A :class:`.Point3DLike_Array` of :math:`\text{PPC}` control points (:math:`\text{PPC: Points Per Curve} = n + 1`) for a single :math:`n`-th degree Bézier curve: ``[[float, float, float], ...]``. This represents anything which can be converted to a :class:`.BezierPoints` NumPy array. Please refer to the documentation of the function you are using for further type information. """ BezierPoints_Array: TypeAlias = npt.NDArray[PointDType] r"""``shape: (N, PPC, 3)`` A NumPy array of :math:`N` :class:`.BezierPoints` objects containing :math:`\text{PPC}` :class:`.Point3D` objects each (:math:`\text{PPC: Points Per Curve} = n + 1`): ``[[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ BezierPointsLike_Array: TypeAlias = BezierPoints_Array | Sequence[BezierPointsLike] r"""``shape: (N, PPC, 3)`` A sequence of :math:`N` :class:`.BezierPointsLike` objects containing :math:`\text{PPC}` :class:`.Point3DLike` objects each (:math:`\text{PPC: Points Per Curve} = n + 1`): ``[[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.BezierPoints_Array` NumPy array. Please refer to the documentation of the function you are using for further type information. """ BezierPath: TypeAlias = Point3D_Array r"""``shape: (PPC*N, 3)`` A :class:`.Point3D_Array` of :math:`\text{PPC} \cdot N` points, where each one of the :math:`N` consecutive blocks of :math:`\text{PPC}` control points (:math:`\text{PPC: Points Per Curve} = n + 1`) represents a Bézier curve of :math:`n`-th degree: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ BezierPathLike: TypeAlias = Point3DLike_Array r"""``shape: (PPC*N, 3)`` A :class:`.Point3DLike_Array` of :math:`\text{PPC} \cdot N` points, where each one of the :math:`N` consecutive blocks of :math:`\text{PPC}` control points (:math:`\text{PPC: Points Per Curve} = n + 1`) represents a Bézier curve of :math:`n`-th degree: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.BezierPath` NumPy array. Please refer to the documentation of the function you are using for further type information. """ Spline: TypeAlias = BezierPath r"""``shape: (PPC*N, 3)`` A special case of :class:`.BezierPath` where all the :math:`N` Bézier curves consisting of :math:`\text{PPC}` :class:`.Point3D` objects (:math:`\text{PPC: Points Per Curve} = n + 1`) are connected, forming an :math:`n`-th degree spline: ``[[float, float, float], ...], ...]``. Please refer to the documentation of the function you are using for further type information. """ SplineLike: TypeAlias = BezierPathLike r"""``shape: (PPC*N, 3)`` A special case of :class:`.BezierPathLike` where all the :math:`N` Bézier curves consisting of :math:`\text{PPC}` :class:`.Point3D` objects (:math:`\text{PPC: Points Per Curve} = n + 1`) are connected, forming an :math:`n`-th degree spline: ``[[float, float, float], ...], ...]``. This represents anything which can be converted to a :class:`.Spline` NumPy array. Please refer to the documentation of the function you are using for further type information. """ FlatBezierPoints: TypeAlias = npt.NDArray[PointDType] | tuple[float, ...] """``shape: (3*PPC*N,)`` A flattened array of Bézier control points: ``[float, ...]``. """ """ [CATEGORY] Function types """ # Due to current limitations # (see https://github.com/python/mypy/issues/14656 / 8263), # we don't specify the first argument type (Mobject). # Nor are we able to specify the return type (Animation) since we cannot import # that here. FunctionOverride: TypeAlias = Callable """Function type returning an :class:`~.Animation` for the specified :class:`~.Mobject`. """ PathFuncType: TypeAlias = Callable[[Point3DLike, Point3DLike, float], Point3DLike] """Function mapping two :class:`.Point3D` objects and an alpha value to a new :class:`.Point3D`. """ MappingFunction: TypeAlias = Callable[[Point3D], Point3D] """A function mapping a :class:`.Point3D` to another :class:`.Point3D`.""" MultiMappingFunction: TypeAlias = Callable[[Point3D_Array], Point3D_Array] """A function mapping a :class:`.Point3D_Array` to another :class:`.Point3D_Array`. """ """ [CATEGORY] Image types """ PixelArray: TypeAlias = npt.NDArray[ManimInt] """``shape: (height, width) | (height, width, 3) | (height, width, 4)`` A rasterized image with a height of ``height`` pixels and a width of ``width`` pixels. Every value in the array is an integer from 0 to 255. Every pixel is represented either by a single integer indicating its lightness (for greyscale images), an :class:`.RGB_Array_Int` or an `RGBA_Array_Int`. """ GrayscalePixelArray: TypeAlias = PixelArray """``shape: (height, width)`` A 100% opaque grayscale :class:`.PixelArray`, where every pixel value is a `ManimInt` indicating its lightness (black -> gray -> white). """ RGBPixelArray: TypeAlias = PixelArray """``shape: (height, width, 3)`` A 100% opaque :class:`.PixelArray` in color, where every pixel value is an `RGB_Array_Int` object. """ RGBAPixelArray: TypeAlias = PixelArray """``shape: (height, width, 4)`` A :class:`.PixelArray` in color where pixels can be transparent. Every pixel value is an :class:`.RGBA_Array_Int` object. """ """ [CATEGORY] Path types """ StrPath: TypeAlias = str | PathLike[str] """A string or :class:`.os.PathLike` representing a path to a directory or file. """ StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes] """A string, bytes or :class:`.os.PathLike` object representing a path to a directory or file. """ ================================================ FILE: manim/utils/__init__.py ================================================ ================================================ FILE: manim/utils/bezier.py ================================================ """Utility functions related to Bézier curves.""" from __future__ import annotations __all__ = [ "bezier", "partial_bezier_points", "split_bezier", "subdivide_bezier", "bezier_remap", "interpolate", "integer_interpolate", "mid", "inverse_interpolate", "match_interpolate", "get_smooth_cubic_bezier_handle_points", "is_closed", "proportions_along_bezier_curve_for_point", "point_lies_on_bezier", ] from collections.abc import Callable, Sequence from functools import reduce from typing import TYPE_CHECKING, overload import numpy as np from manim.utils.simple_functions import choose if TYPE_CHECKING: from manim.typing import ( BezierPoints, BezierPoints_Array, BezierPointsLike, BezierPointsLike_Array, ColVector, MatrixMN, Point3D, Point3D_Array, Point3DLike, Point3DLike_Array, QuadraticBezierPath, QuadraticSpline, Spline, ) # l is a commonly used name in linear algebra # ruff: noqa: E741 @overload def bezier( points: BezierPointsLike, ) -> Callable[[float | ColVector], Point3D | Point3D_Array]: ... @overload def bezier( points: Sequence[Point3DLike_Array], ) -> Callable[[float | ColVector], Point3D_Array]: ... def bezier( points: Point3D_Array | Sequence[Point3D_Array], ) -> Callable[[float | ColVector], Point3D_Array]: """Classic implementation of a Bézier curve. Parameters ---------- points :math:`(d+1, 3)`-shaped array of :math:`d+1` control points defining a single Bézier curve of degree :math:`d`. Alternatively, for vectorization purposes, ``points`` can also be a :math:`(d+1, M, 3)`-shaped sequence of :math:`d+1` arrays of :math:`M` control points each, which define `M` Bézier curves instead. Returns ------- bezier_func : :class:`typing.Callable` [[:class:`float` | :class:`~.ColVector`], :class:`~.Point3D` | :class:`~.Point3D_Array`] Function describing the Bézier curve. The behaviour of this function depends on the shape of ``points``: * If ``points`` was a :math:`(d+1, 3)` array representing a single Bézier curve, then ``bezier_func`` can receive either: * a :class:`float` ``t``, in which case it returns a single :math:`(1, 3)`-shaped :class:`~.Point3D` representing the evaluation of the Bézier at ``t``, or * an :math:`(n, 1)`-shaped :class:`~.ColVector` containing :math:`n` values to evaluate the Bézier curve at, returning instead an :math:`(n, 3)`-shaped :class:`~.Point3D_Array` containing the points resulting from evaluating the Bézier at each of the :math:`n` values. .. warning:: If passing a vector of :math:`t`-values to ``bezier_func``, it **must** be a column vector/matrix of shape :math:`(n, 1)`. Passing an 1D array of shape :math:`(n,)` is not supported and **will result in undefined behaviour**. * If ``points`` was a :math:`(d+1, M, 3)` array describing :math:`M` Bézier curves, then ``bezier_func`` can receive either: * a :class:`float` ``t``, in which case it returns an :math:`(M, 3)`-shaped :class:`~.Point3D_Array` representing the evaluation of the :math:`M` Bézier curves at the same value ``t``, or * an :math:`(M, 1)`-shaped :class:`~.ColVector` containing :math:`M` values, such that the :math:`i`-th Bézier curve defined by ``points`` is evaluated at the corresponding :math:`i`-th value in ``t``, returning again an :math:`(M, 3)`-shaped :class:`~.Point3D_Array` containing those :math:`M` evaluations. .. warning:: Unlike the previous case, if you pass a :class:`~.ColVector` to ``bezier_func``, it **must** contain exactly :math:`M` values, each value for each of the :math:`M` Bézier curves defined by ``points``. Any array of shape other than :math:`(M, 1)` **will result in undefined behaviour**. """ P = np.asarray(points) degree = P.shape[0] - 1 if degree == 0: def zero_bezier(t: float | ColVector) -> Point3D | Point3D_Array: return np.ones_like(t) * P[0] return zero_bezier if degree == 1: def linear_bezier(t: float | ColVector) -> Point3D | Point3D_Array: return P[0] + t * (P[1] - P[0]) return linear_bezier if degree == 2: def quadratic_bezier(t: float | ColVector) -> Point3D | Point3D_Array: t2 = t * t mt = 1 - t mt2 = mt * mt return mt2 * P[0] + 2 * t * mt * P[1] + t2 * P[2] return quadratic_bezier if degree == 3: def cubic_bezier(t: float | ColVector) -> Point3D | Point3D_Array: t2 = t * t t3 = t2 * t mt = 1 - t mt2 = mt * mt mt3 = mt2 * mt return mt3 * P[0] + 3 * t * mt2 * P[1] + 3 * t2 * mt * P[2] + t3 * P[3] return cubic_bezier def nth_grade_bezier(t: float | ColVector) -> Point3D | Point3D_Array: is_scalar = not isinstance(t, np.ndarray) if is_scalar: B = np.empty((1, *P.shape)) else: assert isinstance(t, np.ndarray) t = t.reshape(-1, *[1 for dim in P.shape]) B = np.empty((t.shape[0], *P.shape)) B[:] = P for i in range(degree): # After the i-th iteration (i in [0, ..., d-1]) there are evaluations at t # of (d-i) Bezier curves of grade (i+1), stored in the first d-i slots of B B[:, : degree - i] += t * (B[:, 1 : degree - i + 1] - B[:, : degree - i]) # In the end, there shall be the evaluation at t of a single Bezier curve of # grade d, stored in the first slot of B if is_scalar: val: Point3D = B[0, 0] return val return B[:, 0] return nth_grade_bezier def partial_bezier_points(points: BezierPointsLike, a: float, b: float) -> BezierPoints: r"""Given an array of ``points`` which define a Bézier curve, and two numbers :math:`a, b` such that :math:`0 \le a < b \le 1`, return an array of the same size, which describes the portion of the original Bézier curve on the interval :math:`[a, b]`. :func:`partial_bezier_points` is conceptually equivalent to calling :func:`split_bezier` twice and discarding unused Bézier curves, but this is more efficient and doesn't waste computations. .. seealso:: See :func:`split_bezier` for an explanation on how to split Bézier curves. .. note:: To find the portion of a Bézier curve with :math:`t` between :math:`a` and :math:`b`: 1. Split the curve at :math:`t = a` and extract its 2nd subcurve. 2. We cannot evaluate the new subcurve at :math:`t = b` because its range of values for :math:`t` is different. To find the correct value, we need to transform the interval :math:`[a, 1]` into :math:`[0, 1]` by first subtracting :math:`a` to get :math:`[0, 1-a]` and then dividing by :math:`1-a`. Thus, our new value must be :math:`t = \frac{b - a}{1 - a}`. Define :math:`u = \frac{b - a}{1 - a}`. 3. Split the subcurve at :math:`t = u` and extract its 1st subcurve. The final portion is a linear combination of points, and thus the process can be summarized as a linear transformation by some matrix in terms of :math:`a` and :math:`b`. This matrix is given explicitly for Bézier curves up to degree 3, which are often used in Manim. For higher degrees, the algorithm described previously is used. For the case of a quadratic Bézier curve: * Step 1: .. math:: H'_1 = \begin{pmatrix} (1-a)^2 & 2(1-a)a & a^2 \\ 0 & (1-a) & a \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} * Step 2: .. math:: H''_0 &= \begin{pmatrix} 1 & 0 & 0 \\ (1-u) & u & 0\\ (1-u)^2 & 2(1-u)u & u^2 \end{pmatrix} H'_1 \\ & \\ &= \begin{pmatrix} 1 & 0 & 0 \\ (1-u) & u & 0\\ (1-u)^2 & 2(1-u)u & u^2 \end{pmatrix} \begin{pmatrix} (1-a)^2 & 2(1-a)a & a^2 \\ 0 & (1-a) & a \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} \\ & \\ &= \begin{pmatrix} (1-a)^2 & 2(1-a)a & a^2 \\ (1-a)(1-b) & a(1-b) + (1-a)b & ab \\ (1-b)^2 & 2(1-b)b & b^2 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} from where one can define a :math:`(3, 3)` matrix :math:`P_2` which, when applied over the array of ``points``, will return the desired partial quadratic Bézier curve: .. math:: P_2 = \begin{pmatrix} (1-a)^2 & 2(1-a)a & a^2 \\ (1-a)(1-b) & a(1-b) + (1-a)b & ab \\ (1-b)^2 & 2(1-b)b & b^2 \end{pmatrix} Similarly, for the cubic Bézier curve case, one can define the following :math:`(4, 4)` matrix :math:`P_3`: .. math:: P_3 = \begin{pmatrix} (1-a)^3 & 3(1-a)^2a & 3(1-a)a^2 & a^3 \\ (1-a)^2(1-b) & 2(1-a)a(1-b) + (1-a)^2b & a^2(1-b) + 2(1-a)ab & a^2b \\ (1-a)(1-b)^2 & a(1-b)^2 + 2(1-a)(1-b)b & 2a(1-b)b + (1-a)b^2 & ab^2 \\ (1-b)^3 & 3(1-b)^2b & 3(1-b)b^2 & b^3 \end{pmatrix} Parameters ---------- points set of points defining the bezier curve. a lower bound of the desired partial bezier curve. b upper bound of the desired partial bezier curve. Returns ------- :class:`~.BezierPoints` An array containing the control points defining the partial Bézier curve. """ # Border cases if a == 1: arr = np.array(points) arr[:] = arr[-1] return arr if b == 0: arr = np.array(points) arr[:] = arr[0] return arr points = np.asarray(points) degree = points.shape[0] - 1 if degree == 3: ma, mb = 1 - a, 1 - b a2, b2, ma2, mb2 = a * a, b * b, ma * ma, mb * mb a3, b3, ma3, mb3 = a2 * a, b2 * b, ma2 * ma, mb2 * mb portion_matrix = np.array( [ [ma3, 3 * ma2 * a, 3 * ma * a2, a3], [ma2 * mb, 2 * ma * a * mb + ma2 * b, a2 * mb + 2 * ma * a * b, a2 * b], [ma * mb2, a * mb2 + 2 * ma * mb * b, 2 * a * mb * b + ma * b2, a * b2], [mb3, 3 * mb2 * b, 3 * mb * b2, b3], ] ) return portion_matrix @ points if degree == 2: ma, mb = 1 - a, 1 - b portion_matrix = np.array( [ [ma * ma, 2 * a * ma, a * a], [ma * mb, a * mb + ma * b, a * b], [mb * mb, 2 * b * mb, b * b], ] ) return portion_matrix @ points if degree == 1: direction = points[1] - points[0] return np.array( [ points[0] + a * direction, points[0] + b * direction, ] ) if degree == 0: return points # Fallback case for nth degree Béziers # It is convenient that np.array copies points arr = np.array(points, dtype=float) N = arr.shape[0] # Current state for an example Bézier curve C0 = [P0, P1, P2, P3]: # arr = [P0, P1, P2, P3] if a != 0: for i in range(1, N): # 1st iter: arr = [L0(a), L1(a), L2(a), P3] # 2nd iter: arr = [Q0(a), Q1(a), L2(a), P3] # 3rd iter: arr = [C0(a), Q1(a), L2(a), P3] arr[: N - i] += a * (arr[1 : N - i + 1] - arr[: N - i]) # For faster calculations we shall define mu = 1 - u = (1 - b) / (1 - a). # This is because: # L0'(u) = P0' + u(P1' - P0') # = (1-u)P0' + uP1' # = muP0' + (1-mu)P1' # = P1' + mu(P0' - P1) # In this way, one can do something similar to the first loop. # # Current state: # arr = [C0(a), Q1(a), L2(a), P3] # = [P0', P1', P2', P3'] if b != 1: mu = (1 - b) / (1 - a) for i in range(1, N): # 1st iter: arr = [P0', L0'(u), L1'(u), L2'(u)] # 2nd iter: arr = [P0', L0'(u), Q0'(u), Q1'(u)] # 3rd iter: arr = [P0', L0'(u), Q0'(u), C0'(u)] arr[i:] += mu * (arr[i - 1 : -1] - arr[i:]) return arr def split_bezier(points: BezierPointsLike, t: float) -> Spline: r"""Split a Bézier curve at argument ``t`` into two curves. .. note:: .. seealso:: `A Primer on Bézier Curves #10: Splitting curves. Pomax. `_ As an example for a cubic Bézier curve, let :math:`p_0, p_1, p_2, p_3` be the points needed for the curve :math:`C_0 = [p_0, \ p_1, \ p_2, \ p_3]`. Define the 3 linear Béziers :math:`L_0, L_1, L_2` as interpolations of :math:`p_0, p_1, p_2, p_3`: .. math:: L_0(t) &= p_0 + t(p_1 - p_0) \\ L_1(t) &= p_1 + t(p_2 - p_1) \\ L_2(t) &= p_2 + t(p_3 - p_2) Define the 2 quadratic Béziers :math:`Q_0, Q_1` as interpolations of :math:`L_0, L_1, L_2`: .. math:: Q_0(t) &= L_0(t) + t(L_1(t) - L_0(t)) \\ Q_1(t) &= L_1(t) + t(L_2(t) - L_1(t)) Then :math:`C_0` is the following interpolation of :math:`Q_0` and :math:`Q_1`: .. math:: C_0(t) = Q_0(t) + t(Q_1(t) - Q_0(t)) Evaluating :math:`C_0` at a value :math:`t=t'` splits :math:`C_0` into two cubic Béziers :math:`H_0` and :math:`H_1`, defined by some of the points we calculated earlier: .. math:: H_0 &= [p_0, &\ L_0(t'), &\ Q_0(t'), &\ C_0(t') &] \\ H_1 &= [p_0(t'), &\ Q_1(t'), &\ L_2(t'), &\ p_3 &] As the resulting curves are obtained from linear combinations of ``points``, everything can be encoded into a matrix for efficiency, which is done for Bézier curves of degree up to 3. .. seealso:: `A Primer on Bézier Curves #11: Splitting curves using matrices. Pomax. `_ For the simpler case of a quadratic Bézier curve: .. math:: H_0 &= \begin{pmatrix} p_0 \\ (1-t) p_0 + t p_1 \\ (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\ \end{pmatrix} &= \begin{pmatrix} 1 & 0 & 0 \\ (1-t) & t & 0\\ (1-t)^2 & 2(1-t)t & t^2 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} \\ & \\ H_1 &= \begin{pmatrix} (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\ (1-t) p_1 + t p_2 \\ p_2 \end{pmatrix} &= \begin{pmatrix} (1-t)^2 & 2(1-t)t & t^2 \\ 0 & (1-t) & t \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} from where one can define a :math:`(6, 3)` split matrix :math:`S_2` which can multiply the array of ``points`` to compute the return value: .. math:: S_2 &= \begin{pmatrix} 1 & 0 & 0 \\ (1-t) & t & 0 \\ (1-t)^2 & 2(1-t)t & t^2 \\ (1-t)^2 & 2(1-t)t & t^2 \\ 0 & (1-t) & t \\ 0 & 0 & 1 \end{pmatrix} \\ & \\ S_2 P &= \begin{pmatrix} 1 & 0 & 0 \\ (1-t) & t & 0 \\ (1-t)^2 & 2(1-t)t & t^2 \\ (1-t)^2 & 2(1-t)t & t^2 \\ 0 & (1-t) & t \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \end{pmatrix} = \begin{pmatrix} \vert \\ H_0 \\ \vert \\ \vert \\ H_1 \\ \vert \end{pmatrix} For the previous example with a cubic Bézier curve: .. math:: H_0 &= \begin{pmatrix} p_0 \\ (1-t) p_0 + t p_1 \\ (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\ (1-t)^3 p_0 + 3(1-t)^2 t p_1 + 3(1-t)t^2 p_2 + t^3 p_3 \end{pmatrix} &= \begin{pmatrix} 1 & 0 & 0 & 0 \\ (1-t) & t & 0 & 0 \\ (1-t)^2 & 2(1-t)t & t^2 & 0 \\ (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \\ p_3 \end{pmatrix} \\ & \\ H_1 &= \begin{pmatrix} (1-t)^3 p_0 + 3(1-t)^2 t p_1 + 3(1-t)t^2 p_2 + t^3 p_3 \\ (1-t)^2 p_1 + 2(1-t)t p_2 + t^2 p_3 \\ (1-t) p_2 + t p_3 \\ p_3 \end{pmatrix} &= \begin{pmatrix} (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\ 0 & (1-t)^2 & 2(1-t)t & t^2 \\ 0 & 0 & (1-t) & t \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \\ p_3 \end{pmatrix} from where one can define a :math:`(8, 4)` split matrix :math:`S_3` which can multiply the array of ``points`` to compute the return value: .. math:: S_3 &= \begin{pmatrix} 1 & 0 & 0 & 0 \\ (1-t) & t & 0 & 0 \\ (1-t)^2 & 2(1-t)t & t^2 & 0 \\ (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\ (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\ 0 & (1-t)^2 & 2(1-t)t & t^2 \\ 0 & 0 & (1-t) & t \\ 0 & 0 & 0 & 1 \end{pmatrix} \\ & \\ S_3 P &= \begin{pmatrix} 1 & 0 & 0 & 0 \\ (1-t) & t & 0 & 0 \\ (1-t)^2 & 2(1-t)t & t^2 & 0 \\ (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\ (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\ 0 & (1-t)^2 & 2(1-t)t & t^2 \\ 0 & 0 & (1-t) & t \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_0 \\ p_1 \\ p_2 \\ p_3 \end{pmatrix} = \begin{pmatrix} \vert \\ H_0 \\ \vert \\ \vert \\ H_1 \\ \vert \end{pmatrix} Parameters ---------- points The control points of the Bézier curve. t The ``t``-value at which to split the Bézier curve. Returns ------- :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 if degree == 3: mt = 1 - t mt2 = mt * mt mt3 = mt2 * mt t2 = t * t t3 = t2 * t two_mt_t = 2 * mt * t three_mt2_t = 3 * mt2 * t three_mt_t2 = 3 * mt * t2 # Split matrix S3 explained in the docstring split_matrix = np.array( [ [1, 0, 0, 0], [mt, t, 0, 0], [mt2, two_mt_t, t2, 0], [mt3, three_mt2_t, three_mt_t2, t3], [mt3, three_mt2_t, three_mt_t2, t3], [0, mt2, two_mt_t, t2], [0, 0, mt, t], [0, 0, 0, 1], ] ) return split_matrix @ points if degree == 2: mt = 1 - t mt2 = mt * mt t2 = t * t two_tmt = 2 * t * mt # Split matrix S2 explained in the docstring split_matrix = np.array( [ [1, 0, 0], [mt, t, 0], [mt2, two_tmt, t2], [mt2, two_tmt, t2], [0, mt, t], [0, 0, 1], ] ) return split_matrix @ points if degree == 1: middle = points[0] + t * (points[1] - points[0]) return np.array([points[0], middle, middle, points[1]]) if degree == 0: return np.array([points[0], points[0]]) # Fallback case for nth degree Béziers arr = np.empty((2, N, dim)) arr[1] = points arr[0, 0] = points[0] # Example for a cubic Bézier # arr[0] = [P0 .. .. ..] # arr[1] = [P0 P1 P2 P3] for i in range(1, N): # 1st iter: arr[1] = [L0 L1 L2 P3] # 2nd iter: arr[1] = [Q0 Q1 L2 P3] # 3rd iter: arr[1] = [C0 Q1 L2 P3] arr[1, : N - i] += t * (arr[1, 1 : N - i + 1] - arr[1, : N - i]) # 1st iter: arr[0] = [P0 L0 .. ..] # 2nd iter: arr[0] = [P0 L0 Q0 ..] # 3rd iter: arr[0] = [P0 L0 Q0 C0] arr[0, i] = arr[1, 0] return arr.reshape(2 * N, dim) # Memos explained in subdivide_bezier docstring SUBDIVISION_MATRICES: list[dict[int, MatrixMN]] = [{} for i in range(4)] def _get_subdivision_matrix(n_points: int, n_divisions: int) -> MatrixMN: """Gets the matrix which subdivides a Bézier curve of ``n_points`` control points into ``n_divisions`` parts. Auxiliary function for :func:`subdivide_bezier`. See its docstrings for an explanation of the matrix build process. Parameters ---------- n_points The number of control points of the Bézier curve to subdivide. This function only handles up to 4 points. n_divisions The number of parts to subdivide the Bézier curve into. Returns ------- MatrixMN The matrix which, upon multiplying the control points of the Bézier curve, subdivides it into ``n_divisions`` parts. """ if n_points not in (1, 2, 3, 4): raise NotImplementedError( "This function does not support subdividing Bézier " "curves with 0 or more than 4 control points." ) subdivision_matrix = SUBDIVISION_MATRICES[n_points - 1].get(n_divisions, None) if subdivision_matrix is not None: return subdivision_matrix subdivision_matrix = np.empty((n_points * n_divisions, n_points)) # Cubic Bézier if n_points == 4: for i in range(n_divisions): i2 = i * i i3 = i2 * i ip1 = i + 1 ip12 = ip1 * ip1 ip13 = ip12 * ip1 nmi = n_divisions - i nmi2 = nmi * nmi nmi3 = nmi2 * nmi nmim1 = nmi - 1 nmim12 = nmim1 * nmim1 nmim13 = nmim12 * nmim1 subdivision_matrix[4 * i : 4 * (i + 1)] = np.array( [ [ nmi3, 3 * nmi2 * i, 3 * nmi * i2, i3, ], [ nmi2 * nmim1, 2 * nmi * nmim1 * i + nmi2 * ip1, nmim1 * i2 + 2 * nmi * i * ip1, i2 * ip1, ], [ nmi * nmim12, nmim12 * i + 2 * nmi * nmim1 * ip1, 2 * nmim1 * i * ip1 + nmi * ip12, i * ip12, ], [ nmim13, 3 * nmim12 * ip1, 3 * nmim1 * ip12, ip13, ], ] ) subdivision_matrix /= n_divisions * n_divisions * n_divisions # Quadratic Bézier elif n_points == 3: for i in range(n_divisions): ip1 = i + 1 nmi = n_divisions - i nmim1 = nmi - 1 subdivision_matrix[3 * i : 3 * (i + 1)] = np.array( [ [nmi * nmi, 2 * i * nmi, i * i], [nmi * nmim1, i * nmim1 + ip1 * nmi, i * ip1], [nmim1 * nmim1, 2 * ip1 * nmim1, ip1 * ip1], ] ) subdivision_matrix /= n_divisions * n_divisions # Linear Bézier (straight line) elif n_points == 2: aux_range = np.arange(n_divisions + 1) subdivision_matrix[::2, 1] = aux_range[:-1] subdivision_matrix[1::2, 1] = aux_range[1:] subdivision_matrix[:, 0] = subdivision_matrix[::-1, 1] subdivision_matrix /= n_divisions # Zero-degree Bézier (single point) elif n_points == 1: subdivision_matrix[:] = 1 SUBDIVISION_MATRICES[n_points - 1][n_divisions] = subdivision_matrix return subdivision_matrix def subdivide_bezier(points: BezierPointsLike, n_divisions: int) -> Spline: r"""Subdivide a Bézier curve into :math:`n` subcurves which have the same shape. The points at which the curve is split are located at the arguments :math:`t = \frac{i}{n}`, for :math:`i \in \{1, ..., n-1\}`. .. seealso:: * See :func:`split_bezier` for an explanation on how to split Bézier curves. * See :func:`partial_bezier_points` for an extra understanding of this function. .. note:: The resulting subcurves can be expressed as linear combinations of ``points``, which can be encoded in a single matrix that is precalculated for 2nd and 3rd degree Bézier curves. As an example for a quadratic Bézier curve: taking inspiration from the explanation in :func:`partial_bezier_points`, where the following matrix :math:`P_2` was defined to extract the portion of a quadratic Bézier curve for :math:`t \in [a, b]`: .. math:: P_2 = \begin{pmatrix} (1-a)^2 & 2(1-a)a & a^2 \\ (1-a)(1-b) & a(1-b) + (1-a)b & ab \\ (1-b)^2 & 2(1-b)b & b^2 \end{pmatrix} the plan is to replace :math:`[a, b]` with :math:`\left[ \frac{i-1}{n}, \frac{i}{n} \right], \ \forall i \in \{1, ..., n\}`. As an example for :math:`n = 2` divisions, construct :math:`P_1` for the interval :math:`\left[ 0, \frac{1}{2} \right]`, and :math:`P_2` for the interval :math:`\left[ \frac{1}{2}, 1 \right]`: .. math:: P_1 = \begin{pmatrix} 1 & 0 & 0 \\ 0.5 & 0.5 & 0 \\ 0.25 & 0.5 & 0.25 \end{pmatrix} , \quad P_2 = \begin{pmatrix} 0.25 & 0.5 & 0.25 \\ 0 & 0.5 & 0.5 \\ 0 & 0 & 1 \end{pmatrix} Therefore, the following :math:`(6, 3)` subdivision matrix :math:`D_2` can be constructed, which will subdivide an array of ``points`` into 2 parts: .. math:: D_2 = \begin{pmatrix} M_1 \\ M_2 \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 \\ 0.5 & 0.5 & 0 \\ 0.25 & 0.5 & 0.25 \\ 0.25 & 0.5 & 0.25 \\ 0 & 0.5 & 0.5 \\ 0 & 0 & 1 \end{pmatrix} For quadratic and cubic Bézier curves, the subdivision matrices are memoized for efficiency. For higher degree curves, an iterative algorithm inspired by the one from :func:`split_bezier` is used instead. .. image:: /_static/bezier_subdivision_example.png Parameters ---------- points The control points of the Bézier curve. n_divisions The number of curves to subdivide the Bézier curve into Returns ------- :class:`~.Spline` An array containing the points defining the new :math:`n` subcurves. """ points = np.asarray(points) if n_divisions == 1: return points N, dim = points.shape if N <= 4: subdivision_matrix = _get_subdivision_matrix(N, n_divisions) return subdivision_matrix @ points # Fallback case for an nth degree Bézier: successive splitting beziers = np.empty((n_divisions, N, dim)) beziers[-1] = points for curve_num in range(n_divisions - 1, 0, -1): curr = beziers[curve_num] prev = beziers[curve_num - 1] prev[0] = curr[0] a = (n_divisions - curve_num) / (n_divisions - curve_num + 1) # Current state for an example cubic Bézier curve: # prev = [P0 .. .. ..] # curr = [P0 P1 P2 P3] for i in range(1, N): # 1st iter: curr = [L0 L1 L2 P3] # 2nd iter: curr = [Q0 Q1 L2 P3] # 3rd iter: curr = [C0 Q1 L2 P3] curr[: N - i] += a * (curr[1 : N - i + 1] - curr[: N - i]) # 1st iter: prev = [P0 L0 .. ..] # 2nd iter: prev = [P0 L0 Q0 ..] # 3rd iter: prev = [P0 L0 Q0 C0] prev[i] = curr[0] return beziers.reshape(n_divisions * N, dim) def bezier_remap( bezier_tuples: BezierPointsLike_Array, new_number_of_curves: int, ) -> BezierPoints_Array: """Subdivides each curve in ``bezier_tuples`` into as many parts as necessary, until the final number of curves reaches a desired amount, ``new_number_of_curves``. Parameters ---------- bezier_tuples An array of multiple Bézier curves of degree :math:`d` to be remapped. The shape of this array must be ``(current_number_of_curves, nppc, dim)``, where: * ``current_number_of_curves`` is the current amount of curves in the array ``bezier_tuples``, * ``nppc`` is the amount of points per curve, such that their degree is ``nppc-1``, and * ``dim`` is the dimension of the points, usually :math:`3`. new_number_of_curves The number of curves that the output will contain. This needs to be higher than the current number. Returns ------- :class:`~.BezierPoints_Array` The new array of shape ``(new_number_of_curves, nppc, dim)``, containing the new Bézier curves after the remap. """ bezier_tuples = np.asarray(bezier_tuples) current_number_of_curves, nppc, dim = bezier_tuples.shape # This is an array with values ranging from 0 # up to curr_num_curves, with repeats such that # its total length is target_num_curves. For example, # with curr_num_curves = 10, target_num_curves = 15, this # would be [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]. repeat_indices = ( np.arange(new_number_of_curves, dtype="i") * current_number_of_curves ) // new_number_of_curves # If the nth term of this list is k, it means # that the nth curve of our path should be split # into k pieces. # In the above example our array had the following elements # [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9] # We have two 0s, one 1, two 2s and so on. # The split factors array would hence be: # [2, 1, 2, 1, 2, 1, 2, 1, 2, 1] split_factors = np.zeros(current_number_of_curves, dtype="i") np.add.at(split_factors, repeat_indices, 1) new_tuples = np.empty((new_number_of_curves, nppc, dim)) index = 0 for curve, sf in zip(bezier_tuples, split_factors, strict=True): new_tuples[index : index + sf] = subdivide_bezier(curve, sf).reshape( sf, nppc, dim ) index += sf return new_tuples # Linear interpolation variants @overload def interpolate(start: float, end: float, alpha: float) -> float: ... @overload def interpolate(start: float, end: float, alpha: ColVector) -> ColVector: ... @overload def interpolate(start: Point3D, end: Point3D, alpha: float) -> Point3D: ... @overload def interpolate(start: Point3D, end: Point3D, alpha: ColVector) -> Point3D_Array: ... def interpolate( start: float | Point3D, end: float | Point3D, alpha: float | ColVector, ) -> float | ColVector | Point3D | Point3D_Array: """Linearly interpolates between two values ``start`` and ``end``. Parameters ---------- start The start of the range. end The end of the range. alpha A float between 0 and 1, or an :math:`(n, 1)` column vector containing :math:`n` floats between 0 and 1 to interpolate in a vectorized fashion. Returns ------- :class:`float` | :class:`~.ColVector` | :class:`~.Point3D` | :class:`~.Point3D_Array` The result of the linear interpolation. * If ``start`` and ``end`` are of type :class:`float`, and: * ``alpha`` is also a :class:`float`, the return is simply another :class:`float`. * ``alpha`` is a :class:`~.ColVector`, the return is another :class:`~.ColVector`. * If ``start`` and ``end`` are of type :class:`~.Point3D`, and: * ``alpha`` is a :class:`float`, the return is another :class:`~.Point3D`. * ``alpha`` is a :class:`~.ColVector`, the return is a :class:`~.Point3D_Array`. """ return (1 - alpha) * start + alpha * end def integer_interpolate( start: float, end: float, alpha: float, ) -> tuple[int, float]: """ This is a variant of interpolate that returns an integer and the residual Parameters ---------- start The start of the range end The end of the range alpha a float between 0 and 1. Returns ------- tuple[int, float] This returns an integer between start and end (inclusive) representing appropriate interpolation between them, along with a "residue" representing a new proportion between the returned integer and the next one of the list. Example ------- .. code-block:: pycon >>> integer, residue = integer_interpolate(start=0, end=10, alpha=0.46) >>> np.allclose((integer, residue), (4, 0.6)) True """ if alpha >= 1: return (int(end - 1), 1.0) if alpha <= 0: return (int(start), 0) value = int(interpolate(start, end, alpha)) residue = ((end - start) * alpha) % 1 return (value, residue) @overload def mid(start: float, end: float) -> float: ... @overload def mid(start: Point3D, end: Point3D) -> Point3D: ... def mid(start: float | Point3D, end: float | Point3D) -> float | Point3D: """Returns the midpoint between two values. Parameters ---------- start The first value end The second value Returns ------- The midpoint between the two values """ return (start + end) / 2.0 @overload def inverse_interpolate(start: float, end: float, value: float) -> float: ... @overload def inverse_interpolate(start: float, end: float, value: Point3D) -> Point3D: ... @overload def inverse_interpolate(start: Point3D, end: Point3D, value: Point3D) -> Point3D: ... def inverse_interpolate( start: float | Point3D, end: float | Point3D, value: float | Point3D, ) -> float | Point3D: """Perform inverse interpolation to determine the alpha values that would produce the specified ``value`` given the ``start`` and ``end`` values or points. Parameters ---------- start The start value or point of the interpolation. end The end value or point of the interpolation. value The value or point for which the alpha value should be determined. Returns ------- The alpha values producing the given input when interpolating between ``start`` and ``end``. Example ------- .. code-block:: pycon >>> inverse_interpolate(start=2, end=6, value=4) np.float64(0.5) >>> start = np.array([1, 2, 1]) >>> end = np.array([7, 8, 11]) >>> value = np.array([4, 5, 5]) >>> inverse_interpolate(start, end, value) array([0.5, 0.5, 0.4]) """ return np.true_divide(value - start, end - start) @overload def match_interpolate( new_start: float, new_end: float, old_start: float, old_end: float, old_value: float, ) -> float: ... @overload def match_interpolate( new_start: float, new_end: float, old_start: float, old_end: float, old_value: Point3D, ) -> Point3D: ... def match_interpolate( new_start: float, new_end: float, old_start: float, old_end: float, old_value: float | Point3D, ) -> float | Point3D: """Interpolate a value from an old range to a new range. Parameters ---------- new_start The start of the new range. new_end The end of the new range. old_start The start of the old range. old_end The end of the old range. old_value The value within the old range whose corresponding value in the new range (with the same alpha value) is desired. Returns ------- The interpolated value within the new range. Examples -------- >>> from manim import match_interpolate >>> match_interpolate(0, 100, 10, 20, 15) np.float64(50.0) """ old_alpha = inverse_interpolate(old_start, old_end, old_value) return interpolate( new_start, new_end, old_alpha, ) # Figuring out which Bézier curves most smoothly connect a sequence of points def get_smooth_cubic_bezier_handle_points( anchors: Point3DLike_Array, ) -> tuple[Point3D_Array, Point3D_Array]: """Given an array of anchors for a cubic spline (array of connected cubic Bézier curves), compute the 1st and 2nd handle for every curve, so that the resulting spline is smooth. Parameters ---------- anchors Anchors of a cubic spline. Returns ------- :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`] A tuple of two arrays: one containing the 1st handle for every curve in the cubic spline, and the other containing the 2nd handles. """ anchors = np.asarray(anchors) n_anchors = anchors.shape[0] # If there's a single anchor, there's no Bézier curve. # Return empty arrays. if n_anchors == 1: dim = anchors.shape[1] return np.zeros((0, dim)), np.zeros((0, dim)) # If there are only two anchors (thus only one pair of handles), # they can only be an interpolation of these two anchors with alphas # 1/3 and 2/3, which will draw a straight line between the anchors. if n_anchors == 2: val = interpolate(anchors[0], anchors[1], np.array([[1 / 3], [2 / 3]])) return (val[0], val[1]) # Handle different cases depending on whether the points form a closed # curve or not curve_is_closed = is_closed(anchors) if curve_is_closed: return get_smooth_closed_cubic_bezier_handle_points(anchors) else: return get_smooth_open_cubic_bezier_handle_points(anchors) CP_CLOSED_MEMO = np.array([1 / 3]) UP_CLOSED_MEMO = np.array([1 / 3]) def get_smooth_closed_cubic_bezier_handle_points( anchors: Point3DLike_Array, ) -> tuple[Point3D_Array, Point3D_Array]: r"""Special case of :func:`get_smooth_cubic_bezier_handle_points`, when the ``anchors`` form a closed loop. .. note:: A system of equations must be solved to get the first handles of every Bézier curve (referred to as :math:`H_1`). Then :math:`H_2` (the second handles) can be obtained separately. .. seealso:: The equations were obtained from: * `Conditions on control points for continuous curvature. (2016). Jaco Stuifbergen. `_ In general, if there are :math:`N+1` anchors, there will be :math:`N` Bézier curves and thus :math:`N` pairs of handles to find. We must solve the following system of equations for the 1st handles (example for :math:`N = 5`): .. math:: \begin{pmatrix} 4 & 1 & 0 & 0 & 1 \\ 1 & 4 & 1 & 0 & 0 \\ 0 & 1 & 4 & 1 & 0 \\ 0 & 0 & 1 & 4 & 1 \\ 1 & 0 & 0 & 1 & 4 \end{pmatrix} \begin{pmatrix} H_{1,0} \\ H_{1,1} \\ H_{1,2} \\ H_{1,3} \\ H_{1,4} \end{pmatrix} = \begin{pmatrix} 4A_0 + 2A_1 \\ 4A_1 + 2A_2 \\ 4A_2 + 2A_3 \\ 4A_3 + 2A_4 \\ 4A_4 + 2A_5 \end{pmatrix} which will be expressed as :math:`RH_1 = D`. :math:`R` is almost a tridiagonal matrix, so we could use Thomas' algorithm. .. seealso:: `Tridiagonal matrix algorithm. Wikipedia. `_ However, :math:`R` has ones at the opposite corners. A solution to this is the first decomposition proposed in the link below, with :math:`\alpha = 1`: .. seealso:: `Tridiagonal matrix algorithm # Variants. Wikipedia. `_ .. math:: R = \begin{pmatrix} 4 & 1 & 0 & 0 & 1 \\ 1 & 4 & 1 & 0 & 0 \\ 0 & 1 & 4 & 1 & 0 \\ 0 & 0 & 1 & 4 & 1 \\ 1 & 0 & 0 & 1 & 4 \end{pmatrix} &= \begin{pmatrix} 3 & 1 & 0 & 0 & 0 \\ 1 & 4 & 1 & 0 & 0 \\ 0 & 1 & 4 & 1 & 0 \\ 0 & 0 & 1 & 4 & 1 \\ 0 & 0 & 0 & 1 & 3 \end{pmatrix} + \begin{pmatrix} 1 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 1 \end{pmatrix} \\ & \\ &= \begin{pmatrix} 3 & 1 & 0 & 0 & 0 \\ 1 & 4 & 1 & 0 & 0 \\ 0 & 1 & 4 & 1 & 0 \\ 0 & 0 & 1 & 4 & 1 \\ 0 & 0 & 0 & 1 & 3 \end{pmatrix} + \begin{pmatrix} 1 \\ 0 \\ 0 \\ 0 \\ 1 \end{pmatrix} \begin{pmatrix} 1 & 0 & 0 & 0 & 1 \end{pmatrix} \\ & \\ &= T + uv^t We decompose :math:`R = T + uv^t`, where :math:`T` is a tridiagonal matrix, and :math:`u, v` are :math:`N`-D vectors such that :math:`u_0 = u_{N-1} = v_0 = v_{N-1} = 1`, and :math:`u_i = v_i = 0, \forall i \in \{1, ..., N-2\}`. Thus: .. math:: RH_1 &= D \\ \Rightarrow (T + uv^t)H_1 &= D If we find a vector :math:`q` such that :math:`Tq = u`: .. math:: \Rightarrow (T + Tqv^t)H_1 &= D \\ \Rightarrow T(I + qv^t)H_1 &= D \\ \Rightarrow H_1 &= (I + qv^t)^{-1} T^{-1} D According to Sherman-Morrison's formula: .. seealso:: `Sherman-Morrison's formula. Wikipedia. `_ .. math:: (I + qv^t)^{-1} = I - \frac{1}{1 + v^tq} qv^t If we find :math:`Y = T^{-1} D`, or in other words, if we solve for :math:`Y` in :math:`TY = D`: .. math:: H_1 &= (I + qv^t)^{-1} T^{-1} D \\ &= (I + qv^t)^{-1} Y \\ &= (I - \frac{1}{1 + v^tq} qv^t) Y \\ &= Y - \frac{1}{1 + v^tq} qv^tY Therefore, we must solve for :math:`q` and :math:`Y` in :math:`Tq = u` and :math:`TY = D`. As :math:`T` is now tridiagonal, we shall use Thomas' algorithm. Define: * :math:`a = [a_0, \ a_1, \ ..., \ a_{N-2}]` as :math:`T`'s lower diagonal of :math:`N-1` elements, such that :math:`a_0 = a_1 = ... = a_{N-2} = 1`, so this diagonal is filled with ones; * :math:`b = [b_0, \ b_1, \ ..., \ b_{N-2}, \ b_{N-1}]` as :math:`T`'s main diagonal of :math:`N` elements, such that :math:`b_0 = b_{N-1} = 3`, and :math:`b_1 = b_2 = ... = b_{N-2} = 4`; * :math:`c = [c_0, \ c_1, \ ..., \ c_{N-2}]` as :math:`T`'s upper diagonal of :math:`N-1` elements, such that :math:`c_0 = c_1 = ... = c_{N-2} = 1`: this diagonal is also filled with ones. If, according to Thomas' algorithm, we define: .. math:: c'_0 &= \frac{c_0}{b_0} & \\ c'_i &= \frac{c_i}{b_i - a_{i-1} c'_{i-1}}, & \quad \forall i \in \{1, ..., N-2\} \\ & & \\ u'_0 &= \frac{u_0}{b_0} & \\ u'_i &= \frac{u_i - a_{i-1} u'_{i-1}}{b_i - a_{i-1} c'_{i-1}}, & \quad \forall i \in \{1, ..., N-1\} \\ & & \\ D'_0 &= \frac{1}{b_0} D_0 & \\ D'_i &= \frac{1}{b_i - a_{i-1} c'_{i-1}} (D_i - a_{i-1} D'_{i-1}), & \quad \forall i \in \{1, ..., N-1\} Then: .. math:: c'_0 &= \frac{1}{3} & \\ c'_i &= \frac{1}{4 - c'_{i-1}}, & \quad \forall i \in \{1, ..., N-2\} \\ & & \\ u'_0 &= \frac{1}{3} & \\ u'_i &= \frac{-u'_{i-1}}{4 - c'_{i-1}} = -c'_i u'_{i-1}, & \quad \forall i \in \{1, ..., N-2\} \\ u'_{N-1} &= \frac{1 - u'_{N-2}}{3 - c'_{N-2}} & \\ & & \\ D'_0 &= \frac{1}{3} (4A_0 + 2A_1) & \\ D'_i &= \frac{1}{4 - c'_{i-1}} (4A_i + 2A_{i+1} - D'_{i-1}) & \\ &= c_i (4A_i + 2A_{i+1} - D'_{i-1}), & \quad \forall i \in \{1, ..., N-2\} \\ D'_{N-1} &= \frac{1}{3 - c'_{N-2}} (4A_{N-1} + 2A_N - D'_{N-2}) & Finally, we can do Backward Substitution to find :math:`q` and :math:`Y`: .. math:: q_{N-1} &= u'_{N-1} & \\ q_i &= u'_{i} - c'_i q_{i+1}, & \quad \forall i \in \{0, ..., N-2\} \\ & & \\ Y_{N-1} &= D'_{N-1} & \\ Y_i &= D'_i - c'_i Y_{i+1}, & \quad \forall i \in \{0, ..., N-2\} With those values, we can finally calculate :math:`H_1 = Y - \frac{1}{1 + v^tq} qv^tY`. Given that :math:`v_0 = v_{N-1} = 1`, and :math:`v_1 = v_2 = ... = v_{N-2} = 0`, its dot products with :math:`q` and :math:`Y` are respectively :math:`v^tq = q_0 + q_{N-1}` and :math:`v^tY = Y_0 + Y_{N-1}`. Thus: .. math:: H_1 = Y - \frac{1}{1 + q_0 + q_{N-1}} q(Y_0 + Y_{N-1}) Once we have :math:`H_1`, we can get :math:`H_2` (the array of second handles) as follows: .. math:: H_{2, i} &= 2A_{i+1} - H_{1, i+1}, & \quad \forall i \in \{0, ..., N-2\} \\ H_{2, N-1} &= 2A_0 - H_{1, 0} & Because the matrix :math:`R` always follows the same pattern (and thus :math:`T, u, v` as well), we can define a memo list for :math:`c'` and :math:`u'` to avoid recalculation. We cannot memoize :math:`D` and :math:`Y`, however, because they are always different matrices. We cannot make a memo for :math:`q` either, but we can calculate it faster because :math:`u'` can be memoized. Parameters ---------- anchors Anchors of a closed cubic spline. Returns ------- :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`] A tuple of two arrays: one containing the 1st handle for every curve in the closed cubic spline, and the other containing the 2nd handles. """ global CP_CLOSED_MEMO global UP_CLOSED_MEMO A = np.asarray(anchors) N = A.shape[0] - 1 dim = A.shape[1] # Calculate cp (c prime) and up (u prime) with help from # CP_CLOSED_MEMO and UP_CLOSED_MEMO. len_memo = CP_CLOSED_MEMO.size if len_memo < N - 1: cp = np.empty(N - 1) up = np.empty(N - 1) cp[:len_memo] = CP_CLOSED_MEMO up[:len_memo] = UP_CLOSED_MEMO # Forward Substitution 1 # Calculate up (at the same time we calculate cp). for i in range(len_memo, N - 1): cp[i] = 1 / (4 - cp[i - 1]) up[i] = -cp[i] * up[i - 1] CP_CLOSED_MEMO = cp UP_CLOSED_MEMO = up else: cp = CP_CLOSED_MEMO[: N - 1] up = UP_CLOSED_MEMO[: N - 1] # The last element of u' is different cp_last_division = 1 / (3 - cp[N - 2]) up_last = cp_last_division * (1 - up[N - 2]) # Backward Substitution 1 # Calculate q. q = np.empty((N, dim)) q[N - 1] = up_last for i in range(N - 2, -1, -1): q[i] = up[i] - cp[i] * q[i + 1] # Forward Substitution 2 # Calculate Dp (D prime). Dp = np.empty((N, dim)) AUX = 4 * A[:N] + 2 * A[1:] # Vectorize the sum for efficiency. Dp[0] = AUX[0] / 3 for i in range(1, N - 1): Dp[i] = cp[i] * (AUX[i] - Dp[i - 1]) Dp[N - 1] = cp_last_division * (AUX[N - 1] - Dp[N - 2]) # Backward Substitution # Calculate Y, which is defined as a view of Dp for efficiency # and semantic convenience at the same time. Y = Dp # Y[N-1] = Dp[N-1] (redundant) for i in range(N - 2, -1, -1): Y[i] = Dp[i] - cp[i] * Y[i + 1] # Calculate H1. H1 = Y - 1 / (1 + q[0] + q[N - 1]) * q * (Y[0] + Y[N - 1]) # Calculate H2. H2 = np.empty((N, dim)) H2[0 : N - 1] = 2 * A[1:N] - H1[1:N] H2[N - 1] = 2 * A[N] - H1[0] return H1, H2 CP_OPEN_MEMO = np.array([0.5]) def get_smooth_open_cubic_bezier_handle_points( anchors: Point3DLike_Array, ) -> tuple[Point3D_Array, Point3D_Array]: r"""Special case of :func:`get_smooth_cubic_bezier_handle_points`, when the ``anchors`` do not form a closed loop. .. note:: A system of equations must be solved to get the first handles of every Bèzier curve (referred to as :math:`H_1`). Then :math:`H_2` (the second handles) can be obtained separately. .. seealso:: The equations were obtained from: * `Smooth Bézier Spline Through Prescribed Points. (2012). Particle in Cell Consulting LLC. `_ * `Conditions on control points for continuous curvature. (2016). Jaco Stuifbergen. `_ .. warning:: The equations in the first webpage have some typos which were corrected in the comments. In general, if there are :math:`N+1` anchors, there will be :math:`N` Bézier curves and thus :math:`N` pairs of handles to find. We must solve the following system of equations for the 1st handles (example for :math:`N = 5`): .. math:: \begin{pmatrix} 2 & 1 & 0 & 0 & 0 \\ 1 & 4 & 1 & 0 & 0 \\ 0 & 1 & 4 & 1 & 0 \\ 0 & 0 & 1 & 4 & 1 \\ 0 & 0 & 0 & 2 & 7 \end{pmatrix} \begin{pmatrix} H_{1,0} \\ H_{1,1} \\ H_{1,2} \\ H_{1,3} \\ H_{1,4} \end{pmatrix} = \begin{pmatrix} A_0 + 2A_1 \\ 4A_1 + 2A_2 \\ 4A_2 + 2A_3 \\ 4A_3 + 2A_4 \\ 8A_4 + A_5 \end{pmatrix} which will be expressed as :math:`TH_1 = D`. :math:`T` is a tridiagonal matrix, so the system can be solved in :math:`O(N)` operations. Here we shall use Thomas' algorithm or the tridiagonal matrix algorithm. .. seealso:: `Tridiagonal matrix algorithm. Wikipedia. `_ Define: * :math:`a = [a_0, \ a_1, \ ..., \ a_{N-2}]` as :math:`T`'s lower diagonal of :math:`N-1` elements, such that :math:`a_0 = a_1 = ... = a_{N-3} = 1`, and :math:`a_{N-2} = 2`; * :math:`b = [b_0, \ b_1, \ ..., \ b_{N-2}, \ b_{N-1}]` as :math:`T`'s main diagonal of :math:`N` elements, such that :math:`b_0 = 2`, :math:`b_1 = b_2 = ... = b_{N-2} = 4`, and :math:`b_{N-1} = 7`; * :math:`c = [c_0, \ c_1, \ ..., \ c_{N-2}]` as :math:`T`'s upper diagonal of :math:`{N-1}` elements, such that :math:`c_0 = c_1 = ... = c_{N-2} = 1`: this diagonal is filled with ones. If, according to Thomas' algorithm, we define: .. math:: c'_0 &= \frac{c_0}{b_0} & \\ c'_i &= \frac{c_i}{b_i - a_{i-1} c'_{i-1}}, & \quad \forall i \in \{1, ..., N-2\} \\ & & \\ D'_0 &= \frac{1}{b_0} D_0 & \\ D'_i &= \frac{1}{b_i - a_{i-1} c'{i-1}} (D_i - a_{i-1} D'_{i-1}), & \quad \forall i \in \{1, ..., N-1\} Then: .. math:: c'_0 &= 0.5 & \\ c'_i &= \frac{1}{4 - c'_{i-1}}, & \quad \forall i \in \{1, ..., N-2\} \\ & & \\ D'_0 &= 0.5A_0 + A_1 & \\ D'_i &= \frac{1}{4 - c'_{i-1}} (4A_i + 2A_{i+1} - D'_{i-1}) & \\ &= c_i (4A_i + 2A_{i+1} - D'_{i-1}), & \quad \forall i \in \{1, ..., N-2\} \\ D'_{N-1} &= \frac{1}{7 - 2c'_{N-2}} (8A_{N-1} + A_N - 2D'_{N-2}) & Finally, we can do Backward Substitution to find :math:`H_1`: .. math:: H_{1, N-1} &= D'_{N-1} & \\ H_{1, i} &= D'_i - c'_i H_{1, i+1}, & \quad \forall i \in \{0, ..., N-2\} Once we have :math:`H_1`, we can get :math:`H_2` (the array of second handles) as follows: .. math:: H_{2, i} &= 2A_{i+1} - H_{1, i+1}, & \quad \forall i \in \{0, ..., N-2\} \\ H_{2, N-1} &= 0.5A_N + 0.5H_{1, N-1} & As the matrix :math:`T` always follows the same pattern, we can define a memo list for :math:`c'` to avoid recalculation. We cannot do the same for :math:`D`, however, because it is always a different matrix. Parameters ---------- anchors Anchors of an open cubic spline. Returns ------- :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`] A tuple of two arrays: one containing the 1st handle for every curve in the open cubic spline, and the other containing the 2nd handles. """ global CP_OPEN_MEMO A = np.asarray(anchors) N = A.shape[0] - 1 dim = A.shape[1] # Calculate cp (c prime) with help from CP_OPEN_MEMO. len_memo = CP_OPEN_MEMO.size if len_memo < N - 1: cp = np.empty(N - 1) cp[:len_memo] = CP_OPEN_MEMO for i in range(len_memo, N - 1): cp[i] = 1 / (4 - cp[i - 1]) CP_OPEN_MEMO = cp else: cp = CP_OPEN_MEMO[: N - 1] # Calculate Dp (D prime). Dp = np.empty((N, dim)) Dp[0] = 0.5 * A[0] + A[1] AUX = 4 * A[1 : N - 1] + 2 * A[2:N] # Vectorize the sum for efficiency. for i in range(1, N - 1): Dp[i] = cp[i] * (AUX[i - 1] - Dp[i - 1]) Dp[N - 1] = (1 / (7 - 2 * cp[N - 2])) * (8 * A[N - 1] + A[N] - 2 * Dp[N - 2]) # Backward Substitution. # H1 (array of the first handles) is defined as a view of Dp for efficiency # and semantic convenience at the same time. H1 = Dp # H1[N-1] = Dp[N-1] (redundant) for i in range(N - 2, -1, -1): H1[i] = Dp[i] - cp[i] * H1[i + 1] # Calculate H2. H2 = np.empty((N, dim)) H2[0 : N - 1] = 2 * A[1:N] - H1[1:N] H2[N - 1] = 0.5 * (A[N] + H1[N - 1]) return H1, H2 @overload def get_quadratic_approximation_of_cubic( a0: Point3DLike, h0: Point3DLike, h1: Point3DLike, a1: Point3DLike ) -> QuadraticSpline: ... @overload def get_quadratic_approximation_of_cubic( a0: Point3DLike_Array, h0: Point3DLike_Array, h1: Point3DLike_Array, a1: Point3DLike_Array, ) -> QuadraticBezierPath: ... def get_quadratic_approximation_of_cubic( a0: Point3D | Point3D_Array, h0: Point3D | Point3D_Array, h1: Point3D | Point3D_Array, a1: Point3D | Point3D_Array, ) -> QuadraticSpline | QuadraticBezierPath: r"""If ``a0``, ``h0``, ``h1`` and ``a1`` are the control points of a cubic Bézier curve, approximate the curve with two quadratic Bézier curves and return an array of 6 points, where the first 3 points represent the first quadratic curve and the last 3 represent the second one. Otherwise, if ``a0``, ``h0``, ``h1`` and ``a1`` are _arrays_ of :math:`N` points representing :math:`N` cubic Bézier curves, return an array of :math:`6N` points where each group of :math:`6` consecutive points approximates each of the :math:`N` curves in a similar way as above. .. note:: If the cubic spline given by the original cubic Bézier curves is smooth, this algorithm will generate a quadratic spline which is also smooth. If a cubic Bézier is given by .. math:: C(t) = (1-t)^3 A_0 + 3(1-t)^2 t H_0 + 3(1-t)t^2 H_1 + t^3 A_1 where :math:`A_0`, :math:`H_0`, :math:`H_1` and :math:`A_1` are its control points, then this algorithm should generate two quadratic Béziers given by .. math:: Q_0(t) &= (1-t)^2 A_0 + 2(1-t)t M_0 + t^2 K \\ Q_1(t) &= (1-t)^2 K + 2(1-t)t M_1 + t^2 A_1 where :math:`M_0` and :math:`M_1` are the respective handles to be found for both curves, and :math:`K` is the end anchor of the 1st curve and the start anchor of the 2nd, which must also be found. To solve for :math:`M_0`, :math:`M_1` and :math:`K`, three conditions can be imposed: 1. :math:`Q_0'(0) = \frac{1}{2}C'(0)`. The derivative of the first quadratic curve at :math:`t = 0` should be proportional to that of the original cubic curve, also at :math:`t = 0`. Because the cubic curve is split into two parts, it is necessary to divide this by two: the speed of a point travelling through the curve should be half of the original. This gives: .. math:: Q_0'(0) &= \frac{1}{2}C'(0) \\ 2(M_0 - A_0) &= \frac{3}{2}(H_0 - A_0) \\ 2M_0 - 2A_0 &= \frac{3}{2}H_0 - \frac{3}{2}A_0 \\ 2M_0 &= \frac{3}{2}H_0 + \frac{1}{2}A_0 \\ M_0 &= \frac{1}{4}(3H_0 + A_0) 2. :math:`Q_1'(1) = \frac{1}{2}C'(1)`. The derivative of the second quadratic curve at :math:`t = 1` should be half of that of the original cubic curve for the same reasons as above, also at :math:`t = 1`. This gives: .. math:: Q_1'(1) &= \frac{1}{2}C'(1) \\ 2(A_1 - M_1) &= \frac{3}{2}(A_1 - H_1) \\ 2A_1 - 2M_1 &= \frac{3}{2}A_1 - \frac{3}{2}H_1 \\ -2M_1 &= -\frac{1}{2}A_1 - \frac{3}{2}H_1 \\ M_1 &= \frac{1}{4}(3H_1 + A_1) 3. :math:`Q_0'(1) = Q_1'(0)`. The derivatives of both quadratic curves should match at the point :math:`K`, in order for the final spline to be smooth. This gives: .. math:: Q_0'(1) &= Q_1'(0) \\ 2(K - M_0) &= 2(M_1 - K) \\ 2K - 2M_0 &= 2M_1 - 2K \\ 4K &= 2M_0 + 2M_1 \\ K &= \frac{1}{2}(M_0 + M_1) This is sufficient to find proper control points for the quadratic Bézier curves. Parameters ---------- a0 The start anchor of a single cubic Bézier curve, or an array of :math:`N` start anchors for :math:`N` curves. h0 The first handle of a single cubic Bézier curve, or an array of :math:`N` first handles for :math:`N` curves. h1 The second handle of a single cubic Bézier curve, or an array of :math:`N` second handles for :math:`N` curves. a1 The end anchor of a single cubic Bézier curve, or an array of :math:`N` end anchors for :math:`N` curves. Returns ------- result An array containing either 6 points for 2 quadratic Bézier curves approximating the original cubic curve, or :math:`6N` points for :math:`2N` quadratic curves approximating :math:`N` cubic curves. Raises ------ ValueError If ``a0``, ``h0``, ``h1`` and ``a1`` have different dimensions, or if their number of dimensions is not 1 or 2. """ a0c = np.asarray(a0) h0c = np.asarray(h0) h1c = np.asarray(h1) a1c = np.asarray(a1) if all(arr.ndim == 1 for arr in (a0c, h0c, h1c, a1c)): num_curves, dim = 1, a0c.shape[0] elif all(arr.ndim == 2 for arr in (a0c, h0c, h1c, a1c)): num_curves, dim = a0c.shape else: raise ValueError("All arguments must be Point3D or Point3D_Array.") m0 = 0.25 * (3 * h0c + a0c) m1 = 0.25 * (3 * h1c + a1c) k = 0.5 * (m0 + m1) result = np.empty((6 * num_curves, dim)) result[0::6] = a0c result[1::6] = m0 result[2::6] = k result[3::6] = k result[4::6] = m1 result[5::6] = a1c return result def is_closed(points: Point3D_Array) -> bool: """Returns ``True`` if the spline given by ``points`` is closed, by checking if its first and last points are close to each other, or``False`` otherwise. .. note:: This function reimplements :meth:`np.allclose`, because repeated calling of :meth:`np.allclose` for only 2 points is inefficient. Parameters ---------- points An array of points defining a spline. Returns ------- :class:`bool` Whether the first and last points of the array are close enough or not to be considered the same, thus considering the defined spline as closed. Examples -------- .. code-block:: pycon >>> import numpy as np >>> from manim import is_closed >>> is_closed( ... np.array( ... [ ... [0, 0, 0], ... [1, 2, 3], ... [3, 2, 1], ... [0, 0, 0], ... ] ... ) ... ) True >>> is_closed( ... np.array( ... [ ... [0, 0, 0], ... [1, 2, 3], ... [3, 2, 1], ... [1e-10, 1e-10, 1e-10], ... ] ... ) ... ) True >>> is_closed( ... np.array( ... [ ... [0, 0, 0], ... [1, 2, 3], ... [3, 2, 1], ... [1e-2, 1e-2, 1e-2], ... ] ... ) ... ) False """ start, end = points[0], points[-1] rtol = 1e-5 atol = 1e-8 tolerance = atol + rtol * start if abs(end[0] - start[0]) > tolerance[0]: return False if abs(end[1] - start[1]) > tolerance[1]: return False return bool(abs(end[2] - start[2]) <= tolerance[2]) def proportions_along_bezier_curve_for_point( point: Point3DLike, control_points: BezierPointsLike, round_to: float = 1e-6, ) -> MatrixMN: """Obtains the proportion along the bezier curve corresponding to a given point given the bezier curve's control points. The bezier polynomial is constructed using the coordinates of the given point as well as the bezier curve's control points. On solving the polynomial for each dimension, if there are roots common to every dimension, those roots give the proportion along the curve the point is at. If there are no real roots, the point does not lie on the curve. Parameters ---------- point The Cartesian Coordinates of the point whose parameter should be obtained. control_points The Cartesian Coordinates of the ordered control points of the bezier curve on which the point may or may not lie. round_to A float whose number of decimal places all values such as coordinates of points will be rounded. Returns ------- np.ndarray[float] List containing possible parameters (the proportions along the bezier curve) for the given point on the given bezier curve. This usually only contains one or zero elements, but if the point is, say, at the beginning/end of a closed loop, may return a list with more than 1 value, corresponding to the beginning and end etc. of the loop. Raises ------ :class:`ValueError` When ``point`` and the control points have different shapes. """ # Method taken from # http://polymathprogrammer.com/2012/04/03/does-point-lie-on-bezier-curve/ if not all(np.shape(point) == np.shape(c_p) for c_p in control_points): raise ValueError( f"Point {point} and Control Points {control_points} have different shapes.", ) control_points = np.array(control_points) n = len(control_points) - 1 roots = [] for dim, coord in enumerate(point): control_coords = control_points[:, dim] terms = [] for term_power in range(n, -1, -1): outercoeff = choose(n, term_power) term = [] sign = 1 for subterm_num in range(term_power, -1, -1): innercoeff = choose(term_power, subterm_num) * sign subterm = innercoeff * control_coords[subterm_num] if term_power == 0: subterm -= coord term.append(subterm) sign *= -1 terms.append(outercoeff * sum(np.array(term))) if all(term == 0 for term in terms): # Then both Bezier curve and Point lie on the same plane. # 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() if len(polynom_roots) > 0: polynom_roots = np.around(polynom_roots, int(np.log10(1 / round_to))) roots.append(polynom_roots) 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) result = np.asarray([r.real for r in roots if 0 <= r.real <= 1]) return result def point_lies_on_bezier( point: Point3DLike, control_points: BezierPointsLike, round_to: float = 1e-6, ) -> bool: """Checks if a given point lies on the bezier curves with the given control points. This is done by solving the bezier polynomial with the point as the constant term; if any real roots exist, the point lies on the bezier curve. Parameters ---------- point The Cartesian Coordinates of the point to check. control_points The Cartesian Coordinates of the ordered control points of the bezier curve on which the point may or may not lie. round_to A float whose number of decimal places all values such as coordinates of points will be rounded. Returns ------- bool Whether the point lies on the curve. """ roots = proportions_along_bezier_curve_for_point(point, control_points, round_to) return len(roots) > 0 ================================================ FILE: manim/utils/caching.py ================================================ from __future__ import annotations from collections.abc import Callable from typing import TYPE_CHECKING, Any from .. import config, logger from ..utils.hashing import get_hash_from_play_call __all__ = ["handle_caching_play"] if TYPE_CHECKING: from manim.renderer.opengl_renderer import OpenGLRenderer from manim.scene.scene import Scene def handle_caching_play(func: Callable[..., None]) -> Callable[..., None]: """Decorator that returns a wrapped version of func that will compute the hash of the play invocation. The returned function will act according to the computed hash: either skip the animation because it's already cached, or let the invoked function play normally. Parameters ---------- func 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, # the play logic of the latter has to be refactored in the same way the cairo renderer has been, and thus this # method has to be deleted. def wrapper(self: OpenGLRenderer, scene: Scene, *args: Any, **kwargs: Any) -> None: self.skip_animations = self._original_skipping_status self.update_skipping_status() animations = scene.compile_animations(*args, **kwargs) scene.add_mobjects_from_animations(animations) if self.skip_animations: logger.debug(f"Skipping animation {self.num_plays}") func(self, scene, *args, **kwargs) # If the animation is skipped, we mark its hash as None. # When sceneFileWriter will start combining partial movie files, it won't take into account None hashes. self.animations_hashes.append(None) self.file_writer.add_partial_movie_file(None) return if not config["disable_caching"]: mobjects_on_scene = scene.mobjects hash_play = get_hash_from_play_call( scene, self.camera, animations, mobjects_on_scene, ) if self.file_writer.is_already_cached(hash_play): logger.info( f"Animation {self.num_plays} : Using cached data (hash : %(hash_play)s)", {"hash_play": hash_play}, ) self.skip_animations = True else: hash_play = f"uncached_{self.num_plays:05}" self.animations_hashes.append(hash_play) self.file_writer.add_partial_movie_file(hash_play) logger.debug( "List of the first few animation hashes of the scene: %(h)s", {"h": str(self.animations_hashes[:5])}, ) func(self, scene, *args, **kwargs) return wrapper ================================================ FILE: manim/utils/color/AS2700.py ================================================ """Australian Color Standard In 1985 the Australian Independent Color Standard AS 2700 was created. In this standard, all colors can be identified via a category code (one of B -- Blue, G -- Green, N -- Neutrals (grey), P -- Purple, R -- Red, T -- Blue/Green, X -- Yellow/Red, Y -- Yellow) and a number. The colors also have (natural) names. To use the colors from this list, access them directly from the module (which is exposed to Manim's global name space): .. code:: pycon >>> from manim import AS2700 >>> AS2700.B23_BRIGHT_BLUE ManimColor('#174F90') List of Color Constants ----------------------- These hex values (taken from https://www.w3schools.com/colors/colors_australia.asp) are non official approximate values intended to simulate AS 2700 colors: .. automanimcolormodule:: manim.utils.color.AS2700 """ from __future__ import annotations from .core import ManimColor B11_RICH_BLUE = ManimColor("#2B3770") B12_ROYAL_BLUE = ManimColor("#2C3563") B13_NAVY_BLUE = ManimColor("#28304D") B14_SAPHHIRE = ManimColor("#28426B") B15_MID_BLUE = ManimColor("#144B6F") B21_ULTRAMARINE = ManimColor("#2C5098") B22_HOMEBUSH_BLUE = ManimColor("#215097") B23_BRIGHT_BLUE = ManimColor("#174F90") B24_HARBOUR_BLUE = ManimColor("#1C6293") B25_AQUA = ManimColor("#5097AC") B32_POWDER_BLUE = ManimColor("#B7C8DB") B33_MIST_BLUE = ManimColor("#E0E6E2") B34_PARADISE_BLUE = ManimColor("#3499BA") B35_PALE_BLUE = ManimColor("#CDE4E2") B41_BLUEBELL = ManimColor("#5B94D1") B42_PURPLE_BLUE = ManimColor("#5E7899") B43_GREY_BLUE = ManimColor("#627C8D") B44_LIGHT_GREY_BLUE = ManimColor("#C0C0C1") B45_SKY_BLUE = ManimColor("#7DB7C7") B51_PERIWINKLE = ManimColor("#3871AC") B53_DARK_GREY_BLUE = ManimColor("#4F6572") B55_STORM_BLUE = ManimColor("#3F7C94") B61_CORAL_SEA = ManimColor("#2B3873") B62_MIDNIGHT_BLUE = ManimColor("#292A34") B64_CHARCOAL = ManimColor("#363E45") G11_BOTTLE_GREEN = ManimColor("#253A32") G12_HOLLY = ManimColor("#21432D") G13_EMERALD = ManimColor("#195F35") G14_MOSS_GREEN = ManimColor("#33572D") G15_RAINFOREST_GREEN = ManimColor("#3D492D") G16_TRAFFIC_GREEN = ManimColor("#305442") G17_MINT_GREEN = ManimColor("#006B45") G21_JADE = ManimColor("#127453") G22_SERPENTINE = ManimColor("#78A681") G23_SHAMROCK = ManimColor("#336634") G24_FERN_TREE = ManimColor("#477036") G25_OLIVE = ManimColor("#595B2A") G26_APPLE_GREEN = ManimColor("#4E9843") G27_HOMEBUSH_GREEN = ManimColor("#017F4D") G31_VERTIGRIS = ManimColor("#468A65") G32_OPALINE = ManimColor("#AFCBB8") G33_LETTUCE = ManimColor("#7B9954") G34_AVOCADO = ManimColor("#757C4C") G35_LIME_GREEN = ManimColor("#89922E") G36_KIKUYU = ManimColor("#95B43B") G37_BEANSTALK = ManimColor("#45A56A") G41_LAWN_GREEN = ManimColor("#0D875D") G42_GLACIER = ManimColor("#D5E1D2") G43_SURF_GREEN = ManimColor("#C8C8A7") G44_PALM_GREEN = ManimColor("#99B179") G45_CHARTREUSE = ManimColor("#C7C98D") G46_CITRONELLA = ManimColor("#BFC83E") G47_CRYSTAL_GREEN = ManimColor("#ADCCA8") G51_SPRUCE = ManimColor("#05674F") G52_EUCALYPTUS = ManimColor("#66755B") G53_BANKSIA = ManimColor("#929479") G54_MIST_GREEN = ManimColor("#7A836D") G55_LICHEN = ManimColor("#A7A98C") G56_SAGE_GREEN = ManimColor("#677249") G61_DARK_GREEN = ManimColor("#283533") G62_RIVERGUM = ManimColor("#617061") G63_DEEP_BRONZE_GREEN = ManimColor("#333334") G64_SLATE = ManimColor("#5E6153") G65_TI_TREE = ManimColor("#5D5F4E") G66_ENVIRONMENT_GREEN = ManimColor("#484C3F") G67_ZUCCHINI = ManimColor("#2E443A") N11_PEARL_GREY = ManimColor("#D8D3C7") N12_PASTEL_GREY = ManimColor("#CCCCCC") N14_WHITE = ManimColor("#FFFFFF") N15_HOMEBUSH_GREY = ManimColor("#A29B93") N22_CLOUD_GREY = ManimColor("#C4C1B9") N23_NEUTRAL_GREY = ManimColor("#CCCCCC") N24_SILVER_GREY = ManimColor("#BDC7C5") N25_BIRCH_GREY = ManimColor("#ABA498") N32_GREEN_GREY = ManimColor("#8E9282") N33_LIGHTBOX_GREY = ManimColor("#ACADAD") N35_LIGHT_GREY = ManimColor("#A6A7A1") N41_OYSTER = ManimColor("#998F78") N42_STORM_GREY = ManimColor("#858F88") N43_PIPELINE_GREY = ManimColor("#999999") N44_BRIDGE_GREY = ManimColor("#767779") N45_KOALA_GREY = ManimColor("#928F88") N52_MID_GREY = ManimColor("#727A77") N53_BLUE_GREY = ManimColor("#7C8588") N54_BASALT = ManimColor("#585C63") N55_LEAD_GREY = ManimColor("#5E5C58") N61_BLACK = ManimColor("#2A2A2C") N63_PEWTER = ManimColor("#596064") N64_DARK_GREY = ManimColor("#4B5259") N65_GRAPHITE_GREY = ManimColor("#45474A") P11_MAGENTA = ManimColor("#7B2B48") P12_PURPLE = ManimColor("#85467B") P13_VIOLET = ManimColor("#5D3A61") P14_BLUEBERRY = ManimColor("#4C4176") P21_SUNSET_PINK = ManimColor("#E3BBBD") P22_CYCLAMEN = ManimColor("#83597D") P23_LILAC = ManimColor("#A69FB1") P24_JACKARANDA = ManimColor("#795F91") P31_DUSTY_PINK = ManimColor("#DBBEBC") P33_RIBBON_PINK = ManimColor("#D1BCC9") P41_ERICA_PINK = ManimColor("#C55A83") P42_MULBERRY = ManimColor("#A06574") P43_WISTERIA = ManimColor("#756D91") P52_PLUM = ManimColor("#6E3D4B") R11_INTERNATIONAL_ORANGE = ManimColor("#CE482A") R12_SCARLET = ManimColor("#CD392A") R13_SIGNAL_RED = ManimColor("#BA312B") R14_WARATAH = ManimColor("#AA2429") R15_CRIMSON = ManimColor("#9E2429") R21_TANGERINE = ManimColor("#E96957") R22_HOMEBUSH_RED = ManimColor("#D83A2D") R23_LOLLIPOP = ManimColor("#CC5058") R24_STRAWBERRY = ManimColor("#B4292A") R25_ROSE_PINK = ManimColor("#E8919C") R32_APPLE_BLOSSOM = ManimColor("#F2E1D8") R33_GHOST_GUM = ManimColor("#E8DAD4") R34_MUSHROOM = ManimColor("#D7C0B6") R35_DEEP_ROSE = ManimColor("#CD6D71") R41_SHELL_PINK = ManimColor("#F9D9BB") R42_SALMON_PINK = ManimColor("#D99679") R43_RED_DUST = ManimColor("#D0674F") R44_POSSUM = ManimColor("#A18881") R45_RUBY = ManimColor("#8F3E5C") R51_BURNT_PINK = ManimColor("#E19B8E") R52_TERRACOTTA = ManimColor("#A04C36") R53_RED_GUM = ManimColor("#8D4338") R54_RASPBERRY = ManimColor("#852F31") R55_CLARET = ManimColor("#67292D") R62_VENETIAN_RED = ManimColor("#77372B") R63_RED_OXIDE = ManimColor("#663334") R64_DEEP_INDIAN_RED = ManimColor("#542E2B") R65_MAROON = ManimColor("#3F2B3C") T11_TROPICAL_BLUE = ManimColor("#006698") T12_DIAMANTIA = ManimColor("#006C74") T14_MALACHITE = ManimColor("#105154") T15_TURQUOISE = ManimColor("#098587") T22_ORIENTAL_BLUE = ManimColor("#358792") T24_BLUE_JADE = ManimColor("#427F7E") T32_HUON_GREEN = ManimColor("#72B3B1") T33_SMOKE_BLUE = ManimColor("#9EB6B2") T35_GREEN_ICE = ManimColor("#78AEA2") T44_BLUE_GUM = ManimColor("#6A8A88") T45_COOTAMUNDRA = ManimColor("#759E91") T51_MOUNTAIN_BLUE = ManimColor("#295668") T53_PEACOCK_BLUE = ManimColor("#245764") T63_TEAL = ManimColor("#183F4E") X11_BUTTERSCOTCH = ManimColor("#D38F43") X12_PUMPKIN = ManimColor("#DD7E1A") X13_MARIGOLD = ManimColor("#ED7F15") X14_MANDARIN = ManimColor("#E45427") X15_ORANGE = ManimColor("#E36C2B") X21_PALE_OCHRE = ManimColor("#DAA45F") X22_SAFFRON = ManimColor("#F6AA51") X23_APRICOT = ManimColor("#FEB56D") X24_ROCKMELON = ManimColor("#F6894B") X31_RAFFIA = ManimColor("#EBC695") X32_MAGNOLIA = ManimColor("#F1DEBE") X33_WARM_WHITE = ManimColor("#F3E7D4") X34_DRIFTWOOD = ManimColor("#D5C4AE") X41_BUFF = ManimColor("#C28A44") X42_BISCUIT = ManimColor("#DEBA92") X43_BEIGE = ManimColor("#C9AA8C") X45_CINNAMON = ManimColor("#AC826D") X51_TAN = ManimColor("#8F5F32") X52_COFFEE = ManimColor("#AD7948") X53_GOLDEN_TAN = ManimColor("#925629") X54_BROWN = ManimColor("#68452C") X55_NUT_BROWN = ManimColor("#764832") X61_WOMBAT = ManimColor("#6E5D52") X62_DARK_EARTH = ManimColor("#6E5D52") X63_IRONBARK = ManimColor("#443B36") X64_CHOCOLATE = ManimColor("#4A3B31") X65_DARK_BROWN = ManimColor("#4F372D") Y11_CANARY = ManimColor("#E7BD11") Y12_WATTLE = ManimColor("#E8AF01") Y13_VIVID_YELLOW = ManimColor("#FCAE01") Y14_GOLDEN_YELLOW = ManimColor("#F5A601") Y15_SUNFLOWER = ManimColor("#FFA709") Y16_INCA_GOLD = ManimColor("#DF8C19") Y21_PRIMROSE = ManimColor("#F5CF5B") Y22_CUSTARD = ManimColor("#EFD25C") Y23_BUTTERCUP = ManimColor("#E0CD41") Y24_STRAW = ManimColor("#E3C882") Y25_DEEP_CREAM = ManimColor("#F3C968") Y26_HOMEBUSH_GOLD = ManimColor("#FCC51A") Y31_LILY_GREEN = ManimColor("#E3E3CD") Y32_FLUMMERY = ManimColor("#E6DF9E") Y33_PALE_PRIMROSE = ManimColor("#F5F3CE") Y34_CREAM = ManimColor("#EFE3BE") Y35_OFF_WHITE = ManimColor("#F1E9D5") Y41_OLIVE_YELLOW = ManimColor("#8E7426") Y42_MUSTARD = ManimColor("#C4A32E") Y43_PARCHMENT = ManimColor("#D4C9A3") Y44_SAND = ManimColor("#DCC18B") Y45_MANILLA = ManimColor("#E5D0A7") Y51_BRONZE_OLIVE = ManimColor("#695D3E") Y52_CHAMOIS = ManimColor("#BEA873") Y53_SANDSTONE = ManimColor("#D5BF8E") Y54_OATMEAL = ManimColor("#CAAE82") Y55_DEEP_STONE = ManimColor("#BC9969") Y56_MERINO = ManimColor("#C9B79E") Y61_BLACK_OLIVE = ManimColor("#47473B") Y62_SUGAR_CANE = ManimColor("#BCA55C") Y63_KHAKI = ManimColor("#826843") Y65_MUSHROOM = ManimColor("#A39281") Y66_MUDSTONE = ManimColor("#574E45") ================================================ FILE: manim/utils/color/BS381.py ================================================ """British Color Standard This module contains colors defined in one of the British Standards for colors, BS381C. This standard specifies colors used in identification, coding, and other special purposes. See https://www.britishstandardcolour.com/ for more information. To use the colors from this list, access them directly from the module (which is exposed to Manim's global name space): .. code:: pycon >>> from manim import BS381 >>> BS381.OXFORD_BLUE ManimColor('#1F3057') List of Color Constants ----------------------- These hex values (taken from https://www.w3schools.com/colors/colors_british.asp) are non official approximate values intended to simulate the ones defined in the standard: .. automanimcolormodule:: manim.utils.color.BS381 """ from __future__ import annotations from .core import ManimColor BS381_101 = ManimColor("#94BFAC") SKY_BLUE = ManimColor("#94BFAC") BS381_102 = ManimColor("#5B9291") TURQUOISE_BLUE = ManimColor("#5B9291") BS381_103 = ManimColor("#3B6879") PEACOCK_BLUE = ManimColor("#3B6879") BS381_104 = ManimColor("#264D7E") AZURE_BLUE = ManimColor("#264D7E") BS381_105 = ManimColor("#1F3057") OXFORD_BLUE = ManimColor("#1F3057") BS381_106 = ManimColor("#2A283D") ROYAL_BLUE = ManimColor("#2A283D") BS381_107 = ManimColor("#3A73A9") STRONG_BLUE = ManimColor("#3A73A9") BS381_108 = ManimColor("#173679") AIRCRAFT_BLUE = ManimColor("#173679") BS381_109 = ManimColor("#1C5680") MIDDLE_BLUE = ManimColor("#1C5680") BS381_110 = ManimColor("#2C3E75") ROUNDEL_BLUE = ManimColor("#2C3E75") BS381_111 = ManimColor("#8CC5BB") PALE_BLUE = ManimColor("#8CC5BB") BS381_112 = ManimColor("#78ADC2") ARCTIC_BLUE = ManimColor("#78ADC2") FIESTA_BLUE = ManimColor("#78ADC2") BS381_113 = ManimColor("#3F687D") DEEP_SAXE_BLUE = ManimColor("#3F687D") BS381_114 = ManimColor("#1F4B61") RAIL_BLUE = ManimColor("#1F4B61") BS381_115 = ManimColor("#5F88C1") COBALT_BLUE = ManimColor("#5F88C1") BS381_166 = ManimColor("#2458AF") FRENCH_BLUE = ManimColor("#2458AF") BS381_169 = ManimColor("#135B75") TRAFFIC_BLUE = ManimColor("#135B75") BS381_172 = ManimColor("#A7C6EB") PALE_ROUNDEL_BLUE = ManimColor("#A7C6EB") BS381_174 = ManimColor("#64A0AA") ORIENT_BLUE = ManimColor("#64A0AA") BS381_175 = ManimColor("#4F81C5") LIGHT_FRENCH_BLUE = ManimColor("#4F81C5") BS381_210 = ManimColor("#BBC9A5") SKY = ManimColor("#BBC9A5") BS381_216 = ManimColor("#BCD890") EAU_DE_NIL = ManimColor("#BCD890") BS381_217 = ManimColor("#96BF65") SEA_GREEN = ManimColor("#96BF65") BS381_218 = ManimColor("#698B47") GRASS_GREEN = ManimColor("#698B47") BS381_219 = ManimColor("#757639") SAGE_GREEN = ManimColor("#757639") BS381_220 = ManimColor("#4B5729") OLIVE_GREEN = ManimColor("#4B5729") BS381_221 = ManimColor("#507D3A") BRILLIANT_GREEN = ManimColor("#507D3A") BS381_222 = ManimColor("#6A7031") LIGHT_BRONZE_GREEN = ManimColor("#6A7031") BS381_223 = ManimColor("#49523A") MIDDLE_BRONZE_GREEN = ManimColor("#49523A") BS381_224 = ManimColor("#3E4630") DEEP_BRONZE_GREEN = ManimColor("#3E4630") BS381_225 = ManimColor("#406A28") LIGHT_BRUNSWICK_GREEN = ManimColor("#406A28") BS381_226 = ManimColor("#33533B") MID_BRUNSWICK_GREEN = ManimColor("#33533B") BS381_227 = ManimColor("#254432") DEEP_BRUNSWICK_GREEN = ManimColor("#254432") BS381_228 = ManimColor("#428B64") EMERALD_GREEN = ManimColor("#428B64") BS381_241 = ManimColor("#4F5241") DARK_GREEN = ManimColor("#4F5241") BS381_262 = ManimColor("#44945E") BOLD_GREEN = ManimColor("#44945E") BS381_267 = ManimColor("#476A4C") DEEP_CHROME_GREEN = ManimColor("#476A4C") TRAFFIC_GREEN = ManimColor("#476A4C") BS381_275 = ManimColor("#8FC693") OPALINE_GREEN = ManimColor("#8FC693") BS381_276 = ManimColor("#2E4C1E") LINCON_GREEN = ManimColor("#2E4C1E") BS381_277 = ManimColor("#364A20") CYPRESS_GREEN = ManimColor("#364A20") BS381_278 = ManimColor("#87965A") LIGHT_OLIVE_GREEN = ManimColor("#87965A") BS381_279 = ManimColor("#3B3629") STEEL_FURNITURE_GREEN = ManimColor("#3B3629") BS381_280 = ManimColor("#68AB77") VERDIGRIS_GREEN = ManimColor("#68AB77") BS381_282 = ManimColor("#506B52") FOREST_GREEN = ManimColor("#506B52") BS381_283 = ManimColor("#7E8F6E") AIRCRAFT_GREY_GREEN = ManimColor("#7E8F6E") BS381_284 = ManimColor("#6B6F5A") SPRUCE_GREEN = ManimColor("#6B6F5A") BS381_285 = ManimColor("#5F5C4B") NATO_GREEN = ManimColor("#5F5C4B") BS381_298 = ManimColor("#4F5138") OLIVE_DRAB = ManimColor("#4F5138") BS381_309 = ManimColor("#FEEC04") CANARY_YELLOW = ManimColor("#FEEC04") BS381_310 = ManimColor("#FEF963") PRIMROSE = ManimColor("#FEF963") BS381_315 = ManimColor("#FEF96A") GRAPEFRUIT = ManimColor("#FEF96A") BS381_320 = ManimColor("#9E7339") LIGHT_BROWN = ManimColor("#9E7339") BS381_337 = ManimColor("#4C4A3C") VERY_DARK_DRAB = ManimColor("#4C4A3C") BS381_350 = ManimColor("#7B6B4F") DARK_EARTH = ManimColor("#7B6B4F") BS381_352 = ManimColor("#FCED96") PALE_CREAM = ManimColor("#FCED96") BS381_353 = ManimColor("#FDF07A") DEEP_CREAM = ManimColor("#FDF07A") BS381_354 = ManimColor("#E9BB43") PRIMROSE_2 = ManimColor("#E9BB43") BS381_355 = ManimColor("#FDD906") LEMON = ManimColor("#FDD906") BS381_356 = ManimColor("#FCC808") GOLDEN_YELLOW = ManimColor("#FCC808") BS381_358 = ManimColor("#F6C870") LIGHT_BUFF = ManimColor("#F6C870") BS381_359 = ManimColor("#DBAC50") MIDDLE_BUFF = ManimColor("#DBAC50") BS381_361 = ManimColor("#D4B97D") LIGHT_STONE = ManimColor("#D4B97D") BS381_362 = ManimColor("#AC7C42") MIDDLE_STONE = ManimColor("#AC7C42") BS381_363 = ManimColor("#FDE706") BOLD_YELLOW = ManimColor("#FDE706") BS381_364 = ManimColor("#CEC093") PORTLAND_STONE = ManimColor("#CEC093") BS381_365 = ManimColor("#F4F0BD") VELLUM = ManimColor("#F4F0BD") BS381_366 = ManimColor("#F5E7A1") LIGHT_BEIGE = ManimColor("#F5E7A1") BS381_367 = ManimColor("#FEF6BF") MANILLA = ManimColor("#fef6bf") BS381_368 = ManimColor("#DD7B00") TRAFFIC_YELLOW = ManimColor("#DD7B00") BS381_369 = ManimColor("#FEEBA8") BISCUIT = ManimColor("#feeba8") BS381_380 = ManimColor("#BBA38A") CAMOUFLAGE_DESERT_SAND = ManimColor("#BBA38A") BS381_384 = ManimColor("#EEDFA5") LIGHT_STRAW = ManimColor("#EEDFA5") BS381_385 = ManimColor("#E8C88F") LIGHT_BISCUIT = ManimColor("#E8C88F") BS381_386 = ManimColor("#E6C18D") CHAMPAGNE = ManimColor("#e6c18d") BS381_387 = ManimColor("#CFB48A") SUNRISE = ManimColor("#cfb48a") SUNSHINE = ManimColor("#cfb48a") BS381_388 = ManimColor("#E4CF93") BEIGE = ManimColor("#e4cf93") BS381_389 = ManimColor("#B2A788") CAMOUFLAGE_BEIGE = ManimColor("#B2A788") BS381_397 = ManimColor("#F3D163") JASMINE_YELLOW = ManimColor("#F3D163") BS381_411 = ManimColor("#74542F") MIDDLE_BROWN = ManimColor("#74542F") BS381_412 = ManimColor("#5C422E") DARK_BROWN = ManimColor("#5C422E") BS381_413 = ManimColor("#402D21") NUT_BROWN = ManimColor("#402D21") BS381_414 = ManimColor("#A86C29") GOLDEN_BROWN = ManimColor("#A86C29") BS381_415 = ManimColor("#61361E") IMPERIAL_BROWN = ManimColor("#61361E") BS381_420 = ManimColor("#A89177") DARK_CAMOUFLAGE_DESERT_SAND = ManimColor("#A89177") BS381_435 = ManimColor("#845B4D") CAMOUFLAGE_RED = ManimColor("#845B4D") BS381_436 = ManimColor("#564B47") DARK_CAMOUFLAGE_BROWN = ManimColor("#564B47") BS381_439 = ManimColor("#753B1E") ORANGE_BROWN = ManimColor("#753B1E") BS381_443 = ManimColor("#C98A71") SALMON = ManimColor("#c98a71") BS381_444 = ManimColor("#A65341") TERRACOTTA = ManimColor("#a65341") BS381_445 = ManimColor("#83422B") VENETIAN_RED = ManimColor("#83422B") BS381_446 = ManimColor("#774430") RED_OXIDE = ManimColor("#774430") BS381_447 = ManimColor("#F3B28B") SALMON_PINK = ManimColor("#F3B28B") BS381_448 = ManimColor("#67403A") DEEP_INDIAN_RED = ManimColor("#67403A") BS381_449 = ManimColor("#693B3F") LIGHT_PURPLE_BROWN = ManimColor("#693B3F") BS381_452 = ManimColor("#613339") DARK_CRIMSON = ManimColor("#613339") BS381_453 = ManimColor("#FBDED6") SHELL_PINK = ManimColor("#FBDED6") BS381_454 = ManimColor("#E8A1A2") PALE_ROUNDEL_RED = ManimColor("#E8A1A2") BS381_460 = ManimColor("#BD8F56") DEEP_BUFF = ManimColor("#BD8F56") BS381_473 = ManimColor("#793932") GULF_RED = ManimColor("#793932") BS381_489 = ManimColor("#8D5B41") LEAF_BROWN = ManimColor("#8D5B41") BS381_490 = ManimColor("#573320") BEECH_BROWN = ManimColor("#573320") BS381_499 = ManimColor("#59493E") SERVICE_BROWN = ManimColor("#59493E") BS381_536 = ManimColor("#BB3016") POPPY = ManimColor("#bb3016") BS381_537 = ManimColor("#DD3420") SIGNAL_RED = ManimColor("#DD3420") BS381_538 = ManimColor("#C41C22") POST_OFFICE_RED = ManimColor("#C41C22") CHERRY = ManimColor("#c41c22") BS381_539 = ManimColor("#D21E2B") CURRANT_RED = ManimColor("#D21E2B") BS381_540 = ManimColor("#8B1A32") CRIMSON = ManimColor("#8b1a32") BS381_541 = ManimColor("#471B21") MAROON = ManimColor("#471b21") BS381_542 = ManimColor("#982D57") RUBY = ManimColor("#982d57") BS381_557 = ManimColor("#EF841E") LIGHT_ORANGE = ManimColor("#EF841E") BS381_564 = ManimColor("#DD3524") BOLD_RED = ManimColor("#DD3524") BS381_568 = ManimColor("#FB9C06") APRICOT = ManimColor("#fb9c06") BS381_570 = ManimColor("#A83C19") TRAFFIC_RED = ManimColor("#A83C19") BS381_591 = ManimColor("#D04E09") DEEP_ORANGE = ManimColor("#D04E09") BS381_592 = ManimColor("#E45523") INTERNATIONAL_ORANGE = ManimColor("#E45523") BS381_593 = ManimColor("#F24816") RAIL_RED = ManimColor("#F24816") AZO_ORANGE = ManimColor("#F24816") BS381_626 = ManimColor("#A0A9AA") CAMOUFLAGE_GREY = ManimColor("#A0A9AA") BS381_627 = ManimColor("#BEC0B8") LIGHT_AIRCRAFT_GREY = ManimColor("#BEC0B8") BS381_628 = ManimColor("#9D9D7E") SILVER_GREY = ManimColor("#9D9D7E") BS381_629 = ManimColor("#7A838B") DARK_CAMOUFLAGE_GREY = ManimColor("#7A838B") BS381_630 = ManimColor("#A5AD98") FRENCH_GREY = ManimColor("#A5AD98") BS381_631 = ManimColor("#9AAA9F") LIGHT_GREY = ManimColor("#9AAA9F") BS381_632 = ManimColor("#6B7477") DARK_ADMIRALTY_GREY = ManimColor("#6B7477") BS381_633 = ManimColor("#424C53") RAF_BLUE_GREY = ManimColor("#424C53") BS381_634 = ManimColor("#6F7264") SLATE = ManimColor("#6f7264") BS381_635 = ManimColor("#525B55") LEAD = ManimColor("#525b55") BS381_636 = ManimColor("#5F7682") PRU_BLUE = ManimColor("#5F7682") BS381_637 = ManimColor("#8E9B9C") MEDIUM_SEA_GREY = ManimColor("#8E9B9C") BS381_638 = ManimColor("#6C7377") DARK_SEA_GREY = ManimColor("#6C7377") BS381_639 = ManimColor("#667563") LIGHT_SLATE_GREY = ManimColor("#667563") BS381_640 = ManimColor("#566164") EXTRA_DARK_SEA_GREY = ManimColor("#566164") BS381_642 = ManimColor("#282B2F") NIGHT = ManimColor("#282b2f") BS381_671 = ManimColor("#4E5355") MIDDLE_GRAPHITE = ManimColor("#4E5355") BS381_676 = ManimColor("#A9B7B9") LIGHT_WEATHERWORK_GREY = ManimColor("#A9B7B9") BS381_677 = ManimColor("#676F76") DARK_WEATHERWORK_GREY = ManimColor("#676F76") BS381_692 = ManimColor("#7B93A3") SMOKE_GREY = ManimColor("#7B93A3") BS381_693 = ManimColor("#88918D") AIRCRAFT_GREY = ManimColor("#88918D") BS381_694 = ManimColor("#909A92") DOVE_GREY = ManimColor("#909A92") BS381_697 = ManimColor("#B6D3CC") LIGHT_ADMIRALTY_GREY = ManimColor("#B6D3CC") BS381_796 = ManimColor("#6E4A75") DARK_VIOLET = ManimColor("#6E4A75") BS381_797 = ManimColor("#C9A8CE") LIGHT_VIOLET = ManimColor("#C9A8CE") ================================================ FILE: manim/utils/color/DVIPSNAMES.py ================================================ r"""dvips Colors This module contains the colors defined in the dvips driver, which are commonly accessed as named colors in LaTeX via the ``\usepackage[dvipsnames]{xcolor}`` package. To use the colors from this list, access them directly from the module (which is exposed to Manim's global name space): .. code:: pycon >>> from manim import DVIPSNAMES >>> DVIPSNAMES.DARKORCHID ManimColor('#A4538A') List of Color Constants ----------------------- These hex values are derived from those specified in the ``xcolor`` package documentation (see https://ctan.org/pkg/xcolor): .. automanimcolormodule:: manim.utils.color.DVIPSNAMES """ from __future__ import annotations from .core import ManimColor AQUAMARINE = ManimColor("#00B5BE") BITTERSWEET = ManimColor("#C04F17") APRICOT = ManimColor("#FBB982") BLACK = ManimColor("#221E1F") BLUE = ManimColor("#2D2F92") BLUEGREEN = ManimColor("#00B3B8") BLUEVIOLET = ManimColor("#473992") BRICKRED = ManimColor("#B6321C") BROWN = ManimColor("#792500") BURNTORANGE = ManimColor("#F7921D") CADETBLUE = ManimColor("#74729A") CARNATIONPINK = ManimColor("#F282B4") CERULEAN = ManimColor("#00A2E3") CORNFLOWERBLUE = ManimColor("#41B0E4") CYAN = ManimColor("#00AEEF") DANDELION = ManimColor("#FDBC42") DARKORCHID = ManimColor("#A4538A") EMERALD = ManimColor("#00A99D") FORESTGREEN = ManimColor("#009B55") FUCHSIA = ManimColor("#8C368C") GOLDENROD = ManimColor("#FFDF42") GRAY = ManimColor("#949698") GREEN = ManimColor("#00A64F") GREENYELLOW = ManimColor("#DFE674") JUNGLEGREEN = ManimColor("#00A99A") LAVENDER = ManimColor("#F49EC4") LIMEGREEN = ManimColor("#8DC73E") MAGENTA = ManimColor("#EC008C") MAHOGANY = ManimColor("#A9341F") MAROON = ManimColor("#AF3235") MELON = ManimColor("#F89E7B") MIDNIGHTBLUE = ManimColor("#006795") MULBERRY = ManimColor("#A93C93") NAVYBLUE = ManimColor("#006EB8") OLIVEGREEN = ManimColor("#3C8031") ORANGE = ManimColor("#F58137") ORANGERED = ManimColor("#ED135A") ORCHID = ManimColor("#AF72B0") PEACH = ManimColor("#F7965A") PERIWINKLE = ManimColor("#7977B8") PINEGREEN = ManimColor("#008B72") PLUM = ManimColor("#92268F") PROCESSBLUE = ManimColor("#00B0F0") PURPLE = ManimColor("#99479B") RAWSIENNA = ManimColor("#974006") RED = ManimColor("#ED1B23") REDORANGE = ManimColor("#F26035") REDVIOLET = ManimColor("#A1246B") RHODAMINE = ManimColor("#EF559F") ROYALBLUE = ManimColor("#0071BC") ROYALPURPLE = ManimColor("#613F99") RUBINERED = ManimColor("#ED017D") SALMON = ManimColor("#F69289") SEAGREEN = ManimColor("#3FBC9D") SEPIA = ManimColor("#671800") SKYBLUE = ManimColor("#46C5DD") SPRINGGREEN = ManimColor("#C6DC67") TAN = ManimColor("#DA9D76") TEALBLUE = ManimColor("#00AEB3") THISTLE = ManimColor("#D883B7") TURQUOISE = ManimColor("#00B4CE") VIOLET = ManimColor("#58429B") VIOLETRED = ManimColor("#EF58A0") WHITE = ManimColor("#FFFFFF") WILDSTRAWBERRY = ManimColor("#EE2967") YELLOW = ManimColor("#FFF200") YELLOWGREEN = ManimColor("#98CC70") YELLOWORANGE = ManimColor("#FAA21A") ================================================ FILE: manim/utils/color/SVGNAMES.py ================================================ r"""SVG 1.1 Colors This module contains the colors defined in the SVG 1.1 specification, which are commonly accessed as named colors in LaTeX via the ``\usepackage[svgnames]{xcolor}`` package. To use the colors from this list, access them directly from the module (which is exposed to Manim's global name space): .. code:: pycon >>> from manim import SVGNAMES >>> SVGNAMES.LIGHTCORAL ManimColor('#EF7F7F') List of Color Constants ----------------------- These hex values are derived from those specified in the ``xcolor`` package documentation (see https://ctan.org/pkg/xcolor): .. automanimcolormodule:: manim.utils.color.SVGNAMES """ from __future__ import annotations from .core import ManimColor ALICEBLUE = ManimColor("#EFF7FF") ANTIQUEWHITE = ManimColor("#F9EAD7") AQUA = ManimColor("#00FFFF") AQUAMARINE = ManimColor("#7EFFD3") AZURE = ManimColor("#EFFFFF") BEIGE = ManimColor("#F4F4DC") BISQUE = ManimColor("#FFE3C4") BLACK = ManimColor("#000000") BLANCHEDALMOND = ManimColor("#FFEACD") BLUE = ManimColor("#0000FF") BLUEVIOLET = ManimColor("#892BE2") BROWN = ManimColor("#A52A2A") BURLYWOOD = ManimColor("#DDB787") CADETBLUE = ManimColor("#5E9EA0") CHARTREUSE = ManimColor("#7EFF00") CHOCOLATE = ManimColor("#D2681D") CORAL = ManimColor("#FF7E4F") CORNFLOWERBLUE = ManimColor("#6395ED") CORNSILK = ManimColor("#FFF7DC") CRIMSON = ManimColor("#DC143B") CYAN = ManimColor("#00FFFF") DARKBLUE = ManimColor("#00008A") DARKCYAN = ManimColor("#008A8A") DARKGOLDENROD = ManimColor("#B7850B") DARKGRAY = ManimColor("#A9A9A9") DARKGREEN = ManimColor("#006300") DARKGREY = ManimColor("#A9A9A9") DARKKHAKI = ManimColor("#BCB66B") DARKMAGENTA = ManimColor("#8A008A") DARKOLIVEGREEN = ManimColor("#546B2F") DARKORANGE = ManimColor("#FF8C00") DARKORCHID = ManimColor("#9931CC") DARKRED = ManimColor("#8A0000") DARKSALMON = ManimColor("#E8967A") DARKSEAGREEN = ManimColor("#8EBB8E") DARKSLATEBLUE = ManimColor("#483D8A") DARKSLATEGRAY = ManimColor("#2F4F4F") DARKSLATEGREY = ManimColor("#2F4F4F") DARKTURQUOISE = ManimColor("#00CED1") DARKVIOLET = ManimColor("#9300D3") DEEPPINK = ManimColor("#FF1492") DEEPSKYBLUE = ManimColor("#00BFFF") DIMGRAY = ManimColor("#686868") DIMGREY = ManimColor("#686868") DODGERBLUE = ManimColor("#1D90FF") FIREBRICK = ManimColor("#B12121") FLORALWHITE = ManimColor("#FFF9EF") FORESTGREEN = ManimColor("#218A21") FUCHSIA = ManimColor("#FF00FF") GAINSBORO = ManimColor("#DCDCDC") GHOSTWHITE = ManimColor("#F7F7FF") GOLD = ManimColor("#FFD700") GOLDENROD = ManimColor("#DAA51F") GRAY = ManimColor("#7F7F7F") GREEN = ManimColor("#007F00") GREENYELLOW = ManimColor("#ADFF2F") GREY = ManimColor("#7F7F7F") HONEYDEW = ManimColor("#EFFFEF") HOTPINK = ManimColor("#FF68B3") INDIANRED = ManimColor("#CD5B5B") INDIGO = ManimColor("#4A0082") IVORY = ManimColor("#FFFFEF") KHAKI = ManimColor("#EFE58C") LAVENDER = ManimColor("#E5E5F9") LAVENDERBLUSH = ManimColor("#FFEFF4") LAWNGREEN = ManimColor("#7CFC00") LEMONCHIFFON = ManimColor("#FFF9CD") LIGHTBLUE = ManimColor("#ADD8E5") LIGHTCORAL = ManimColor("#EF7F7F") LIGHTCYAN = ManimColor("#E0FFFF") LIGHTGOLDENROD = ManimColor("#EDDD82") LIGHTGOLDENRODYELLOW = ManimColor("#F9F9D2") LIGHTGRAY = ManimColor("#D3D3D3") LIGHTGREEN = ManimColor("#90ED90") LIGHTGREY = ManimColor("#D3D3D3") LIGHTPINK = ManimColor("#FFB5C0") LIGHTSALMON = ManimColor("#FFA07A") LIGHTSEAGREEN = ManimColor("#1FB1AA") LIGHTSKYBLUE = ManimColor("#87CEF9") LIGHTSLATEBLUE = ManimColor("#8470FF") LIGHTSLATEGRAY = ManimColor("#778799") LIGHTSLATEGREY = ManimColor("#778799") LIGHTSTEELBLUE = ManimColor("#AFC4DD") LIGHTYELLOW = ManimColor("#FFFFE0") LIME = ManimColor("#00FF00") LIMEGREEN = ManimColor("#31CD31") LINEN = ManimColor("#F9EFE5") MAGENTA = ManimColor("#FF00FF") MAROON = ManimColor("#7F0000") MEDIUMAQUAMARINE = ManimColor("#66CDAA") MEDIUMBLUE = ManimColor("#0000CD") MEDIUMORCHID = ManimColor("#BA54D3") MEDIUMPURPLE = ManimColor("#9270DB") MEDIUMSEAGREEN = ManimColor("#3BB271") MEDIUMSLATEBLUE = ManimColor("#7B68ED") MEDIUMSPRINGGREEN = ManimColor("#00F99A") MEDIUMTURQUOISE = ManimColor("#48D1CC") MEDIUMVIOLETRED = ManimColor("#C61584") MIDNIGHTBLUE = ManimColor("#181870") MINTCREAM = ManimColor("#F4FFF9") MISTYROSE = ManimColor("#FFE3E1") MOCCASIN = ManimColor("#FFE3B5") NAVAJOWHITE = ManimColor("#FFDDAD") NAVY = ManimColor("#00007F") NAVYBLUE = ManimColor("#00007F") OLDLACE = ManimColor("#FCF4E5") OLIVE = ManimColor("#7F7F00") OLIVEDRAB = ManimColor("#6B8D22") ORANGE = ManimColor("#FFA500") ORANGERED = ManimColor("#FF4400") ORCHID = ManimColor("#DA70D6") PALEGOLDENROD = ManimColor("#EDE8AA") PALEGREEN = ManimColor("#97FB97") PALETURQUOISE = ManimColor("#AFEDED") PALEVIOLETRED = ManimColor("#DB7092") PAPAYAWHIP = ManimColor("#FFEED4") PEACHPUFF = ManimColor("#FFDAB8") PERU = ManimColor("#CD843F") PINK = ManimColor("#FFBFCA") PLUM = ManimColor("#DDA0DD") POWDERBLUE = ManimColor("#AFE0E5") PURPLE = ManimColor("#7F007F") RED = ManimColor("#FF0000") ROSYBROWN = ManimColor("#BB8E8E") ROYALBLUE = ManimColor("#4168E1") SADDLEBROWN = ManimColor("#8A4413") SALMON = ManimColor("#F97F72") SANDYBROWN = ManimColor("#F3A45F") SEAGREEN = ManimColor("#2D8A56") SEASHELL = ManimColor("#FFF4ED") SIENNA = ManimColor("#A0512C") SILVER = ManimColor("#BFBFBF") SKYBLUE = ManimColor("#87CEEA") SLATEBLUE = ManimColor("#6959CD") SLATEGRAY = ManimColor("#707F90") SLATEGREY = ManimColor("#707F90") SNOW = ManimColor("#FFF9F9") SPRINGGREEN = ManimColor("#00FF7E") STEELBLUE = ManimColor("#4682B3") TAN = ManimColor("#D2B38C") TEAL = ManimColor("#007F7F") THISTLE = ManimColor("#D8BFD8") TOMATO = ManimColor("#FF6347") TURQUOISE = ManimColor("#3FE0CF") VIOLET = ManimColor("#ED82ED") VIOLETRED = ManimColor("#D01F90") WHEAT = ManimColor("#F4DDB2") WHITE = ManimColor("#FFFFFF") WHITESMOKE = ManimColor("#F4F4F4") YELLOW = ManimColor("#FFFF00") YELLOWGREEN = ManimColor("#9ACD30") ================================================ FILE: manim/utils/color/X11.py ================================================ # from https://www.w3schools.com/colors/colors_x11.asp """X11 Colors These color and their names (taken from https://www.w3schools.com/colors/colors_x11.asp) were developed at the Massachusetts Intitute of Technology (MIT) during the development of color based computer display system. To use the colors from this list, access them directly from the module (which is exposed to Manim's global name space): .. code:: pycon >>> from manim import X11 >>> X11.BEIGE ManimColor('#F5F5DC') List of Color Constants ----------------------- .. automanimcolormodule:: manim.utils.color.X11 """ from __future__ import annotations from .core import ManimColor ALICEBLUE = ManimColor("#F0F8FF") ANTIQUEWHITE = ManimColor("#FAEBD7") ANTIQUEWHITE1 = ManimColor("#FFEFDB") ANTIQUEWHITE2 = ManimColor("#EEDFCC") ANTIQUEWHITE3 = ManimColor("#CDC0B0") ANTIQUEWHITE4 = ManimColor("#8B8378") AQUAMARINE1 = ManimColor("#7FFFD4") AQUAMARINE2 = ManimColor("#76EEC6") AQUAMARINE4 = ManimColor("#458B74") AZURE1 = ManimColor("#F0FFFF") AZURE2 = ManimColor("#E0EEEE") AZURE3 = ManimColor("#C1CDCD") AZURE4 = ManimColor("#838B8B") BEIGE = ManimColor("#F5F5DC") BISQUE1 = ManimColor("#FFE4C4") BISQUE2 = ManimColor("#EED5B7") BISQUE3 = ManimColor("#CDB79E") BISQUE4 = ManimColor("#8B7D6B") BLACK = ManimColor("#000000") BLANCHEDALMOND = ManimColor("#FFEBCD") BLUE1 = ManimColor("#0000FF") BLUE2 = ManimColor("#0000EE") BLUE4 = ManimColor("#00008B") BLUEVIOLET = ManimColor("#8A2BE2") BROWN = ManimColor("#A52A2A") BROWN1 = ManimColor("#FF4040") BROWN2 = ManimColor("#EE3B3B") BROWN3 = ManimColor("#CD3333") BROWN4 = ManimColor("#8B2323") BURLYWOOD = ManimColor("#DEB887") BURLYWOOD1 = ManimColor("#FFD39B") BURLYWOOD2 = ManimColor("#EEC591") BURLYWOOD3 = ManimColor("#CDAA7D") BURLYWOOD4 = ManimColor("#8B7355") CADETBLUE = ManimColor("#5F9EA0") CADETBLUE1 = ManimColor("#98F5FF") CADETBLUE2 = ManimColor("#8EE5EE") CADETBLUE3 = ManimColor("#7AC5CD") CADETBLUE4 = ManimColor("#53868B") CHARTREUSE1 = ManimColor("#7FFF00") CHARTREUSE2 = ManimColor("#76EE00") CHARTREUSE3 = ManimColor("#66CD00") CHARTREUSE4 = ManimColor("#458B00") CHOCOLATE = ManimColor("#D2691E") CHOCOLATE1 = ManimColor("#FF7F24") CHOCOLATE2 = ManimColor("#EE7621") CHOCOLATE3 = ManimColor("#CD661D") CORAL = ManimColor("#FF7F50") CORAL1 = ManimColor("#FF7256") CORAL2 = ManimColor("#EE6A50") CORAL3 = ManimColor("#CD5B45") CORAL4 = ManimColor("#8B3E2F") CORNFLOWERBLUE = ManimColor("#6495ED") CORNSILK1 = ManimColor("#FFF8DC") CORNSILK2 = ManimColor("#EEE8CD") CORNSILK3 = ManimColor("#CDC8B1") CORNSILK4 = ManimColor("#8B8878") CYAN1 = ManimColor("#00FFFF") CYAN2 = ManimColor("#00EEEE") CYAN3 = ManimColor("#00CDCD") CYAN4 = ManimColor("#008B8B") DARKGOLDENROD = ManimColor("#B8860B") DARKGOLDENROD1 = ManimColor("#FFB90F") DARKGOLDENROD2 = ManimColor("#EEAD0E") DARKGOLDENROD3 = ManimColor("#CD950C") DARKGOLDENROD4 = ManimColor("#8B6508") DARKGREEN = ManimColor("#006400") DARKKHAKI = ManimColor("#BDB76B") DARKOLIVEGREEN = ManimColor("#556B2F") DARKOLIVEGREEN1 = ManimColor("#CAFF70") DARKOLIVEGREEN2 = ManimColor("#BCEE68") DARKOLIVEGREEN3 = ManimColor("#A2CD5A") DARKOLIVEGREEN4 = ManimColor("#6E8B3D") DARKORANGE = ManimColor("#FF8C00") DARKORANGE1 = ManimColor("#FF7F00") DARKORANGE2 = ManimColor("#EE7600") DARKORANGE3 = ManimColor("#CD6600") DARKORANGE4 = ManimColor("#8B4500") DARKORCHID = ManimColor("#9932CC") DARKORCHID1 = ManimColor("#BF3EFF") DARKORCHID2 = ManimColor("#B23AEE") DARKORCHID3 = ManimColor("#9A32CD") DARKORCHID4 = ManimColor("#68228B") DARKSALMON = ManimColor("#E9967A") DARKSEAGREEN = ManimColor("#8FBC8F") DARKSEAGREEN1 = ManimColor("#C1FFC1") DARKSEAGREEN2 = ManimColor("#B4EEB4") DARKSEAGREEN3 = ManimColor("#9BCD9B") DARKSEAGREEN4 = ManimColor("#698B69") DARKSLATEBLUE = ManimColor("#483D8B") DARKSLATEGRAY = ManimColor("#2F4F4F") DARKSLATEGRAY1 = ManimColor("#97FFFF") DARKSLATEGRAY2 = ManimColor("#8DEEEE") DARKSLATEGRAY3 = ManimColor("#79CDCD") DARKSLATEGRAY4 = ManimColor("#528B8B") DARKTURQUOISE = ManimColor("#00CED1") DARKVIOLET = ManimColor("#9400D3") DEEPPINK1 = ManimColor("#FF1493") DEEPPINK2 = ManimColor("#EE1289") DEEPPINK3 = ManimColor("#CD1076") DEEPPINK4 = ManimColor("#8B0A50") DEEPSKYBLUE1 = ManimColor("#00BFFF") DEEPSKYBLUE2 = ManimColor("#00B2EE") DEEPSKYBLUE3 = ManimColor("#009ACD") DEEPSKYBLUE4 = ManimColor("#00688B") DIMGRAY = ManimColor("#696969") DODGERBLUE1 = ManimColor("#1E90FF") DODGERBLUE2 = ManimColor("#1C86EE") DODGERBLUE3 = ManimColor("#1874CD") DODGERBLUE4 = ManimColor("#104E8B") FIREBRICK = ManimColor("#B22222") FIREBRICK1 = ManimColor("#FF3030") FIREBRICK2 = ManimColor("#EE2C2C") FIREBRICK3 = ManimColor("#CD2626") FIREBRICK4 = ManimColor("#8B1A1A") FLORALWHITE = ManimColor("#FFFAF0") FORESTGREEN = ManimColor("#228B22") GAINSBORO = ManimColor("#DCDCDC") GHOSTWHITE = ManimColor("#F8F8FF") GOLD1 = ManimColor("#FFD700") GOLD2 = ManimColor("#EEC900") GOLD3 = ManimColor("#CDAD00") GOLD4 = ManimColor("#8B7500") GOLDENROD = ManimColor("#DAA520") GOLDENROD1 = ManimColor("#FFC125") GOLDENROD2 = ManimColor("#EEB422") GOLDENROD3 = ManimColor("#CD9B1D") GOLDENROD4 = ManimColor("#8B6914") GRAY = ManimColor("#BEBEBE") GRAY1 = ManimColor("#030303") GRAY2 = ManimColor("#050505") GRAY3 = ManimColor("#080808") GRAY4 = ManimColor("#0A0A0A") GRAY5 = ManimColor("#0D0D0D") GRAY6 = ManimColor("#0F0F0F") GRAY7 = ManimColor("#121212") GRAY8 = ManimColor("#141414") GRAY9 = ManimColor("#171717") GRAY10 = ManimColor("#1A1A1A") GRAY11 = ManimColor("#1C1C1C") GRAY12 = ManimColor("#1F1F1F") GRAY13 = ManimColor("#212121") GRAY14 = ManimColor("#242424") GRAY15 = ManimColor("#262626") GRAY16 = ManimColor("#292929") GRAY17 = ManimColor("#2B2B2B") GRAY18 = ManimColor("#2E2E2E") GRAY19 = ManimColor("#303030") GRAY20 = ManimColor("#333333") GRAY21 = ManimColor("#363636") GRAY22 = ManimColor("#383838") GRAY23 = ManimColor("#3B3B3B") GRAY24 = ManimColor("#3D3D3D") GRAY25 = ManimColor("#404040") GRAY26 = ManimColor("#424242") GRAY27 = ManimColor("#454545") GRAY28 = ManimColor("#474747") GRAY29 = ManimColor("#4A4A4A") GRAY30 = ManimColor("#4D4D4D") GRAY31 = ManimColor("#4F4F4F") GRAY32 = ManimColor("#525252") GRAY33 = ManimColor("#545454") GRAY34 = ManimColor("#575757") GRAY35 = ManimColor("#595959") GRAY36 = ManimColor("#5C5C5C") GRAY37 = ManimColor("#5E5E5E") GRAY38 = ManimColor("#616161") GRAY39 = ManimColor("#636363") GRAY40 = ManimColor("#666666") GRAY41 = ManimColor("#696969") GRAY42 = ManimColor("#6B6B6B") GRAY43 = ManimColor("#6E6E6E") GRAY44 = ManimColor("#707070") GRAY45 = ManimColor("#737373") GRAY46 = ManimColor("#757575") GRAY47 = ManimColor("#787878") GRAY48 = ManimColor("#7A7A7A") GRAY49 = ManimColor("#7D7D7D") GRAY50 = ManimColor("#7F7F7F") GRAY51 = ManimColor("#828282") GRAY52 = ManimColor("#858585") GRAY53 = ManimColor("#878787") GRAY54 = ManimColor("#8A8A8A") GRAY55 = ManimColor("#8C8C8C") GRAY56 = ManimColor("#8F8F8F") GRAY57 = ManimColor("#919191") GRAY58 = ManimColor("#949494") GRAY59 = ManimColor("#969696") GRAY60 = ManimColor("#999999") GRAY61 = ManimColor("#9C9C9C") GRAY62 = ManimColor("#9E9E9E") GRAY63 = ManimColor("#A1A1A1") GRAY64 = ManimColor("#A3A3A3") GRAY65 = ManimColor("#A6A6A6") GRAY66 = ManimColor("#A8A8A8") GRAY67 = ManimColor("#ABABAB") GRAY68 = ManimColor("#ADADAD") GRAY69 = ManimColor("#B0B0B0") GRAY70 = ManimColor("#B3B3B3") GRAY71 = ManimColor("#B5B5B5") GRAY72 = ManimColor("#B8B8B8") GRAY73 = ManimColor("#BABABA") GRAY74 = ManimColor("#BDBDBD") GRAY75 = ManimColor("#BFBFBF") GRAY76 = ManimColor("#C2C2C2") GRAY77 = ManimColor("#C4C4C4") GRAY78 = ManimColor("#C7C7C7") GRAY79 = ManimColor("#C9C9C9") GRAY80 = ManimColor("#CCCCCC") GRAY81 = ManimColor("#CFCFCF") GRAY82 = ManimColor("#D1D1D1") GRAY83 = ManimColor("#D4D4D4") GRAY84 = ManimColor("#D6D6D6") GRAY85 = ManimColor("#D9D9D9") GRAY86 = ManimColor("#DBDBDB") GRAY87 = ManimColor("#DEDEDE") GRAY88 = ManimColor("#E0E0E0") GRAY89 = ManimColor("#E3E3E3") GRAY90 = ManimColor("#E5E5E5") GRAY91 = ManimColor("#E8E8E8") GRAY92 = ManimColor("#EBEBEB") GRAY93 = ManimColor("#EDEDED") GRAY94 = ManimColor("#F0F0F0") GRAY95 = ManimColor("#F2F2F2") GRAY97 = ManimColor("#F7F7F7") GRAY98 = ManimColor("#FAFAFA") GRAY99 = ManimColor("#FCFCFC") GREEN1 = ManimColor("#00FF00") GREEN2 = ManimColor("#00EE00") GREEN3 = ManimColor("#00CD00") GREEN4 = ManimColor("#008B00") GREENYELLOW = ManimColor("#ADFF2F") HONEYDEW1 = ManimColor("#F0FFF0") HONEYDEW2 = ManimColor("#E0EEE0") HONEYDEW3 = ManimColor("#C1CDC1") HONEYDEW4 = ManimColor("#838B83") HOTPINK = ManimColor("#FF69B4") HOTPINK1 = ManimColor("#FF6EB4") HOTPINK2 = ManimColor("#EE6AA7") HOTPINK3 = ManimColor("#CD6090") HOTPINK4 = ManimColor("#8B3A62") INDIANRED = ManimColor("#CD5C5C") INDIANRED1 = ManimColor("#FF6A6A") INDIANRED2 = ManimColor("#EE6363") INDIANRED3 = ManimColor("#CD5555") INDIANRED4 = ManimColor("#8B3A3A") IVORY1 = ManimColor("#FFFFF0") IVORY2 = ManimColor("#EEEEE0") IVORY3 = ManimColor("#CDCDC1") IVORY4 = ManimColor("#8B8B83") KHAKI = ManimColor("#F0E68C") KHAKI1 = ManimColor("#FFF68F") KHAKI2 = ManimColor("#EEE685") KHAKI3 = ManimColor("#CDC673") KHAKI4 = ManimColor("#8B864E") LAVENDER = ManimColor("#E6E6FA") LAVENDERBLUSH1 = ManimColor("#FFF0F5") LAVENDERBLUSH2 = ManimColor("#EEE0E5") LAVENDERBLUSH3 = ManimColor("#CDC1C5") LAVENDERBLUSH4 = ManimColor("#8B8386") LAWNGREEN = ManimColor("#7CFC00") LEMONCHIFFON1 = ManimColor("#FFFACD") LEMONCHIFFON2 = ManimColor("#EEE9BF") LEMONCHIFFON3 = ManimColor("#CDC9A5") LEMONCHIFFON4 = ManimColor("#8B8970") LIGHT = ManimColor("#EEDD82") LIGHTBLUE = ManimColor("#ADD8E6") LIGHTBLUE1 = ManimColor("#BFEFFF") LIGHTBLUE2 = ManimColor("#B2DFEE") LIGHTBLUE3 = ManimColor("#9AC0CD") LIGHTBLUE4 = ManimColor("#68838B") LIGHTCORAL = ManimColor("#F08080") LIGHTCYAN1 = ManimColor("#E0FFFF") LIGHTCYAN2 = ManimColor("#D1EEEE") LIGHTCYAN3 = ManimColor("#B4CDCD") LIGHTCYAN4 = ManimColor("#7A8B8B") LIGHTGOLDENROD1 = ManimColor("#FFEC8B") LIGHTGOLDENROD2 = ManimColor("#EEDC82") LIGHTGOLDENROD3 = ManimColor("#CDBE70") LIGHTGOLDENROD4 = ManimColor("#8B814C") LIGHTGOLDENRODYELLOW = ManimColor("#FAFAD2") LIGHTGRAY = ManimColor("#D3D3D3") LIGHTPINK = ManimColor("#FFB6C1") LIGHTPINK1 = ManimColor("#FFAEB9") LIGHTPINK2 = ManimColor("#EEA2AD") LIGHTPINK3 = ManimColor("#CD8C95") LIGHTPINK4 = ManimColor("#8B5F65") LIGHTSALMON1 = ManimColor("#FFA07A") LIGHTSALMON2 = ManimColor("#EE9572") LIGHTSALMON3 = ManimColor("#CD8162") LIGHTSALMON4 = ManimColor("#8B5742") LIGHTSEAGREEN = ManimColor("#20B2AA") LIGHTSKYBLUE = ManimColor("#87CEFA") LIGHTSKYBLUE1 = ManimColor("#B0E2FF") LIGHTSKYBLUE2 = ManimColor("#A4D3EE") LIGHTSKYBLUE3 = ManimColor("#8DB6CD") LIGHTSKYBLUE4 = ManimColor("#607B8B") LIGHTSLATEBLUE = ManimColor("#8470FF") LIGHTSLATEGRAY = ManimColor("#778899") LIGHTSTEELBLUE = ManimColor("#B0C4DE") LIGHTSTEELBLUE1 = ManimColor("#CAE1FF") LIGHTSTEELBLUE2 = ManimColor("#BCD2EE") LIGHTSTEELBLUE3 = ManimColor("#A2B5CD") LIGHTSTEELBLUE4 = ManimColor("#6E7B8B") LIGHTYELLOW1 = ManimColor("#FFFFE0") LIGHTYELLOW2 = ManimColor("#EEEED1") LIGHTYELLOW3 = ManimColor("#CDCDB4") LIGHTYELLOW4 = ManimColor("#8B8B7A") LIMEGREEN = ManimColor("#32CD32") LINEN = ManimColor("#FAF0E6") MAGENTA = ManimColor("#FF00FF") MAGENTA2 = ManimColor("#EE00EE") MAGENTA3 = ManimColor("#CD00CD") MAGENTA4 = ManimColor("#8B008B") MAROON = ManimColor("#B03060") MAROON1 = ManimColor("#FF34B3") MAROON2 = ManimColor("#EE30A7") MAROON3 = ManimColor("#CD2990") MAROON4 = ManimColor("#8B1C62") MEDIUM = ManimColor("#66CDAA") MEDIUMAQUAMARINE = ManimColor("#66CDAA") MEDIUMBLUE = ManimColor("#0000CD") MEDIUMORCHID = ManimColor("#BA55D3") MEDIUMORCHID1 = ManimColor("#E066FF") MEDIUMORCHID2 = ManimColor("#D15FEE") MEDIUMORCHID3 = ManimColor("#B452CD") MEDIUMORCHID4 = ManimColor("#7A378B") MEDIUMPURPLE = ManimColor("#9370DB") MEDIUMPURPLE1 = ManimColor("#AB82FF") MEDIUMPURPLE2 = ManimColor("#9F79EE") MEDIUMPURPLE3 = ManimColor("#8968CD") MEDIUMPURPLE4 = ManimColor("#5D478B") MEDIUMSEAGREEN = ManimColor("#3CB371") MEDIUMSLATEBLUE = ManimColor("#7B68EE") MEDIUMSPRINGGREEN = ManimColor("#00FA9A") MEDIUMTURQUOISE = ManimColor("#48D1CC") MEDIUMVIOLETRED = ManimColor("#C71585") MIDNIGHTBLUE = ManimColor("#191970") MINTCREAM = ManimColor("#F5FFFA") MISTYROSE1 = ManimColor("#FFE4E1") MISTYROSE2 = ManimColor("#EED5D2") MISTYROSE3 = ManimColor("#CDB7B5") MISTYROSE4 = ManimColor("#8B7D7B") MOCCASIN = ManimColor("#FFE4B5") NAVAJOWHITE1 = ManimColor("#FFDEAD") NAVAJOWHITE2 = ManimColor("#EECFA1") NAVAJOWHITE3 = ManimColor("#CDB38B") NAVAJOWHITE4 = ManimColor("#8B795E") NAVYBLUE = ManimColor("#000080") OLDLACE = ManimColor("#FDF5E6") OLIVEDRAB = ManimColor("#6B8E23") OLIVEDRAB1 = ManimColor("#C0FF3E") OLIVEDRAB2 = ManimColor("#B3EE3A") OLIVEDRAB4 = ManimColor("#698B22") ORANGE1 = ManimColor("#FFA500") ORANGE2 = ManimColor("#EE9A00") ORANGE3 = ManimColor("#CD8500") ORANGE4 = ManimColor("#8B5A00") ORANGERED1 = ManimColor("#FF4500") ORANGERED2 = ManimColor("#EE4000") ORANGERED3 = ManimColor("#CD3700") ORANGERED4 = ManimColor("#8B2500") ORCHID = ManimColor("#DA70D6") ORCHID1 = ManimColor("#FF83FA") ORCHID2 = ManimColor("#EE7AE9") ORCHID3 = ManimColor("#CD69C9") ORCHID4 = ManimColor("#8B4789") PALE = ManimColor("#DB7093") PALEGOLDENROD = ManimColor("#EEE8AA") PALEGREEN = ManimColor("#98FB98") PALEGREEN1 = ManimColor("#9AFF9A") PALEGREEN2 = ManimColor("#90EE90") PALEGREEN3 = ManimColor("#7CCD7C") PALEGREEN4 = ManimColor("#548B54") PALETURQUOISE = ManimColor("#AFEEEE") PALETURQUOISE1 = ManimColor("#BBFFFF") PALETURQUOISE2 = ManimColor("#AEEEEE") PALETURQUOISE3 = ManimColor("#96CDCD") PALETURQUOISE4 = ManimColor("#668B8B") PALEVIOLETRED = ManimColor("#DB7093") PALEVIOLETRED1 = ManimColor("#FF82AB") PALEVIOLETRED2 = ManimColor("#EE799F") PALEVIOLETRED3 = ManimColor("#CD6889") PALEVIOLETRED4 = ManimColor("#8B475D") PAPAYAWHIP = ManimColor("#FFEFD5") PEACHPUFF1 = ManimColor("#FFDAB9") PEACHPUFF2 = ManimColor("#EECBAD") PEACHPUFF3 = ManimColor("#CDAF95") PEACHPUFF4 = ManimColor("#8B7765") PINK = ManimColor("#FFC0CB") PINK1 = ManimColor("#FFB5C5") PINK2 = ManimColor("#EEA9B8") PINK3 = ManimColor("#CD919E") PINK4 = ManimColor("#8B636C") PLUM = ManimColor("#DDA0DD") PLUM1 = ManimColor("#FFBBFF") PLUM2 = ManimColor("#EEAEEE") PLUM3 = ManimColor("#CD96CD") PLUM4 = ManimColor("#8B668B") POWDERBLUE = ManimColor("#B0E0E6") PURPLE = ManimColor("#A020F0") PURPLE1 = ManimColor("#9B30FF") PURPLE2 = ManimColor("#912CEE") PURPLE3 = ManimColor("#7D26CD") PURPLE4 = ManimColor("#551A8B") RED1 = ManimColor("#FF0000") RED2 = ManimColor("#EE0000") RED3 = ManimColor("#CD0000") RED4 = ManimColor("#8B0000") ROSYBROWN = ManimColor("#BC8F8F") ROSYBROWN1 = ManimColor("#FFC1C1") ROSYBROWN2 = ManimColor("#EEB4B4") ROSYBROWN3 = ManimColor("#CD9B9B") ROSYBROWN4 = ManimColor("#8B6969") ROYALBLUE = ManimColor("#4169E1") ROYALBLUE1 = ManimColor("#4876FF") ROYALBLUE2 = ManimColor("#436EEE") ROYALBLUE3 = ManimColor("#3A5FCD") ROYALBLUE4 = ManimColor("#27408B") SADDLEBROWN = ManimColor("#8B4513") SALMON = ManimColor("#FA8072") SALMON1 = ManimColor("#FF8C69") SALMON2 = ManimColor("#EE8262") SALMON3 = ManimColor("#CD7054") SALMON4 = ManimColor("#8B4C39") SANDYBROWN = ManimColor("#F4A460") SEAGREEN1 = ManimColor("#54FF9F") SEAGREEN2 = ManimColor("#4EEE94") SEAGREEN3 = ManimColor("#43CD80") SEAGREEN4 = ManimColor("#2E8B57") SEASHELL1 = ManimColor("#FFF5EE") SEASHELL2 = ManimColor("#EEE5DE") SEASHELL3 = ManimColor("#CDC5BF") SEASHELL4 = ManimColor("#8B8682") SIENNA = ManimColor("#A0522D") SIENNA1 = ManimColor("#FF8247") SIENNA2 = ManimColor("#EE7942") SIENNA3 = ManimColor("#CD6839") SIENNA4 = ManimColor("#8B4726") SKYBLUE = ManimColor("#87CEEB") SKYBLUE1 = ManimColor("#87CEFF") SKYBLUE2 = ManimColor("#7EC0EE") SKYBLUE3 = ManimColor("#6CA6CD") SKYBLUE4 = ManimColor("#4A708B") SLATEBLUE = ManimColor("#6A5ACD") SLATEBLUE1 = ManimColor("#836FFF") SLATEBLUE2 = ManimColor("#7A67EE") SLATEBLUE3 = ManimColor("#6959CD") SLATEBLUE4 = ManimColor("#473C8B") SLATEGRAY = ManimColor("#708090") SLATEGRAY1 = ManimColor("#C6E2FF") SLATEGRAY2 = ManimColor("#B9D3EE") SLATEGRAY3 = ManimColor("#9FB6CD") SLATEGRAY4 = ManimColor("#6C7B8B") SNOW1 = ManimColor("#FFFAFA") SNOW2 = ManimColor("#EEE9E9") SNOW3 = ManimColor("#CDC9C9") SNOW4 = ManimColor("#8B8989") SPRINGGREEN1 = ManimColor("#00FF7F") SPRINGGREEN2 = ManimColor("#00EE76") SPRINGGREEN3 = ManimColor("#00CD66") SPRINGGREEN4 = ManimColor("#008B45") STEELBLUE = ManimColor("#4682B4") STEELBLUE1 = ManimColor("#63B8FF") STEELBLUE2 = ManimColor("#5CACEE") STEELBLUE3 = ManimColor("#4F94CD") STEELBLUE4 = ManimColor("#36648B") TAN = ManimColor("#D2B48C") TAN1 = ManimColor("#FFA54F") TAN2 = ManimColor("#EE9A49") TAN3 = ManimColor("#CD853F") TAN4 = ManimColor("#8B5A2B") THISTLE = ManimColor("#D8BFD8") THISTLE1 = ManimColor("#FFE1FF") THISTLE2 = ManimColor("#EED2EE") THISTLE3 = ManimColor("#CDB5CD") THISTLE4 = ManimColor("#8B7B8B") TOMATO1 = ManimColor("#FF6347") TOMATO2 = ManimColor("#EE5C42") TOMATO3 = ManimColor("#CD4F39") TOMATO4 = ManimColor("#8B3626") TURQUOISE = ManimColor("#40E0D0") TURQUOISE1 = ManimColor("#00F5FF") TURQUOISE2 = ManimColor("#00E5EE") TURQUOISE3 = ManimColor("#00C5CD") TURQUOISE4 = ManimColor("#00868B") VIOLET = ManimColor("#EE82EE") VIOLETRED = ManimColor("#D02090") VIOLETRED1 = ManimColor("#FF3E96") VIOLETRED2 = ManimColor("#EE3A8C") VIOLETRED3 = ManimColor("#CD3278") VIOLETRED4 = ManimColor("#8B2252") WHEAT = ManimColor("#F5DEB3") WHEAT1 = ManimColor("#FFE7BA") WHEAT2 = ManimColor("#EED8AE") WHEAT3 = ManimColor("#CDBA96") WHEAT4 = ManimColor("#8B7E66") WHITE = ManimColor("#FFFFFF") WHITESMOKE = ManimColor("#F5F5F5") YELLOW1 = ManimColor("#FFFF00") YELLOW2 = ManimColor("#EEEE00") YELLOW3 = ManimColor("#CDCD00") YELLOW4 = ManimColor("#8B8B00") YELLOWGREEN = ManimColor("#9ACD32") ================================================ FILE: manim/utils/color/XKCD.py ================================================ """Colors from the XKCD Color Name Survey XKCD is a popular `web comic `__ created by Randall Munroe. His "`Color Name Survey `__" (with 200000 participants) resulted in a list of nearly 1000 color names. While the ``XKCD`` module is exposed to Manim's global name space, the colors included in it are not. This means that in order to use the colors, access them via the module name: .. code:: pycon >>> from manim import XKCD >>> XKCD.MANGO ManimColor('#FFA62B') List of Color Constants ----------------------- These hex values are non official approximate values intended to simulate the colors in HTML, taken from https://www.w3schools.com/colors/colors_xkcd.asp. .. automanimcolormodule:: manim.utils.color.XKCD """ from __future__ import annotations from .core import ManimColor ACIDGREEN = ManimColor("#8FFE09") ADOBE = ManimColor("#BD6C48") ALGAE = ManimColor("#54AC68") ALGAEGREEN = ManimColor("#21C36F") ALMOSTBLACK = ManimColor("#070D0D") AMBER = ManimColor("#FEB308") AMETHYST = ManimColor("#9B5FC0") APPLE = ManimColor("#6ECB3C") APPLEGREEN = ManimColor("#76CD26") APRICOT = ManimColor("#FFB16D") AQUA = ManimColor("#13EAC9") AQUABLUE = ManimColor("#02D8E9") AQUAGREEN = ManimColor("#12E193") AQUAMARINE = ManimColor("#2EE8BB") ARMYGREEN = ManimColor("#4B5D16") ASPARAGUS = ManimColor("#77AB56") AUBERGINE = ManimColor("#3D0734") AUBURN = ManimColor("#9A3001") AVOCADO = ManimColor("#90B134") AVOCADOGREEN = ManimColor("#87A922") AZUL = ManimColor("#1D5DEC") AZURE = ManimColor("#069AF3") BABYBLUE = ManimColor("#A2CFFE") BABYGREEN = ManimColor("#8CFF9E") BABYPINK = ManimColor("#FFB7CE") BABYPOO = ManimColor("#AB9004") BABYPOOP = ManimColor("#937C00") BABYPOOPGREEN = ManimColor("#8F9805") BABYPUKEGREEN = ManimColor("#B6C406") BABYPURPLE = ManimColor("#CA9BF7") BABYSHITBROWN = ManimColor("#AD900D") BABYSHITGREEN = ManimColor("#889717") BANANA = ManimColor("#FFFF7E") BANANAYELLOW = ManimColor("#FAFE4B") BARBIEPINK = ManimColor("#FE46A5") BARFGREEN = ManimColor("#94AC02") BARNEY = ManimColor("#AC1DB8") BARNEYPURPLE = ManimColor("#A00498") BATTLESHIPGREY = ManimColor("#6B7C85") BEIGE = ManimColor("#E6DAA6") BERRY = ManimColor("#990F4B") BILE = ManimColor("#B5C306") BLACK = ManimColor("#000000") BLAND = ManimColor("#AFA88B") BLOOD = ManimColor("#770001") BLOODORANGE = ManimColor("#FE4B03") BLOODRED = ManimColor("#980002") BLUE = ManimColor("#0343DF") BLUEBERRY = ManimColor("#464196") BLUEBLUE = ManimColor("#2242C7") BLUEGREEN = ManimColor("#0F9B8E") BLUEGREY = ManimColor("#85A3B2") BLUEPURPLE = ManimColor("#5A06EF") BLUEVIOLET = ManimColor("#5D06E9") BLUEWITHAHINTOFPURPLE = ManimColor("#533CC6") BLUEYGREEN = ManimColor("#2BB179") BLUEYGREY = ManimColor("#89A0B0") BLUEYPURPLE = ManimColor("#6241C7") BLUISH = ManimColor("#2976BB") BLUISHGREEN = ManimColor("#10A674") BLUISHGREY = ManimColor("#748B97") BLUISHPURPLE = ManimColor("#703BE7") BLURPLE = ManimColor("#5539CC") BLUSH = ManimColor("#F29E8E") BLUSHPINK = ManimColor("#FE828C") BOOGER = ManimColor("#9BB53C") BOOGERGREEN = ManimColor("#96B403") BORDEAUX = ManimColor("#7B002C") BORINGGREEN = ManimColor("#63B365") BOTTLEGREEN = ManimColor("#044A05") BRICK = ManimColor("#A03623") BRICKORANGE = ManimColor("#C14A09") BRICKRED = ManimColor("#8F1402") BRIGHTAQUA = ManimColor("#0BF9EA") BRIGHTBLUE = ManimColor("#0165FC") BRIGHTCYAN = ManimColor("#41FDFE") BRIGHTGREEN = ManimColor("#01FF07") BRIGHTLAVENDER = ManimColor("#C760FF") BRIGHTLIGHTBLUE = ManimColor("#26F7FD") BRIGHTLIGHTGREEN = ManimColor("#2DFE54") BRIGHTLILAC = ManimColor("#C95EFB") BRIGHTLIME = ManimColor("#87FD05") BRIGHTLIMEGREEN = ManimColor("#65FE08") BRIGHTMAGENTA = ManimColor("#FF08E8") BRIGHTOLIVE = ManimColor("#9CBB04") BRIGHTORANGE = ManimColor("#FF5B00") BRIGHTPINK = ManimColor("#FE01B1") BRIGHTPURPLE = ManimColor("#BE03FD") BRIGHTRED = ManimColor("#FF000D") BRIGHTSEAGREEN = ManimColor("#05FFA6") BRIGHTSKYBLUE = ManimColor("#02CCFE") BRIGHTTEAL = ManimColor("#01F9C6") BRIGHTTURQUOISE = ManimColor("#0FFEF9") BRIGHTVIOLET = ManimColor("#AD0AFD") BRIGHTYELLOW = ManimColor("#FFFD01") BRIGHTYELLOWGREEN = ManimColor("#9DFF00") BRITISHRACINGGREEN = ManimColor("#05480D") BRONZE = ManimColor("#A87900") BROWN = ManimColor("#653700") BROWNGREEN = ManimColor("#706C11") BROWNGREY = ManimColor("#8D8468") BROWNISH = ManimColor("#9C6D57") BROWNISHGREEN = ManimColor("#6A6E09") BROWNISHGREY = ManimColor("#86775F") BROWNISHORANGE = ManimColor("#CB7723") BROWNISHPINK = ManimColor("#C27E79") BROWNISHPURPLE = ManimColor("#76424E") BROWNISHRED = ManimColor("#9E3623") BROWNISHYELLOW = ManimColor("#C9B003") BROWNORANGE = ManimColor("#B96902") BROWNRED = ManimColor("#922B05") BROWNYELLOW = ManimColor("#B29705") BROWNYGREEN = ManimColor("#6F6C0A") BROWNYORANGE = ManimColor("#CA6B02") BRUISE = ManimColor("#7E4071") BUBBLEGUM = ManimColor("#FF6CB5") BUBBLEGUMPINK = ManimColor("#FF69AF") BUFF = ManimColor("#FEF69E") BURGUNDY = ManimColor("#610023") BURNTORANGE = ManimColor("#C04E01") BURNTRED = ManimColor("#9F2305") BURNTSIENA = ManimColor("#B75203") BURNTSIENNA = ManimColor("#B04E0F") BURNTUMBER = ManimColor("#A0450E") BURNTYELLOW = ManimColor("#D5AB09") BURPLE = ManimColor("#6832E3") BUTTER = ManimColor("#FFFF81") BUTTERSCOTCH = ManimColor("#FDB147") BUTTERYELLOW = ManimColor("#FFFD74") CADETBLUE = ManimColor("#4E7496") CAMEL = ManimColor("#C69F59") CAMO = ManimColor("#7F8F4E") CAMOGREEN = ManimColor("#526525") CAMOUFLAGEGREEN = ManimColor("#4B6113") CANARY = ManimColor("#FDFF63") CANARYYELLOW = ManimColor("#FFFE40") CANDYPINK = ManimColor("#FF63E9") CARAMEL = ManimColor("#AF6F09") CARMINE = ManimColor("#9D0216") CARNATION = ManimColor("#FD798F") CARNATIONPINK = ManimColor("#FF7FA7") CAROLINABLUE = ManimColor("#8AB8FE") CELADON = ManimColor("#BEFDB7") CELERY = ManimColor("#C1FD95") CEMENT = ManimColor("#A5A391") CERISE = ManimColor("#DE0C62") CERULEAN = ManimColor("#0485D1") CERULEANBLUE = ManimColor("#056EEE") CHARCOAL = ManimColor("#343837") CHARCOALGREY = ManimColor("#3C4142") CHARTREUSE = ManimColor("#C1F80A") CHERRY = ManimColor("#CF0234") CHERRYRED = ManimColor("#F7022A") CHESTNUT = ManimColor("#742802") CHOCOLATE = ManimColor("#3D1C02") CHOCOLATEBROWN = ManimColor("#411900") CINNAMON = ManimColor("#AC4F06") CLARET = ManimColor("#680018") CLAY = ManimColor("#B66A50") CLAYBROWN = ManimColor("#B2713D") CLEARBLUE = ManimColor("#247AFD") COBALT = ManimColor("#1E488F") COBALTBLUE = ManimColor("#030AA7") COCOA = ManimColor("#875F42") COFFEE = ManimColor("#A6814C") COOLBLUE = ManimColor("#4984B8") COOLGREEN = ManimColor("#33B864") COOLGREY = ManimColor("#95A3A6") COPPER = ManimColor("#B66325") CORAL = ManimColor("#FC5A50") CORALPINK = ManimColor("#FF6163") CORNFLOWER = ManimColor("#6A79F7") CORNFLOWERBLUE = ManimColor("#5170D7") CRANBERRY = ManimColor("#9E003A") CREAM = ManimColor("#FFFFC2") CREME = ManimColor("#FFFFB6") CRIMSON = ManimColor("#8C000F") CUSTARD = ManimColor("#FFFD78") CYAN = ManimColor("#00FFFF") DANDELION = ManimColor("#FEDF08") DARK = ManimColor("#1B2431") DARKAQUA = ManimColor("#05696B") DARKAQUAMARINE = ManimColor("#017371") DARKBEIGE = ManimColor("#AC9362") DARKBLUE = ManimColor("#030764") DARKBLUEGREEN = ManimColor("#005249") DARKBLUEGREY = ManimColor("#1F3B4D") DARKBROWN = ManimColor("#341C02") DARKCORAL = ManimColor("#CF524E") DARKCREAM = ManimColor("#FFF39A") DARKCYAN = ManimColor("#0A888A") DARKFORESTGREEN = ManimColor("#002D04") DARKFUCHSIA = ManimColor("#9D0759") DARKGOLD = ManimColor("#B59410") DARKGRASSGREEN = ManimColor("#388004") DARKGREEN = ManimColor("#054907") DARKGREENBLUE = ManimColor("#1F6357") DARKGREY = ManimColor("#363737") DARKGREYBLUE = ManimColor("#29465B") DARKHOTPINK = ManimColor("#D90166") DARKINDIGO = ManimColor("#1F0954") DARKISHBLUE = ManimColor("#014182") DARKISHGREEN = ManimColor("#287C37") DARKISHPINK = ManimColor("#DA467D") DARKISHPURPLE = ManimColor("#751973") DARKISHRED = ManimColor("#A90308") DARKKHAKI = ManimColor("#9B8F55") DARKLAVENDER = ManimColor("#856798") DARKLILAC = ManimColor("#9C6DA5") DARKLIME = ManimColor("#84B701") DARKLIMEGREEN = ManimColor("#7EBD01") DARKMAGENTA = ManimColor("#960056") DARKMAROON = ManimColor("#3C0008") DARKMAUVE = ManimColor("#874C62") DARKMINT = ManimColor("#48C072") DARKMINTGREEN = ManimColor("#20C073") DARKMUSTARD = ManimColor("#A88905") DARKNAVY = ManimColor("#000435") DARKNAVYBLUE = ManimColor("#00022E") DARKOLIVE = ManimColor("#373E02") DARKOLIVEGREEN = ManimColor("#3C4D03") DARKORANGE = ManimColor("#C65102") DARKPASTELGREEN = ManimColor("#56AE57") DARKPEACH = ManimColor("#DE7E5D") DARKPERIWINKLE = ManimColor("#665FD1") DARKPINK = ManimColor("#CB416B") DARKPLUM = ManimColor("#3F012C") DARKPURPLE = ManimColor("#35063E") DARKRED = ManimColor("#840000") DARKROSE = ManimColor("#B5485D") DARKROYALBLUE = ManimColor("#02066F") DARKSAGE = ManimColor("#598556") DARKSALMON = ManimColor("#C85A53") DARKSAND = ManimColor("#A88F59") DARKSEAFOAM = ManimColor("#1FB57A") DARKSEAFOAMGREEN = ManimColor("#3EAF76") DARKSEAGREEN = ManimColor("#11875D") DARKSKYBLUE = ManimColor("#448EE4") DARKSLATEBLUE = ManimColor("#214761") DARKTAN = ManimColor("#AF884A") DARKTAUPE = ManimColor("#7F684E") DARKTEAL = ManimColor("#014D4E") DARKTURQUOISE = ManimColor("#045C5A") DARKVIOLET = ManimColor("#34013F") DARKYELLOW = ManimColor("#D5B60A") DARKYELLOWGREEN = ManimColor("#728F02") DEEPAQUA = ManimColor("#08787F") DEEPBLUE = ManimColor("#040273") DEEPBROWN = ManimColor("#410200") DEEPGREEN = ManimColor("#02590F") DEEPLAVENDER = ManimColor("#8D5EB7") DEEPLILAC = ManimColor("#966EBD") DEEPMAGENTA = ManimColor("#A0025C") DEEPORANGE = ManimColor("#DC4D01") DEEPPINK = ManimColor("#CB0162") DEEPPURPLE = ManimColor("#36013F") DEEPRED = ManimColor("#9A0200") DEEPROSE = ManimColor("#C74767") DEEPSEABLUE = ManimColor("#015482") DEEPSKYBLUE = ManimColor("#0D75F8") DEEPTEAL = ManimColor("#00555A") DEEPTURQUOISE = ManimColor("#017374") DEEPVIOLET = ManimColor("#490648") DENIM = ManimColor("#3B638C") DENIMBLUE = ManimColor("#3B5B92") DESERT = ManimColor("#CCAD60") DIARRHEA = ManimColor("#9F8303") DIRT = ManimColor("#8A6E45") DIRTBROWN = ManimColor("#836539") DIRTYBLUE = ManimColor("#3F829D") DIRTYGREEN = ManimColor("#667E2C") DIRTYORANGE = ManimColor("#C87606") DIRTYPINK = ManimColor("#CA7B80") DIRTYPURPLE = ManimColor("#734A65") DIRTYYELLOW = ManimColor("#CDC50A") DODGERBLUE = ManimColor("#3E82FC") DRAB = ManimColor("#828344") DRABGREEN = ManimColor("#749551") DRIEDBLOOD = ManimColor("#4B0101") DUCKEGGBLUE = ManimColor("#C3FBF4") DULLBLUE = ManimColor("#49759C") DULLBROWN = ManimColor("#876E4B") DULLGREEN = ManimColor("#74A662") DULLORANGE = ManimColor("#D8863B") DULLPINK = ManimColor("#D5869D") DULLPURPLE = ManimColor("#84597E") DULLRED = ManimColor("#BB3F3F") DULLTEAL = ManimColor("#5F9E8F") DULLYELLOW = ManimColor("#EEDC5B") DUSK = ManimColor("#4E5481") DUSKBLUE = ManimColor("#26538D") DUSKYBLUE = ManimColor("#475F94") DUSKYPINK = ManimColor("#CC7A8B") DUSKYPURPLE = ManimColor("#895B7B") DUSKYROSE = ManimColor("#BA6873") DUST = ManimColor("#B2996E") DUSTYBLUE = ManimColor("#5A86AD") DUSTYGREEN = ManimColor("#76A973") DUSTYLAVENDER = ManimColor("#AC86A8") DUSTYORANGE = ManimColor("#F0833A") DUSTYPINK = ManimColor("#D58A94") DUSTYPURPLE = ManimColor("#825F87") DUSTYRED = ManimColor("#B9484E") DUSTYROSE = ManimColor("#C0737A") DUSTYTEAL = ManimColor("#4C9085") EARTH = ManimColor("#A2653E") EASTERGREEN = ManimColor("#8CFD7E") EASTERPURPLE = ManimColor("#C071FE") ECRU = ManimColor("#FEFFCA") EGGPLANT = ManimColor("#380835") EGGPLANTPURPLE = ManimColor("#430541") EGGSHELL = ManimColor("#FFFCC4") EGGSHELLBLUE = ManimColor("#C4FFF7") ELECTRICBLUE = ManimColor("#0652FF") ELECTRICGREEN = ManimColor("#21FC0D") ELECTRICLIME = ManimColor("#A8FF04") ELECTRICPINK = ManimColor("#FF0490") ELECTRICPURPLE = ManimColor("#AA23FF") EMERALD = ManimColor("#01A049") EMERALDGREEN = ManimColor("#028F1E") EVERGREEN = ManimColor("#05472A") FADEDBLUE = ManimColor("#658CBB") FADEDGREEN = ManimColor("#7BB274") FADEDORANGE = ManimColor("#F0944D") FADEDPINK = ManimColor("#DE9DAC") FADEDPURPLE = ManimColor("#916E99") FADEDRED = ManimColor("#D3494E") FADEDYELLOW = ManimColor("#FEFF7F") FAWN = ManimColor("#CFAF7B") FERN = ManimColor("#63A950") FERNGREEN = ManimColor("#548D44") FIREENGINERED = ManimColor("#FE0002") FLATBLUE = ManimColor("#3C73A8") FLATGREEN = ManimColor("#699D4C") FLUORESCENTGREEN = ManimColor("#08FF08") FLUROGREEN = ManimColor("#0AFF02") FOAMGREEN = ManimColor("#90FDA9") FOREST = ManimColor("#0B5509") FORESTGREEN = ManimColor("#06470C") FORRESTGREEN = ManimColor("#154406") FRENCHBLUE = ManimColor("#436BAD") FRESHGREEN = ManimColor("#69D84F") FROGGREEN = ManimColor("#58BC08") FUCHSIA = ManimColor("#ED0DD9") GOLD = ManimColor("#DBB40C") GOLDEN = ManimColor("#F5BF03") GOLDENBROWN = ManimColor("#B27A01") GOLDENROD = ManimColor("#F9BC08") GOLDENYELLOW = ManimColor("#FEC615") GRAPE = ManimColor("#6C3461") GRAPEFRUIT = ManimColor("#FD5956") GRAPEPURPLE = ManimColor("#5D1451") GRASS = ManimColor("#5CAC2D") GRASSGREEN = ManimColor("#3F9B0B") GRASSYGREEN = ManimColor("#419C03") GREEN = ManimColor("#15B01A") GREENAPPLE = ManimColor("#5EDC1F") GREENBLUE = ManimColor("#01C08D") GREENBROWN = ManimColor("#544E03") GREENGREY = ManimColor("#77926F") GREENISH = ManimColor("#40A368") GREENISHBEIGE = ManimColor("#C9D179") GREENISHBLUE = ManimColor("#0B8B87") GREENISHBROWN = ManimColor("#696112") GREENISHCYAN = ManimColor("#2AFEB7") GREENISHGREY = ManimColor("#96AE8D") GREENISHTAN = ManimColor("#BCCB7A") GREENISHTEAL = ManimColor("#32BF84") GREENISHTURQUOISE = ManimColor("#00FBB0") GREENISHYELLOW = ManimColor("#CDFD02") GREENTEAL = ManimColor("#0CB577") GREENYBLUE = ManimColor("#42B395") GREENYBROWN = ManimColor("#696006") GREENYELLOW = ManimColor("#B5CE08") GREENYGREY = ManimColor("#7EA07A") GREENYYELLOW = ManimColor("#C6F808") GREY = ManimColor("#929591") GREYBLUE = ManimColor("#647D8E") GREYBROWN = ManimColor("#7F7053") GREYGREEN = ManimColor("#86A17D") GREYISH = ManimColor("#A8A495") GREYISHBLUE = ManimColor("#5E819D") GREYISHBROWN = ManimColor("#7A6A4F") GREYISHGREEN = ManimColor("#82A67D") GREYISHPINK = ManimColor("#C88D94") GREYISHPURPLE = ManimColor("#887191") GREYISHTEAL = ManimColor("#719F91") GREYPINK = ManimColor("#C3909B") GREYPURPLE = ManimColor("#826D8C") GREYTEAL = ManimColor("#5E9B8A") GROSSGREEN = ManimColor("#A0BF16") GUNMETAL = ManimColor("#536267") HAZEL = ManimColor("#8E7618") HEATHER = ManimColor("#A484AC") HELIOTROPE = ManimColor("#D94FF5") HIGHLIGHTERGREEN = ManimColor("#1BFC06") HOSPITALGREEN = ManimColor("#9BE5AA") HOTGREEN = ManimColor("#25FF29") HOTMAGENTA = ManimColor("#F504C9") HOTPINK = ManimColor("#FF028D") HOTPURPLE = ManimColor("#CB00F5") HUNTERGREEN = ManimColor("#0B4008") ICE = ManimColor("#D6FFFA") ICEBLUE = ManimColor("#D7FFFE") ICKYGREEN = ManimColor("#8FAE22") INDIANRED = ManimColor("#850E04") INDIGO = ManimColor("#380282") INDIGOBLUE = ManimColor("#3A18B1") IRIS = ManimColor("#6258C4") IRISHGREEN = ManimColor("#019529") IVORY = ManimColor("#FFFFCB") JADE = ManimColor("#1FA774") JADEGREEN = ManimColor("#2BAF6A") JUNGLEGREEN = ManimColor("#048243") KELLEYGREEN = ManimColor("#009337") KELLYGREEN = ManimColor("#02AB2E") KERMITGREEN = ManimColor("#5CB200") KEYLIME = ManimColor("#AEFF6E") KHAKI = ManimColor("#AAA662") KHAKIGREEN = ManimColor("#728639") KIWI = ManimColor("#9CEF43") KIWIGREEN = ManimColor("#8EE53F") LAVENDER = ManimColor("#C79FEF") LAVENDERBLUE = ManimColor("#8B88F8") LAVENDERPINK = ManimColor("#DD85D7") LAWNGREEN = ManimColor("#4DA409") LEAF = ManimColor("#71AA34") LEAFGREEN = ManimColor("#5CA904") LEAFYGREEN = ManimColor("#51B73B") LEATHER = ManimColor("#AC7434") LEMON = ManimColor("#FDFF52") LEMONGREEN = ManimColor("#ADF802") LEMONLIME = ManimColor("#BFFE28") LEMONYELLOW = ManimColor("#FDFF38") LICHEN = ManimColor("#8FB67B") LIGHTAQUA = ManimColor("#8CFFDB") LIGHTAQUAMARINE = ManimColor("#7BFDC7") LIGHTBEIGE = ManimColor("#FFFEB6") LIGHTBLUE = ManimColor("#7BC8F6") LIGHTBLUEGREEN = ManimColor("#7EFBB3") LIGHTBLUEGREY = ManimColor("#B7C9E2") LIGHTBLUISHGREEN = ManimColor("#76FDA8") LIGHTBRIGHTGREEN = ManimColor("#53FE5C") LIGHTBROWN = ManimColor("#AD8150") LIGHTBURGUNDY = ManimColor("#A8415B") LIGHTCYAN = ManimColor("#ACFFFC") LIGHTEGGPLANT = ManimColor("#894585") LIGHTERGREEN = ManimColor("#75FD63") LIGHTERPURPLE = ManimColor("#A55AF4") LIGHTFORESTGREEN = ManimColor("#4F9153") LIGHTGOLD = ManimColor("#FDDC5C") LIGHTGRASSGREEN = ManimColor("#9AF764") LIGHTGREEN = ManimColor("#76FF7B") LIGHTGREENBLUE = ManimColor("#56FCA2") LIGHTGREENISHBLUE = ManimColor("#63F7B4") LIGHTGREY = ManimColor("#D8DCD6") LIGHTGREYBLUE = ManimColor("#9DBCD4") LIGHTGREYGREEN = ManimColor("#B7E1A1") LIGHTINDIGO = ManimColor("#6D5ACF") LIGHTISHBLUE = ManimColor("#3D7AFD") LIGHTISHGREEN = ManimColor("#61E160") LIGHTISHPURPLE = ManimColor("#A552E6") LIGHTISHRED = ManimColor("#FE2F4A") LIGHTKHAKI = ManimColor("#E6F2A2") LIGHTLAVENDAR = ManimColor("#EFC0FE") LIGHTLAVENDER = ManimColor("#DFC5FE") LIGHTLIGHTBLUE = ManimColor("#CAFFFB") LIGHTLIGHTGREEN = ManimColor("#C8FFB0") LIGHTLILAC = ManimColor("#EDC8FF") LIGHTLIME = ManimColor("#AEFD6C") LIGHTLIMEGREEN = ManimColor("#B9FF66") LIGHTMAGENTA = ManimColor("#FA5FF7") LIGHTMAROON = ManimColor("#A24857") LIGHTMAUVE = ManimColor("#C292A1") LIGHTMINT = ManimColor("#B6FFBB") LIGHTMINTGREEN = ManimColor("#A6FBB2") LIGHTMOSSGREEN = ManimColor("#A6C875") LIGHTMUSTARD = ManimColor("#F7D560") LIGHTNAVY = ManimColor("#155084") LIGHTNAVYBLUE = ManimColor("#2E5A88") LIGHTNEONGREEN = ManimColor("#4EFD54") LIGHTOLIVE = ManimColor("#ACBF69") LIGHTOLIVEGREEN = ManimColor("#A4BE5C") LIGHTORANGE = ManimColor("#FDAA48") LIGHTPASTELGREEN = ManimColor("#B2FBA5") LIGHTPEACH = ManimColor("#FFD8B1") LIGHTPEAGREEN = ManimColor("#C4FE82") LIGHTPERIWINKLE = ManimColor("#C1C6FC") LIGHTPINK = ManimColor("#FFD1DF") LIGHTPLUM = ManimColor("#9D5783") LIGHTPURPLE = ManimColor("#BF77F6") LIGHTRED = ManimColor("#FF474C") LIGHTROSE = ManimColor("#FFC5CB") LIGHTROYALBLUE = ManimColor("#3A2EFE") LIGHTSAGE = ManimColor("#BCECAC") LIGHTSALMON = ManimColor("#FEA993") LIGHTSEAFOAM = ManimColor("#A0FEBF") LIGHTSEAFOAMGREEN = ManimColor("#a7ffb5") LIGHTSEAGREEN = ManimColor("#98F6B0") LIGHTSKYBLUE = ManimColor("#C6FCFF") LIGHTTAN = ManimColor("#FBEEAC") LIGHTTEAL = ManimColor("#90E4C1") LIGHTTURQUOISE = ManimColor("#7EF4CC") LIGHTURPLE = ManimColor("#B36FF6") LIGHTVIOLET = ManimColor("#D6B4FC") LIGHTYELLOW = ManimColor("#FFFE7A") LIGHTYELLOWGREEN = ManimColor("#CCFD7F") LIGHTYELLOWISHGREEN = ManimColor("#C2FF89") LILAC = ManimColor("#CEA2FD") LILIAC = ManimColor("#C48EFD") LIME = ManimColor("#AAFF32") LIMEGREEN = ManimColor("#89FE05") LIMEYELLOW = ManimColor("#D0FE1D") LIPSTICK = ManimColor("#D5174E") LIPSTICKRED = ManimColor("#C0022F") MACARONIANDCHEESE = ManimColor("#EFB435") MAGENTA = ManimColor("#C20078") MAHOGANY = ManimColor("#4A0100") MAIZE = ManimColor("#F4D054") MANGO = ManimColor("#FFA62B") MANILLA = ManimColor("#FFFA86") MARIGOLD = ManimColor("#FCC006") MARINE = ManimColor("#042E60") MARINEBLUE = ManimColor("#01386A") MAROON = ManimColor("#650021") MAUVE = ManimColor("#AE7181") MEDIUMBLUE = ManimColor("#2C6FBB") MEDIUMBROWN = ManimColor("#7F5112") MEDIUMGREEN = ManimColor("#39AD48") MEDIUMGREY = ManimColor("#7D7F7C") MEDIUMPINK = ManimColor("#F36196") MEDIUMPURPLE = ManimColor("#9E43A2") MELON = ManimColor("#FF7855") MERLOT = ManimColor("#730039") METALLICBLUE = ManimColor("#4F738E") MIDBLUE = ManimColor("#276AB3") MIDGREEN = ManimColor("#50A747") MIDNIGHT = ManimColor("#03012D") MIDNIGHTBLUE = ManimColor("#020035") MIDNIGHTPURPLE = ManimColor("#280137") MILITARYGREEN = ManimColor("#667C3E") MILKCHOCOLATE = ManimColor("#7F4E1E") MINT = ManimColor("#9FFEB0") MINTGREEN = ManimColor("#8FFF9F") MINTYGREEN = ManimColor("#0BF77D") MOCHA = ManimColor("#9D7651") MOSS = ManimColor("#769958") MOSSGREEN = ManimColor("#658B38") MOSSYGREEN = ManimColor("#638B27") MUD = ManimColor("#735C12") MUDBROWN = ManimColor("#60460F") MUDDYBROWN = ManimColor("#886806") MUDDYGREEN = ManimColor("#657432") MUDDYYELLOW = ManimColor("#BFAC05") MUDGREEN = ManimColor("#606602") MULBERRY = ManimColor("#920A4E") MURKYGREEN = ManimColor("#6C7A0E") MUSHROOM = ManimColor("#BA9E88") MUSTARD = ManimColor("#CEB301") MUSTARDBROWN = ManimColor("#AC7E04") MUSTARDGREEN = ManimColor("#A8B504") MUSTARDYELLOW = ManimColor("#D2BD0A") MUTEDBLUE = ManimColor("#3B719F") MUTEDGREEN = ManimColor("#5FA052") MUTEDPINK = ManimColor("#D1768F") MUTEDPURPLE = ManimColor("#805B87") NASTYGREEN = ManimColor("#70B23F") NAVY = ManimColor("#01153E") NAVYBLUE = ManimColor("#001146") NAVYGREEN = ManimColor("#35530A") NEONBLUE = ManimColor("#04D9FF") NEONGREEN = ManimColor("#0CFF0C") NEONPINK = ManimColor("#FE019A") NEONPURPLE = ManimColor("#BC13FE") NEONRED = ManimColor("#FF073A") NEONYELLOW = ManimColor("#CFFF04") NICEBLUE = ManimColor("#107AB0") NIGHTBLUE = ManimColor("#040348") OCEAN = ManimColor("#017B92") OCEANBLUE = ManimColor("#03719C") OCEANGREEN = ManimColor("#3D9973") OCHER = ManimColor("#BF9B0C") OCHRE = ManimColor("#BF9005") OCRE = ManimColor("#C69C04") OFFBLUE = ManimColor("#5684AE") OFFGREEN = ManimColor("#6BA353") OFFWHITE = ManimColor("#FFFFE4") OFFYELLOW = ManimColor("#F1F33F") OLDPINK = ManimColor("#C77986") OLDROSE = ManimColor("#C87F89") OLIVE = ManimColor("#6E750E") OLIVEBROWN = ManimColor("#645403") OLIVEDRAB = ManimColor("#6F7632") OLIVEGREEN = ManimColor("#677A04") OLIVEYELLOW = ManimColor("#C2B709") ORANGE = ManimColor("#F97306") ORANGEBROWN = ManimColor("#BE6400") ORANGEISH = ManimColor("#FD8D49") ORANGEPINK = ManimColor("#FF6F52") ORANGERED = ManimColor("#FE420F") ORANGEYBROWN = ManimColor("#B16002") ORANGEYELLOW = ManimColor("#FFAD01") ORANGEYRED = ManimColor("#FA4224") ORANGEYYELLOW = ManimColor("#FDB915") ORANGISH = ManimColor("#FC824A") ORANGISHBROWN = ManimColor("#B25F03") ORANGISHRED = ManimColor("#F43605") ORCHID = ManimColor("#C875C4") PALE = ManimColor("#FFF9D0") PALEAQUA = ManimColor("#B8FFEB") PALEBLUE = ManimColor("#D0FEFE") PALEBROWN = ManimColor("#B1916E") PALECYAN = ManimColor("#B7FFFA") PALEGOLD = ManimColor("#FDDE6C") PALEGREEN = ManimColor("#C7FDB5") PALEGREY = ManimColor("#FDFDFE") PALELAVENDER = ManimColor("#EECFFE") PALELIGHTGREEN = ManimColor("#B1FC99") PALELILAC = ManimColor("#E4CBFF") PALELIME = ManimColor("#BEFD73") PALELIMEGREEN = ManimColor("#B1FF65") PALEMAGENTA = ManimColor("#D767AD") PALEMAUVE = ManimColor("#FED0FC") PALEOLIVE = ManimColor("#B9CC81") PALEOLIVEGREEN = ManimColor("#B1D27B") PALEORANGE = ManimColor("#FFA756") PALEPEACH = ManimColor("#FFE5AD") PALEPINK = ManimColor("#FFCFDC") PALEPURPLE = ManimColor("#B790D4") PALERED = ManimColor("#D9544D") PALEROSE = ManimColor("#FDC1C5") PALESALMON = ManimColor("#FFB19A") PALESKYBLUE = ManimColor("#BDF6FE") PALETEAL = ManimColor("#82CBB2") PALETURQUOISE = ManimColor("#A5FBD5") PALEVIOLET = ManimColor("#CEAEFA") PALEYELLOW = ManimColor("#FFFF84") PARCHMENT = ManimColor("#FEFCAF") PASTELBLUE = ManimColor("#A2BFFE") PASTELGREEN = ManimColor("#B0FF9D") PASTELORANGE = ManimColor("#FF964F") PASTELPINK = ManimColor("#FFBACD") PASTELPURPLE = ManimColor("#CAA0FF") PASTELRED = ManimColor("#DB5856") PASTELYELLOW = ManimColor("#FFFE71") PEA = ManimColor("#A4BF20") PEACH = ManimColor("#FFB07C") PEACHYPINK = ManimColor("#FF9A8A") PEACOCKBLUE = ManimColor("#016795") PEAGREEN = ManimColor("#8EAB12") PEAR = ManimColor("#CBF85F") PEASOUP = ManimColor("#929901") PEASOUPGREEN = ManimColor("#94A617") PERIWINKLE = ManimColor("#8E82FE") PERIWINKLEBLUE = ManimColor("#8F99FB") PERRYWINKLE = ManimColor("#8F8CE7") PETROL = ManimColor("#005F6A") PIGPINK = ManimColor("#E78EA5") PINE = ManimColor("#2B5D34") PINEGREEN = ManimColor("#0A481E") PINK = ManimColor("#FF81C0") PINKISH = ManimColor("#D46A7E") PINKISHBROWN = ManimColor("#B17261") PINKISHGREY = ManimColor("#C8ACA9") PINKISHORANGE = ManimColor("#FF724C") PINKISHPURPLE = ManimColor("#D648D7") PINKISHRED = ManimColor("#F10C45") PINKISHTAN = ManimColor("#D99B82") PINKPURPLE = ManimColor("#EF1DE7") PINKRED = ManimColor("#F5054F") PINKY = ManimColor("#FC86AA") PINKYPURPLE = ManimColor("#C94CBE") PINKYRED = ManimColor("#FC2647") PISSYELLOW = ManimColor("#DDD618") PISTACHIO = ManimColor("#C0FA8B") PLUM = ManimColor("#580F41") PLUMPURPLE = ManimColor("#4E0550") POISONGREEN = ManimColor("#40FD14") POO = ManimColor("#8F7303") POOBROWN = ManimColor("#885F01") POOP = ManimColor("#7F5E00") POOPBROWN = ManimColor("#7A5901") POOPGREEN = ManimColor("#6F7C00") POWDERBLUE = ManimColor("#B1D1FC") POWDERPINK = ManimColor("#FFB2D0") PRIMARYBLUE = ManimColor("#0804F9") PRUSSIANBLUE = ManimColor("#004577") PUCE = ManimColor("#A57E52") PUKE = ManimColor("#A5A502") PUKEBROWN = ManimColor("#947706") PUKEGREEN = ManimColor("#9AAE07") PUKEYELLOW = ManimColor("#C2BE0E") PUMPKIN = ManimColor("#E17701") PUMPKINORANGE = ManimColor("#FB7D07") PUREBLUE = ManimColor("#0203E2") PURPLE = ManimColor("#7E1E9C") PURPLEBLUE = ManimColor("#5D21D0") PURPLEBROWN = ManimColor("#673A3F") PURPLEGREY = ManimColor("#866F85") PURPLEISH = ManimColor("#98568D") PURPLEISHBLUE = ManimColor("#6140EF") PURPLEISHPINK = ManimColor("#DF4EC8") PURPLEPINK = ManimColor("#D725DE") PURPLERED = ManimColor("#990147") PURPLEY = ManimColor("#8756E4") PURPLEYBLUE = ManimColor("#5F34E7") PURPLEYGREY = ManimColor("#947E94") PURPLEYPINK = ManimColor("#C83CB9") PURPLISH = ManimColor("#94568C") PURPLISHBLUE = ManimColor("#601EF9") PURPLISHBROWN = ManimColor("#6B4247") PURPLISHGREY = ManimColor("#7A687F") PURPLISHPINK = ManimColor("#CE5DAE") PURPLISHRED = ManimColor("#B0054B") PURPLY = ManimColor("#983FB2") PURPLYBLUE = ManimColor("#661AEE") PURPLYPINK = ManimColor("#F075E6") PUTTY = ManimColor("#BEAE8A") RACINGGREEN = ManimColor("#014600") RADIOACTIVEGREEN = ManimColor("#2CFA1F") RASPBERRY = ManimColor("#B00149") RAWSIENNA = ManimColor("#9A6200") RAWUMBER = ManimColor("#A75E09") REALLYLIGHTBLUE = ManimColor("#D4FFFF") RED = ManimColor("#E50000") REDBROWN = ManimColor("#8B2E16") REDDISH = ManimColor("#C44240") REDDISHBROWN = ManimColor("#7F2B0A") REDDISHGREY = ManimColor("#997570") REDDISHORANGE = ManimColor("#F8481C") REDDISHPINK = ManimColor("#FE2C54") REDDISHPURPLE = ManimColor("#910951") REDDYBROWN = ManimColor("#6E1005") REDORANGE = ManimColor("#FD3C06") REDPINK = ManimColor("#FA2A55") REDPURPLE = ManimColor("#820747") REDVIOLET = ManimColor("#9E0168") REDWINE = ManimColor("#8C0034") RICHBLUE = ManimColor("#021BF9") RICHPURPLE = ManimColor("#720058") ROBINEGGBLUE = ManimColor("#8AF1FE") ROBINSEGG = ManimColor("#6DEDFD") ROBINSEGGBLUE = ManimColor("#98EFF9") ROSA = ManimColor("#FE86A4") ROSE = ManimColor("#CF6275") ROSEPINK = ManimColor("#F7879A") ROSERED = ManimColor("#BE013C") ROSYPINK = ManimColor("#F6688E") ROGUE = ManimColor("#AB1239") ROYAL = ManimColor("#0C1793") ROYALBLUE = ManimColor("#0504AA") ROYALPURPLE = ManimColor("#4B006E") RUBY = ManimColor("#CA0147") RUSSET = ManimColor("#A13905") RUST = ManimColor("#A83C09") RUSTBROWN = ManimColor("#8B3103") RUSTORANGE = ManimColor("#C45508") RUSTRED = ManimColor("#AA2704") RUSTYORANGE = ManimColor("#CD5909") RUSTYRED = ManimColor("#AF2F0D") SAFFRON = ManimColor("#FEB209") SAGE = ManimColor("#87AE73") SAGEGREEN = ManimColor("#88B378") SALMON = ManimColor("#FF796C") SALMONPINK = ManimColor("#FE7B7C") SAND = ManimColor("#E2CA76") SANDBROWN = ManimColor("#CBA560") SANDSTONE = ManimColor("#C9AE74") SANDY = ManimColor("#F1DA7A") SANDYBROWN = ManimColor("#C4A661") SANDYELLOW = ManimColor("#FCE166") SANDYYELLOW = ManimColor("#FDEE73") SAPGREEN = ManimColor("#5C8B15") SAPPHIRE = ManimColor("#2138AB") SCARLET = ManimColor("#BE0119") SEA = ManimColor("#3C9992") SEABLUE = ManimColor("#047495") SEAFOAM = ManimColor("#80F9AD") SEAFOAMBLUE = ManimColor("#78D1B6") SEAFOAMGREEN = ManimColor("#7AF9AB") SEAGREEN = ManimColor("#53FCA1") SEAWEED = ManimColor("#18D17B") SEAWEEDGREEN = ManimColor("#35AD6B") SEPIA = ManimColor("#985E2B") SHAMROCK = ManimColor("#01B44C") SHAMROCKGREEN = ManimColor("#02C14D") SHIT = ManimColor("#7F5F00") SHITBROWN = ManimColor("#7B5804") SHITGREEN = ManimColor("#758000") SHOCKINGPINK = ManimColor("#FE02A2") SICKGREEN = ManimColor("#9DB92C") SICKLYGREEN = ManimColor("#94B21C") SICKLYYELLOW = ManimColor("#D0E429") SIENNA = ManimColor("#A9561E") SILVER = ManimColor("#C5C9C7") SKY = ManimColor("#82CAFC") SKYBLUE = ManimColor("#75BBFD") SLATE = ManimColor("#516572") SLATEBLUE = ManimColor("#5B7C99") SLATEGREEN = ManimColor("#658D6D") SLATEGREY = ManimColor("#59656D") SLIMEGREEN = ManimColor("#99CC04") SNOT = ManimColor("#ACBB0D") SNOTGREEN = ManimColor("#9DC100") SOFTBLUE = ManimColor("#6488EA") SOFTGREEN = ManimColor("#6FC276") SOFTPINK = ManimColor("#FDB0C0") SOFTPURPLE = ManimColor("#A66FB5") SPEARMINT = ManimColor("#1EF876") SPRINGGREEN = ManimColor("#A9F971") SPRUCE = ManimColor("#0A5F38") SQUASH = ManimColor("#F2AB15") STEEL = ManimColor("#738595") STEELBLUE = ManimColor("#5A7D9A") STEELGREY = ManimColor("#6F828A") STONE = ManimColor("#ADA587") STORMYBLUE = ManimColor("#507B9C") STRAW = ManimColor("#FCF679") STRAWBERRY = ManimColor("#FB2943") STRONGBLUE = ManimColor("#0C06F7") STRONGPINK = ManimColor("#FF0789") SUNFLOWER = ManimColor("#FFC512") SUNFLOWERYELLOW = ManimColor("#FFDA03") SUNNYYELLOW = ManimColor("#FFF917") SUNSHINEYELLOW = ManimColor("#FFFD37") SUNYELLOW = ManimColor("#FFDF22") SWAMP = ManimColor("#698339") SWAMPGREEN = ManimColor("#748500") TAN = ManimColor("#D1B26F") TANBROWN = ManimColor("#AB7E4C") TANGERINE = ManimColor("#FF9408") TANGREEN = ManimColor("#A9BE70") TAUPE = ManimColor("#B9A281") TEA = ManimColor("#65AB7C") TEAGREEN = ManimColor("#BDF8A3") TEAL = ManimColor("#029386") TEALBLUE = ManimColor("#01889F") TEALGREEN = ManimColor("#25A36F") TEALISH = ManimColor("#24BCA8") TEALISHGREEN = ManimColor("#0CDC73") TERRACOTA = ManimColor("#CB6843") TERRACOTTA = ManimColor("#C9643B") TIFFANYBLUE = ManimColor("#7BF2DA") TOMATO = ManimColor("#EF4026") TOMATORED = ManimColor("#EC2D01") TOPAZ = ManimColor("#13BBAF") TOUPE = ManimColor("#C7AC7D") TOXICGREEN = ManimColor("#61DE2A") TREEGREEN = ManimColor("#2A7E19") TRUEBLUE = ManimColor("#010FCC") TRUEGREEN = ManimColor("#089404") TURQUOISE = ManimColor("#06C2AC") TURQUOISEBLUE = ManimColor("#06B1C4") TURQUOISEGREEN = ManimColor("#04F489") TURTLEGREEN = ManimColor("#75B84F") TWILIGHT = ManimColor("#4E518B") TWILIGHTBLUE = ManimColor("#0A437A") UGLYBLUE = ManimColor("#31668A") UGLYBROWN = ManimColor("#7D7103") UGLYGREEN = ManimColor("#7A9703") UGLYPINK = ManimColor("#CD7584") UGLYPURPLE = ManimColor("#A442A0") UGLYYELLOW = ManimColor("#D0C101") ULTRAMARINE = ManimColor("#2000B1") ULTRAMARINEBLUE = ManimColor("#1805DB") UMBER = ManimColor("#B26400") VELVET = ManimColor("#750851") VERMILION = ManimColor("#F4320C") VERYDARKBLUE = ManimColor("#000133") VERYDARKBROWN = ManimColor("#1D0200") VERYDARKGREEN = ManimColor("#062E03") VERYDARKPURPLE = ManimColor("#2A0134") VERYLIGHTBLUE = ManimColor("#D5FFFF") VERYLIGHTBROWN = ManimColor("#D3B683") VERYLIGHTGREEN = ManimColor("#D1FFBD") VERYLIGHTPINK = ManimColor("#FFF4F2") VERYLIGHTPURPLE = ManimColor("#F6CEFC") VERYPALEBLUE = ManimColor("#D6FFFE") VERYPALEGREEN = ManimColor("#CFFDBC") VIBRANTBLUE = ManimColor("#0339F8") VIBRANTGREEN = ManimColor("#0ADD08") VIBRANTPURPLE = ManimColor("#AD03DE") VIOLET = ManimColor("#9A0EEA") VIOLETBLUE = ManimColor("#510AC9") VIOLETPINK = ManimColor("#FB5FFC") VIOLETRED = ManimColor("#A50055") VIRIDIAN = ManimColor("#1E9167") VIVIDBLUE = ManimColor("#152EFF") VIVIDGREEN = ManimColor("#2FEF10") VIVIDPURPLE = ManimColor("#9900FA") VOMIT = ManimColor("#A2A415") VOMITGREEN = ManimColor("#89A203") VOMITYELLOW = ManimColor("#C7C10C") WARMBLUE = ManimColor("#4B57DB") WARMBROWN = ManimColor("#964E02") WARMGREY = ManimColor("#978A84") WARMPINK = ManimColor("#FB5581") WARMPURPLE = ManimColor("#952E8F") WASHEDOUTGREEN = ManimColor("#BCF5A6") WATERBLUE = ManimColor("#0E87CC") WATERMELON = ManimColor("#FD4659") WEIRDGREEN = ManimColor("#3AE57F") WHEAT = ManimColor("#FBDD7E") WHITE = ManimColor("#FFFFFF") WINDOWSBLUE = ManimColor("#3778BF") WINE = ManimColor("#80013F") WINERED = ManimColor("#7B0323") WINTERGREEN = ManimColor("#20F986") WISTERIA = ManimColor("#A87DC2") YELLOW = ManimColor("#FFFF14") YELLOWBROWN = ManimColor("#B79400") YELLOWGREEN = ManimColor("#BBF90F") YELLOWISH = ManimColor("#FAEE66") YELLOWISHBROWN = ManimColor("#9B7A01") YELLOWISHGREEN = ManimColor("#B0DD16") YELLOWISHORANGE = ManimColor("#FFAB0F") YELLOWISHTAN = ManimColor("#FCFC81") YELLOWOCHRE = ManimColor("#CB9D06") YELLOWORANGE = ManimColor("#FCB001") YELLOWTAN = ManimColor("#FFE36E") YELLOWYBROWN = ManimColor("#AE8B0C") YELLOWYGREEN = ManimColor("#BFF128") ================================================ FILE: manim/utils/color/__init__.py ================================================ """Utilities for working with colors and predefined color constants. Color data structure -------------------- .. autosummary:: :toctree: ../reference core Predefined colors ----------------- There are several predefined colors available in Manim: - The colors listed in :mod:`.color.manim_colors` are loaded into Manim's global name space. - The colors in :mod:`.color.AS2700`, :mod:`.color.BS381`, :mod:`.color.DVIPSNAMES`, :mod:`.color.SVGNAMES`, :mod:`.color.X11` and :mod:`.color.XKCD` need to be accessed via their module (which are available in Manim's global name space), or imported separately. For example: .. code:: pycon >>> from manim import XKCD >>> XKCD.AVOCADO ManimColor('#90B134') Or, alternatively: .. code:: pycon >>> from manim.utils.color.XKCD import AVOCADO >>> AVOCADO ManimColor('#90B134') The following modules contain the predefined color constants: .. autosummary:: :toctree: ../reference manim_colors AS2700 BS381 DVIPSNAMES SVGNAMES XKCD X11 """ from __future__ import annotations from . import AS2700, BS381, DVIPSNAMES, SVGNAMES, X11, XKCD from .core import * from .manim_colors import * _all_color_dict: dict[str, ManimColor] = { k: v for k, v in globals().items() if isinstance(v, ManimColor) } ================================================ FILE: manim/utils/color/core.py ================================================ """Manim's (internal) color data structure and some utilities for color conversion. This module contains the implementation of :class:`.ManimColor`, the data structure internally used to represent colors. The preferred way of using these colors is by importing their constants from Manim: .. code-block:: pycon >>> from manim import RED, GREEN, BLUE >>> print(RED) #FC6255 Note that this way uses the name of the colors in UPPERCASE. .. note:: The colors with a ``_C`` suffix have an alias equal to the colorname without a letter. For example, ``GREEN = GREEN_C``. =================== Custom Color Spaces =================== Hello, dear visitor. You seem to be interested in implementing a custom color class for a color space we don't currently support. The current system is using a few indirections for ensuring a consistent behavior with all other color types in Manim. To implement a custom color space, you must subclass :class:`ManimColor` and implement three important methods: - :attr:`~.ManimColor._internal_value`: a ``@property`` implemented on :class:`ManimColor` with the goal of keeping a consistent internal representation which can be referenced by other functions in :class:`ManimColor`. This property acts as a proxy to whatever representation you need in your class. - The getter should always return a NumPy array in the format ``[r,g,b,a]``, in accordance with the type :class:`ManimColorInternal`. - The setter should always accept a value in the format ``[r,g,b,a]`` which can be converted to whatever attributes you need. - :attr:`~ManimColor._internal_space`: a read-only ``@property`` implemented on :class:`ManimColor` with the goal of providing a useful representation which can be used by operators, interpolation and color transform functions. The only constraints on this value are: - It must be a NumPy array. - The last value must be the opacity in a range ``0.0`` to ``1.0``. Additionally, your ``__init__`` must support this format as an initialization value without additional parameters to ensure correct functionality of all other methods in :class:`ManimColor`. - :meth:`~ManimColor._from_internal`: a ``@classmethod`` which converts an ``[r,g,b,a]`` value into suitable parameters for your ``__init__`` method and calls the ``cls`` parameter. """ from __future__ import annotations import colorsys # logger = _config.logger import random import re from collections.abc import Iterable, Sequence from typing import Self, TypeAlias, TypeVar, overload import numpy as np import numpy.typing as npt from typing_extensions import TypeIs, override from manim.typing import ( FloatHSL, FloatHSLLike, FloatHSV, FloatHSVA, FloatHSVALike, FloatHSVLike, FloatRGB, FloatRGBA, FloatRGBALike, FloatRGBLike, IntRGB, IntRGBA, IntRGBALike, IntRGBLike, ManimColorDType, ManimColorInternal, ManimFloat, Point3D, Vector3D, ) from ...utils.space_ops import normalize # import manim._config as _config re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{3,8}", re.IGNORECASE) class ManimColor: """Internal representation of a color. The :class:`ManimColor` class is the main class for the representation of a color. Its internal representation is an array of 4 floats corresponding to a ``[r,g,b,a]`` value where ``r,g,b,a`` can be between 0.0 and 1.0. This is done in order to reduce the amount of color inconsistencies by constantly casting between integers and floats which introduces errors. The class can accept any value of type :class:`ParsableManimColor` i.e. ``ManimColor, int, str, RGB_Tuple_Int, RGB_Tuple_Float, RGBA_Tuple_Int, RGBA_Tuple_Float, RGB_Array_Int, RGB_Array_Float, RGBA_Array_Int, RGBA_Array_Float`` :class:`ManimColor` itself only accepts singular values and will directly interpret them into a single color if possible. Be careful when passing strings to :class:`ManimColor`: it can create a big overhead for the color processing. If you want to parse a list of colors, use the :meth:`parse` method, which assumes that you're going to pass a list of colors so that arrays will not be interpreted as a single color. .. warning:: If you pass an array of numbers to :meth:`parse`, it will interpret the ``r,g,b,a`` numbers in that array as colors: Instead of the expected singular color, you will get an array with 4 colors. For conversion behaviors, see the ``_internal`` functions for further documentation. You can create a :class:`ManimColor` instance via its classmethods. See the respective methods for more info. .. code-block:: python mycolor = ManimColor.from_rgb((0, 1, 0.4, 0.5)) myothercolor = ManimColor.from_rgb((153, 255, 255)) You can also convert between different color spaces: .. code-block:: python mycolor_hex = mycolor.to_hex() myoriginalcolor = ManimColor.from_hex(mycolor_hex).to_hsv() Parameters ---------- value Some representation of a color (e.g., a string or a suitable tuple). The default ``None`` is ``BLACK``. alpha The opacity of the color. By default, colors are fully opaque (value 1.0). """ def __init__( self, value: ParsableManimColor | None, alpha: float = 1.0, ) -> None: if value is None: self._internal_value = np.array((0, 0, 0, alpha), dtype=ManimColorDType) elif isinstance(value, ManimColor): # logger.info( # "ManimColor was passed another ManimColor. This is probably not what " # "you want. Created a copy of the passed ManimColor instead." # ) self._internal_value = value._internal_value elif isinstance(value, int): self._internal_value = ManimColor._internal_from_integer(value, alpha) elif isinstance(value, str): result = re_hex.search(value) if result is not None: self._internal_value = ManimColor._internal_from_hex_string( result.group(), alpha ) else: # This is not expected to be called on module initialization time # It can be horribly slow to convert a string to a color because # it has to access the dictionary of colors and find the right color self._internal_value = ManimColor._internal_from_string(value, alpha) elif isinstance(value, (list, tuple, np.ndarray)): length = len(value) if all(isinstance(x, float) for x in value): if length == 3: self._internal_value = ManimColor._internal_from_rgb(value, alpha) elif length == 4: self._internal_value = ManimColor._internal_from_rgba(value) else: raise ValueError( f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}" ) else: if length == 3: self._internal_value = ManimColor._internal_from_int_rgb( value, alpha ) elif length == 4: self._internal_value = ManimColor._internal_from_int_rgba(value) else: raise ValueError( f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}" ) elif hasattr(value, "get_hex") and callable(value.get_hex): result = re_hex.search(value.get_hex()) if result is None: raise ValueError(f"Failed to parse a color from {value}") self._internal_value = ManimColor._internal_from_hex_string( result.group(), alpha ) else: # logger.error(f"Invalid color value: {value}") raise TypeError( "ManimColor only accepts int, str, list[int, int, int], " "list[int, int, int, int], list[float, float, float], " f"list[float, float, float, float], not {type(value)}" ) @property def _internal_space(self) -> npt.NDArray[ManimFloat]: """This is a readonly property which is a custom representation for color space operations. It is used for operators and can be used when implementing a custom color space. """ return self._internal_value @property def _internal_value(self) -> ManimColorInternal: """Return the internal value of the current Manim color ``[r,g,b,a]`` float array. Returns ------- ManimColorInternal Internal color representation. """ return self.__value @_internal_value.setter def _internal_value(self, value: ManimColorInternal) -> None: """Overwrite the internal color value of this :class:`ManimColor`. Parameters ---------- value The value which will overwrite the current color. Raises ------ TypeError If an invalid array is passed. """ if not isinstance(value, np.ndarray): raise TypeError("Value must be a NumPy array.") if value.shape[0] != 4: raise TypeError("Array must have exactly 4 values.") self.__value: ManimColorInternal = value @classmethod def _construct_from_space( cls, _space: npt.NDArray[ManimFloat] | tuple[float, float, float] | tuple[float, float, float, float], ) -> Self: """This function is used as a proxy for constructing a color with an internal value. This can be used by subclasses to hook into the construction of new objects using the internal value format. """ return cls(_space) @staticmethod def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal: return np.asarray( ( ((value >> 16) & 0xFF) / 255, ((value >> 8) & 0xFF) / 255, ((value >> 0) & 0xFF) / 255, alpha, ), dtype=ManimColorDType, ) @staticmethod def _internal_from_hex_string(hex_: str, alpha: float) -> ManimColorInternal: """Internal function for converting a hex string into the internal representation of a :class:`ManimColor`. .. warning:: This does not accept any prefixes like # or similar in front of the hex string. This is just intended for the raw hex part. *For internal use only* Parameters ---------- hex Hex string to be parsed. alpha Alpha value used for the color, if the color is only 3 bytes long. Otherwise, if the color is 4 bytes long, this parameter will not be used. Returns ------- ManimColorInternal Internal color representation """ if len(hex_) in (3, 4): hex_ = "".join([x * 2 for x in hex_]) if len(hex_) == 6: hex_ += "FF" elif len(hex_) == 8: alpha = (int(hex_, 16) & 0xFF) / 255 else: raise ValueError( "Hex colors must be specified with either 0x or # as prefix and contain 6 or 8 hexadecimal numbers" ) tmp = int(hex_, 16) return np.asarray( ( ((tmp >> 24) & 0xFF) / 255, ((tmp >> 16) & 0xFF) / 255, ((tmp >> 8) & 0xFF) / 255, alpha, ), dtype=ManimColorDType, ) @staticmethod def _internal_from_int_rgb( rgb: IntRGBLike, alpha: float = 1.0 ) -> ManimColorInternal: """Internal function for converting an RGB tuple of integers into the internal representation of a :class:`ManimColor`. *For internal use only* Parameters ---------- rgb Integer RGB tuple to be parsed alpha Optional alpha value. Default is 1.0. Returns ------- ManimColorInternal Internal color representation. """ value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() / 255 value.resize(4, refcheck=False) value[3] = alpha return value @staticmethod def _internal_from_rgb(rgb: FloatRGBLike, alpha: float = 1.0) -> ManimColorInternal: """Internal function for converting a rgb tuple of floats into the internal representation of a :class:`ManimColor`. *For internal use only* Parameters ---------- rgb Float RGB tuple to be parsed. alpha Optional alpha value. Default is 1.0. Returns ------- ManimColorInternal Internal color representation. """ value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() value.resize(4, refcheck=False) value[3] = alpha return value @staticmethod def _internal_from_int_rgba(rgba: IntRGBALike) -> ManimColorInternal: """Internal function for converting an RGBA tuple of integers into the internal representation of a :class:`ManimColor`. *For internal use only* Parameters ---------- rgba Int RGBA tuple to be parsed. Returns ------- ManimColorInternal Internal color representation. """ return np.asarray(rgba, dtype=ManimColorDType) / 255 @staticmethod def _internal_from_rgba(rgba: FloatRGBALike) -> ManimColorInternal: """Internal function for converting an RGBA tuple of floats into the internal representation of a :class:`ManimColor`. *For internal use only* Parameters ---------- rgba Int RGBA tuple to be parsed. Returns ------- ManimColorInternal Internal color representation. """ return np.asarray(rgba, dtype=ManimColorDType) @staticmethod def _internal_from_string(name: str, alpha: float) -> ManimColorInternal: """Internal function for converting a string into the internal representation of a :class:`ManimColor`. This is not used for hex strings: please refer to :meth:`_internal_from_hex` for this functionality. *For internal use only* Parameters ---------- name The color name to be parsed into a color. Refer to the different color modules in the documentation page to find the corresponding color names. Returns ------- ManimColorInternal Internal color representation. Raises ------ ValueError If the color name is not present in Manim. """ from . import _all_color_dict if tmp := _all_color_dict.get(name.upper()): tmp._internal_value[3] = alpha return tmp._internal_value.copy() else: raise ValueError(f"Color {name} not found") def to_integer(self) -> int: """Convert the current :class:`ManimColor` into an integer. .. warning:: This will return only the RGB part of the color. Returns ------- int Integer representation of the color. """ tmp = (self._internal_value[:3] * 255).astype(dtype=np.byte).tobytes() return int.from_bytes(tmp, "big") def to_rgb(self) -> FloatRGB: """Convert the current :class:`ManimColor` into an RGB array of floats. Returns ------- RGB_Array_Float RGB array of 3 floats from 0.0 to 1.0. """ return self._internal_value[:3] def to_int_rgb(self) -> IntRGB: """Convert the current :class:`ManimColor` into an RGB array of integers. Returns ------- RGB_Array_Int RGB array of 3 integers from 0 to 255. """ return (self._internal_value[:3] * 255).astype(int) def to_rgba(self) -> FloatRGBA: """Convert the current :class:`ManimColor` into an RGBA array of floats. Returns ------- RGBA_Array_Float RGBA array of 4 floats from 0.0 to 1.0. """ return self._internal_value def to_int_rgba(self) -> IntRGBA: """Convert the current ManimColor into an RGBA array of integers. Returns ------- RGBA_Array_Int RGBA array of 4 integers from 0 to 255. """ return (self._internal_value * 255).astype(int) def to_rgba_with_alpha(self, alpha: float) -> FloatRGBA: """Convert the current :class:`ManimColor` into an RGBA array of floats. This is similar to :meth:`to_rgba`, but you can change the alpha value. Parameters ---------- alpha Alpha value to be used in the return value. Returns ------- RGBA_Array_Float RGBA array of 4 floats from 0.0 to 1.0. """ return np.fromiter((*self._internal_value[:3], alpha), dtype=ManimColorDType) def to_int_rgba_with_alpha(self, alpha: float) -> IntRGBA: """Convert the current :class:`ManimColor` into an RGBA array of integers. This is similar to :meth:`to_int_rgba`, but you can change the alpha value. Parameters ---------- alpha Alpha value to be used for the return value. Pass a float between 0.0 and 1.0: it will automatically be scaled to an integer between 0 and 255. Returns ------- RGBA_Array_Int RGBA array of 4 integers from 0 to 255. """ tmp = self._internal_value * 255 tmp[3] = alpha * 255 return tmp.astype(int) def to_hex(self, with_alpha: bool = False) -> str: """Convert the :class:`ManimColor` to a hexadecimal representation of the color. Parameters ---------- with_alpha If ``True``, append 2 extra characters to the hex string which represent the alpha value of the color between 0 and 255. Default is ``False``. Returns ------- str A hex string starting with a ``#``, with either 6 or 8 nibbles depending on the ``with_alpha`` parameter. By default, it has 6 nibbles, i.e. ``#XXXXXX``. """ tmp = ( f"#{int(self._internal_value[0] * 255):02X}" f"{int(self._internal_value[1] * 255):02X}" f"{int(self._internal_value[2] * 255):02X}" ) if with_alpha: tmp += f"{int(self._internal_value[3] * 255):02X}" return tmp def to_hsv(self) -> FloatHSV: """Convert the :class:`ManimColor` to an HSV array. .. note:: Be careful: this returns an array in the form ``[h, s, v]``, where the elements are floats. This might be confusing, because RGB can also be an array of floats. You might want to annotate the usage of this function in your code by typing your HSV array variables as :class:`HSV_Array_Float` in order to differentiate them from RGB arrays. Returns ------- HSV_Array_Float An HSV array of 3 floats from 0.0 to 1.0. """ return np.array(colorsys.rgb_to_hsv(*self.to_rgb())) def to_hsl(self) -> FloatHSL: """Convert the :class:`ManimColor` to an HSL array. .. note:: Be careful: this returns an array in the form ``[h, s, l]``, where the elements are floats. This might be confusing, because RGB can also be an array of floats. You might want to annotate the usage of this function in your code by typing your HSL array variables as :class:`HSL_Array_Float` in order to differentiate them from RGB arrays. Returns ------- HSL_Array_Float An HSL array of 3 floats from 0.0 to 1.0. """ hls = colorsys.rgb_to_hls(*self.to_rgb()) return np.array([hls[0], hls[2], hls[1]]) def invert(self, with_alpha: bool = False) -> Self: """Return a new, linearly inverted version of this :class:`ManimColor` (no inplace changes). Parameters ---------- with_alpha If ``True``, the alpha value will be inverted too. Default is ``False``. .. note:: Setting ``with_alpha=True`` can result in unintended behavior where objects are not displayed because their new alpha value is suddenly 0 or very low. Returns ------- ManimColor The linearly inverted :class:`ManimColor`. """ if with_alpha: return self._construct_from_space(1.0 - self._internal_space) else: alpha = self._internal_space[3] new = 1.0 - self._internal_space new[-1] = alpha return self._construct_from_space(new) def interpolate(self, other: Self, alpha: float) -> Self: """Interpolate between the current and the given :class:`ManimColor`, and return the result. Parameters ---------- other The other :class:`ManimColor` to be used for interpolation. alpha A point on the line in RGBA colorspace connecting the two colors, i.e. the interpolation point. 0.0 corresponds to the current :class:`ManimColor` and 1.0 corresponds to the other :class:`ManimColor`. Returns ------- ManimColor The interpolated :class:`ManimColor`. """ return self._construct_from_space( self._internal_space * (1 - alpha) + other._internal_space * alpha ) def darker(self, blend: float = 0.2) -> Self: """Return a new color that is darker than the current color, i.e. interpolated with ``BLACK``. The opacity is unchanged. Parameters ---------- blend The blend ratio for the interpolation, from 0.0 (the current color unchanged) to 1.0 (pure black). Default is 0.2, which results in a slightly darker color. Returns ------- ManimColor The darker :class:`ManimColor`. See Also -------- :meth:`lighter` """ from manim.utils.color.manim_colors import BLACK alpha = self._internal_space[3] black = self._from_internal(BLACK._internal_value) return self.interpolate(black, blend).opacity(alpha) def lighter(self, blend: float = 0.2) -> Self: """Return a new color that is lighter than the current color, i.e. interpolated with ``WHITE``. The opacity is unchanged. Parameters ---------- blend The blend ratio for the interpolation, from 0.0 (the current color unchanged) to 1.0 (pure white). Default is 0.2, which results in a slightly lighter color. Returns ------- ManimColor The lighter :class:`ManimColor`. See Also -------- :meth:`darker` """ from manim.utils.color.manim_colors import WHITE alpha = self._internal_space[3] white = self._from_internal(WHITE._internal_value) return self.interpolate(white, blend).opacity(alpha) def contrasting( self, threshold: float = 0.5, light: Self | None = None, dark: Self | None = None, ) -> Self: """Return one of two colors, light or dark (by default white or black), that contrasts with the current color (depending on its luminance). This is typically used to set text in a contrasting color that ensures it is readable against a background of the current color. Parameters ---------- threshold The luminance threshold which dictates whether the current color is considered light or dark (and thus whether to return the dark or light color, respectively). Default is 0.5. light The light color to return if the current color is considered dark. Default is ``None``: in this case, pure ``WHITE`` will be returned. dark The dark color to return if the current color is considered light, Default is ``None``: in this case, pure ``BLACK`` will be returned. Returns ------- ManimColor The contrasting :class:`ManimColor`. """ from manim.utils.color.manim_colors import BLACK, WHITE luminance, _, _ = colorsys.rgb_to_yiq(*self.to_rgb()) if luminance < threshold: if light is not None: return light return self._from_internal(WHITE._internal_value) else: if dark is not None: return dark return self._from_internal(BLACK._internal_value) def opacity(self, opacity: float) -> Self: """Create a new :class:`ManimColor` with the given opacity and the same color values as before. Parameters ---------- opacity The new opacity value to be used. Returns ------- ManimColor The new :class:`ManimColor` with the same color values and the new opacity. """ tmp = self._internal_space.copy() tmp[-1] = opacity return self._construct_from_space(tmp) def into(self, class_type: type[ManimColorT]) -> ManimColorT: """Convert the current color into a different colorspace given by ``class_type``, without changing the :attr:`_internal_value`. Parameters ---------- class_type The class that is used for conversion. It must be a subclass of :class:`ManimColor` which respects the specification HSV, RGBA, ... Returns ------- ManimColorT A new color object of type ``class_type`` and the same :attr:`_internal_value` as the original color. """ return class_type._from_internal(self._internal_value) @classmethod def _from_internal(cls, value: ManimColorInternal) -> Self: """This method is intended to be overwritten by custom color space classes which are subtypes of :class:`ManimColor`. The method constructs a new object of the given class by transforming the value in the internal format ``[r,g,b,a]`` into a format which the constructor of the custom class can understand. Look at :class:`.HSV` for an example. """ return cls(value) @classmethod def from_rgb( cls, rgb: FloatRGBLike | IntRGBLike, alpha: float = 1.0, ) -> Self: """Create a ManimColor from an RGB array. Automagically decides which type it is: ``int`` or ``float``. .. warning:: Please make sure that your elements are not floats if you want integers. A ``5.0`` will result in the input being interpreted as if it was an RGB float array with the value ``5.0`` and not the integer ``5``. Parameters ---------- rgb Any iterable of 3 floats or 3 integers. alpha Alpha value to be used in the color. Default is 1.0. Returns ------- ManimColor The :class:`ManimColor` which corresponds to the given ``rgb``. """ return cls._from_internal(ManimColor(rgb, alpha)._internal_value) @classmethod def from_rgba(cls, rgba: FloatRGBALike | IntRGBALike) -> Self: """Create a ManimColor from an RGBA Array. Automagically decides which type it is: ``int`` or ``float``. .. warning:: Please make sure that your elements are not floats if you want integers. A ``5.0`` will result in the input being interpreted as if it was a float RGB array with the float ``5.0`` and not the integer ``5``. Parameters ---------- rgba Any iterable of 4 floats or 4 integers. Returns ------- ManimColor The :class:`ManimColor` corresponding to the given ``rgba``. """ return cls(rgba) @classmethod def from_hex(cls, hex_str: str, alpha: float = 1.0) -> Self: """Create a :class:`ManimColor` from a hex string. Parameters ---------- hex_str The hex string to be converted. The allowed prefixes for this string are ``#`` and ``0x``. Currently, this method only supports 6 nibbles, i.e. only strings in the format ``#XXXXXX`` or ``0xXXXXXX``. alpha Alpha value to be used for the hex string. Default is 1.0. Returns ------- ManimColor The :class:`ManimColor` represented by the hex string. """ return cls._from_internal(ManimColor(hex_str, alpha)._internal_value) @classmethod def from_hsv(cls, hsv: FloatHSVLike, alpha: float = 1.0) -> Self: """Create a :class:`ManimColor` from an HSV array. Parameters ---------- hsv Any iterable containing 3 floats from 0.0 to 1.0. alpha The alpha value to be used. Default is 1.0. Returns ------- ManimColor The :class:`ManimColor` with the corresponding RGB values to the given HSV array. """ rgb = colorsys.hsv_to_rgb(*hsv) return cls._from_internal(ManimColor(rgb, alpha)._internal_value) @classmethod def from_hsl(cls, hsl: FloatHSLLike, alpha: float = 1.0) -> Self: """Create a :class:`ManimColor` from an HSL array. Parameters ---------- hsl Any iterable containing 3 floats from 0.0 to 1.0. alpha The alpha value to be used. Default is 1.0. Returns ------- ManimColor The :class:`ManimColor` with the corresponding RGB values to the given HSL array. """ rgb = colorsys.hls_to_rgb(hsl[0], hsl[2], hsl[1]) return cls._from_internal(ManimColor(rgb, alpha)._internal_value) @overload @classmethod def parse( cls, color: ParsableManimColor | None, alpha: float = ..., ) -> Self: ... @overload @classmethod def parse( cls, color: Sequence[ParsableManimColor], alpha: float = ..., ) -> list[Self]: ... @classmethod def parse( cls, color: ParsableManimColor | Sequence[ParsableManimColor] | None, alpha: float = 1.0, ) -> Self | list[Self]: """Parse one color as a :class:`ManimColor` or a sequence of colors as a list of :class:`ManimColor`'s. Parameters ---------- color The color or list of colors to parse. Note that this function can not accept tuples: it will assume that you mean ``Sequence[ParsableManimColor]`` and will return a ``list[ManimColor]``. alpha The alpha (opacity) value to use for the passed color(s). Returns ------- ManimColor | list[ManimColor] Either a list of colors or a singular color, depending on the input. """ def is_sequence( color: ParsableManimColor | Sequence[ParsableManimColor] | None, ) -> TypeIs[Sequence[ParsableManimColor]]: return isinstance(color, (list, tuple)) if is_sequence(color): return [ cls._from_internal(ManimColor(c, alpha)._internal_value) for c in color ] else: return cls._from_internal(ManimColor(color, alpha)._internal_value) @staticmethod def gradient( colors: list[ManimColor], length: int ) -> ManimColor | list[ManimColor]: """This method is currently not implemented. Refer to :func:`color_gradient` for a working implementation for now. """ # TODO: implement proper gradient, research good implementation for this or look at 3b1b implementation raise NotImplementedError def __repr__(self) -> str: return f"{self.__class__.__name__}('{self.to_hex()}')" def __str__(self) -> str: return f"{self.to_hex()}" def __eq__(self, other: object) -> bool: if not isinstance(other, ManimColor): raise TypeError( f"Cannot compare {self.__class__.__name__} with {other.__class__.__name__}" ) are_equal: bool = np.allclose(self._internal_value, other._internal_value) return are_equal def __add__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space + other) else: return self._construct_from_space( self._internal_space + other._internal_space ) def __radd__(self, other: int | float | Self) -> Self: return self + other def __sub__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space - other) else: return self._construct_from_space( self._internal_space - other._internal_space ) def __rsub__(self, other: int | float | Self) -> Self: return self - other def __mul__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space * other) else: return self._construct_from_space( self._internal_space * other._internal_space ) def __rmul__(self, other: int | float | Self) -> Self: return self * other def __truediv__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space / other) else: return self._construct_from_space( self._internal_space / other._internal_space ) def __rtruediv__(self, other: int | float | Self) -> Self: return self / other def __floordiv__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space // other) else: return self._construct_from_space( self._internal_space // other._internal_space ) def __rfloordiv__(self, other: int | float | Self) -> Self: return self // other def __mod__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space % other) else: return self._construct_from_space( self._internal_space % other._internal_space ) def __rmod__(self, other: int | float | Self) -> Self: return self % other def __pow__(self, other: int | float | Self) -> Self: if isinstance(other, (int, float)): return self._construct_from_space(self._internal_space**other) else: return self._construct_from_space( self._internal_space**other._internal_space ) def __rpow__(self, other: int | float | Self) -> Self: return self**other def __invert__(self) -> Self: return self.invert() def __int__(self) -> int: return self.to_integer() def __getitem__(self, index: int) -> float: item: float = self._internal_space[index] return item def __and__(self, other: Self) -> Self: return self._construct_from_space( self._internal_from_integer(self.to_integer() & int(other), 1.0) ) def __or__(self, other: Self) -> Self: return self._construct_from_space( self._internal_from_integer(self.to_integer() | int(other), 1.0) ) def __xor__(self, other: Self) -> Self: return self._construct_from_space( self._internal_from_integer(self.to_integer() ^ int(other), 1.0) ) def __hash__(self) -> int: return hash(self.to_hex(with_alpha=True)) RGBA = ManimColor """RGBA Color Space""" class HSV(ManimColor): """HSV Color Space""" def __init__( self, hsv: FloatHSVLike | FloatHSVALike, alpha: float = 1.0, ) -> None: super().__init__(None) self.__hsv: FloatHSVA if len(hsv) == 3: self.__hsv = np.asarray((*hsv, alpha)) elif len(hsv) == 4: self.__hsv = np.asarray(hsv) else: raise ValueError("HSV Color must be an array of 3 values") @classmethod @override def _from_internal(cls, value: ManimColorInternal) -> Self: hsv = colorsys.rgb_to_hsv(*value[:3]) hsva = [*hsv, value[-1]] return cls(np.array(hsva)) @property def hue(self) -> float: hue: float = self.__hsv[0] return hue @hue.setter def hue(self, hue: float) -> None: self.__hsv[0] = hue @property def saturation(self) -> float: saturation: float = self.__hsv[1] return saturation @saturation.setter def saturation(self, saturation: float) -> None: self.__hsv[1] = saturation @property def value(self) -> float: value: float = self.__hsv[2] return value @value.setter def value(self, value: float) -> None: self.__hsv[2] = value @property def h(self) -> float: hue: float = self.__hsv[0] return hue @h.setter def h(self, hue: float) -> None: self.__hsv[0] = hue @property def s(self) -> float: saturation: float = self.__hsv[1] return saturation @s.setter def s(self, saturation: float) -> None: self.__hsv[1] = saturation @property def v(self) -> float: value: float = self.__hsv[2] return value @v.setter def v(self, value: float) -> None: self.__hsv[2] = value @property def _internal_space(self) -> npt.NDArray: return self.__hsv @property def _internal_value(self) -> ManimColorInternal: """Return the internal value of the current :class:`ManimColor` as an ``[r,g,b,a]`` float array. Returns ------- ManimColorInternal Internal color representation. """ return np.array( [ *colorsys.hsv_to_rgb(self.__hsv[0], self.__hsv[1], self.__hsv[2]), self.__alpha, ], dtype=ManimColorDType, ) @_internal_value.setter def _internal_value(self, value: ManimColorInternal) -> None: """Overwrite the internal color value of this :class:`ManimColor`. Parameters ---------- value The value which will overwrite the current color. Raises ------ TypeError If an invalid array is passed. """ if not isinstance(value, np.ndarray): raise TypeError("Value must be a NumPy array.") if value.shape[0] != 4: raise TypeError("Array must have exactly 4 values.") tmp = colorsys.rgb_to_hsv(value[0], value[1], value[2]) self.__hsv = np.array(tmp) self.__alpha = value[3] ParsableManimColor: TypeAlias = ( ManimColor | int | str | IntRGBLike | FloatRGBLike | IntRGBALike | FloatRGBALike ) """`ParsableManimColor` represents all the types which can be parsed to a :class:`ManimColor` in Manim. """ ManimColorT = TypeVar("ManimColorT", bound=ManimColor) def color_to_rgb(color: ParsableManimColor) -> FloatRGB: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.to_rgb`. Parameters ---------- color A color to convert to an RGB float array. Returns ------- RGB_Array_Float The corresponding RGB float array. """ return ManimColor(color).to_rgb() def color_to_rgba(color: ParsableManimColor, alpha: float = 1.0) -> FloatRGBA: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.to_rgba_with_alpha`. Parameters ---------- color A color to convert to an RGBA float array. alpha An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is 1.0. Returns ------- RGBA_Array_Float The corresponding RGBA float array. """ return ManimColor(color).to_rgba_with_alpha(alpha) def color_to_int_rgb(color: ParsableManimColor) -> IntRGB: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.to_int_rgb`. Parameters ---------- color A color to convert to an RGB integer array. Returns ------- RGB_Array_Int The corresponding RGB integer array. """ return ManimColor(color).to_int_rgb() def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> IntRGBA: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.to_int_rgba_with_alpha`. Parameters ---------- color A color to convert to an RGBA integer array. alpha An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is 1.0. Returns ------- RGBA_Array_Int The corresponding RGBA integer array. """ return ManimColor(color).to_int_rgba_with_alpha(alpha) def rgb_to_color(rgb: FloatRGBLike | IntRGBLike) -> ManimColor: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.from_rgb`. Parameters ---------- rgb A 3 element iterable. Returns ------- ManimColor A ManimColor with the corresponding value. """ return ManimColor.from_rgb(rgb) def rgba_to_color(rgba: FloatRGBALike | IntRGBALike) -> ManimColor: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.from_rgba`. Parameters ---------- rgba A 4 element iterable. Returns ------- ManimColor A ManimColor with the corresponding value """ return ManimColor.from_rgba(rgba) def rgb_to_hex(rgb: FloatRGBLike | IntRGBLike) -> str: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.from_rgb` and :meth:`ManimColor.to_hex`. Parameters ---------- rgb A 3 element iterable. Returns ------- str A hex representation of the color. """ return ManimColor.from_rgb(rgb).to_hex() def hex_to_rgb(hex_code: str) -> FloatRGB: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.to_rgb`. Parameters ---------- hex_code A hex string representing a color. Returns ------- RGB_Array_Float An RGB array representing the color. """ return ManimColor(hex_code).to_rgb() def invert_color(color: ManimColorT) -> ManimColorT: """Helper function for use in functional style programming. Refer to :meth:`ManimColor.invert` Parameters ---------- color The :class:`ManimColor` to invert. Returns ------- ManimColor The linearly inverted :class:`ManimColor`. """ return color.invert() def color_gradient( reference_colors: Iterable[ParsableManimColor], length_of_output: int, ) -> list[ManimColor]: """Create a list of colors interpolated between the input array of colors with a specific number of colors. Parameters ---------- reference_colors The colors to be interpolated between or spread apart. length_of_output The number of colors that the output should have, ideally more than the input. Returns ------- list[ManimColor] A list of interpolated :class:`ManimColor`'s. """ if length_of_output == 0: return [] parsed_colors = [ManimColor(color) for color in reference_colors] num_colors = len(parsed_colors) if num_colors == 0: raise ValueError("Expected 1 or more reference colors. Got 0 colors.") if num_colors == 1: return parsed_colors * length_of_output rgbs = [color.to_rgb() for color in parsed_colors] alphas = np.linspace(0, (num_colors - 1), length_of_output) floors = alphas.astype("int") alphas_mod1 = alphas % 1 # End edge case alphas_mod1[-1] = 1 floors[-1] = num_colors - 2 return [ rgb_to_color((rgbs[i] * (1 - alpha)) + (rgbs[i + 1] * alpha)) for i, alpha in zip(floors, alphas_mod1, strict=True) ] def interpolate_color( color1: ManimColorT, color2: ManimColorT, alpha: float ) -> ManimColorT: """Standalone function to interpolate two ManimColors and get the result. Refer to :meth:`ManimColor.interpolate`. Parameters ---------- color1 The first :class:`ManimColor`. color2 The second :class:`ManimColor`. alpha The alpha value determining the point of interpolation between the colors. Returns ------- ManimColor The interpolated ManimColor. """ return color1.interpolate(color2, alpha) def average_color(*colors: ParsableManimColor) -> ManimColor: """Determine the average color between the given parameters. .. note:: This operation does not consider the alphas (opacities) of the colors. The generated color has an alpha or opacity of 1.0. Returns ------- ManimColor The average color of the input. """ rgbs = np.array([color_to_rgb(color) for color in colors]) mean_rgb = np.apply_along_axis(np.mean, 0, rgbs) return rgb_to_color(mean_rgb) def random_bright_color() -> ManimColor: """Return a random bright color: a random color averaged with ``WHITE``. .. warning:: This operation is very expensive. Please keep in mind the performance loss. Returns ------- ManimColor A random bright :class:`ManimColor`. """ curr_rgb = color_to_rgb(random_color()) new_rgb = 0.5 * (curr_rgb + np.ones(3)) return ManimColor(new_rgb) def random_color() -> ManimColor: """Return a random :class:`ManimColor`. Returns ------- ManimColor A random :class:`ManimColor`. """ return RandomColorGenerator._random_color() class RandomColorGenerator: """A generator for producing random colors from a given list of Manim colors, optionally in a reproducible sequence using a seed value. When initialized with a specific seed, this class produces a deterministic sequence of :class:`.ManimColor` instances. If no seed is provided, the selection is non-deterministic using Python’s global random state. Parameters ---------- seed A seed value to initialize the internal random number generator. If ``None`` (the default), colors are chosen using the global random state. sample_colors A custom list of Manim colors to sample from. Defaults to the full Manim color palette. Examples -------- Without a seed (non-deterministic):: >>> from manim import RandomColorGenerator, ManimColor, RED, GREEN, BLUE >>> rnd = RandomColorGenerator() >>> isinstance(rnd.next(), ManimColor) True With a seed (deterministic sequence):: >>> rnd = RandomColorGenerator(42) >>> rnd.next() ManimColor('#8B4513') >>> rnd.next() ManimColor('#BBBBBB') >>> rnd.next() ManimColor('#BBBBBB') Re-initializing with the same seed gives the same sequence:: >>> rnd2 = RandomColorGenerator(42) >>> rnd2.next() ManimColor('#8B4513') >>> rnd2.next() ManimColor('#BBBBBB') >>> rnd2.next() ManimColor('#BBBBBB') Using a custom color list:: >>> custom_palette = [RED, GREEN, BLUE] >>> rnd_custom = RandomColorGenerator(1, sample_colors=custom_palette) >>> rnd_custom.next() in custom_palette True >>> rnd_custom.next() in custom_palette True Without a seed and custom palette (non-deterministic):: >>> rnd_nodet = RandomColorGenerator(sample_colors=[RED]) >>> rnd_nodet.next() ManimColor('#FC6255') """ _singleton: RandomColorGenerator | None = None def __init__( self, seed: int | None = None, sample_colors: list[ManimColor] | None = None, ) -> None: from manim.utils.color.manim_colors import _all_manim_colors self.choice = random.choice if seed is None else random.Random(seed).choice self.colors = _all_manim_colors if sample_colors is None else sample_colors def next(self) -> ManimColor: """Returns the next color from the configured color list. Returns ------- ManimColor A randomly selected color from the specified color list. Examples -------- Usage:: >>> from manim import RandomColorGenerator, RED >>> rnd = RandomColorGenerator(sample_colors=[RED]) >>> rnd.next() ManimColor('#FC6255') """ return self.choice(self.colors) @classmethod def _random_color(cls) -> ManimColor: """Internal method to generate a random color using the singleton instance of `RandomColorGenerator`. It will be used by proxy method `random_color` publicly available and makes it backwards compatible. Returns ------- ManimColor: A randomly selected color from the configured color list of the singleton instance. """ if cls._singleton is None: cls._singleton = cls() return cls._singleton.next() def get_shaded_rgb( rgb: FloatRGB, point: Point3D, unit_normal_vect: Vector3D, light_source: Point3D, ) -> FloatRGB: """Add light or shadow to the ``rgb`` color of some surface which is located at a given ``point`` in space and facing in the direction of ``unit_normal_vect``, depending on whether the surface is facing a ``light_source`` or away from it. Parameters ---------- rgb An RGB array of floats. point The location of the colored surface. unit_normal_vect The direction in which the colored surface is facing. light_source The location of a light source which might illuminate the surface. Returns ------- RGB_Array_Float The color with added light or shadow, depending on the direction of the colored surface. """ to_sun = normalize(light_source - point) light = 0.5 * np.dot(unit_normal_vect, to_sun) ** 3 if light < 0: light *= 0.5 shaded_rgb: FloatRGB = rgb + light return shaded_rgb __all__ = [ "ManimColor", "ManimColorDType", "ParsableManimColor", "color_to_rgb", "color_to_rgba", "color_to_int_rgb", "color_to_int_rgba", "rgb_to_color", "rgba_to_color", "rgb_to_hex", "hex_to_rgb", "invert_color", "color_gradient", "interpolate_color", "average_color", "random_bright_color", "random_color", "RandomColorGenerator", "get_shaded_rgb", "HSV", "RGBA", ] ================================================ FILE: manim/utils/color/manim_colors.py ================================================ """Colors included in the global name space. These colors form Manim's default color space. .. manim:: ColorsOverview :save_last_frame: :hide_source: import manim.utils.color.manim_colors as Colors class ColorsOverview(Scene): def construct(self): def color_group(color): group = VGroup( *[ Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=getattr(Colors, name.upper())) for name in subnames(color) ] ).arrange_submobjects(buff=0.4, direction=DOWN) name = Text(color).scale(0.6).next_to(group, UP, buff=0.3) if any(decender in color for decender in "gjpqy"): name.shift(DOWN * 0.08) group.add(name) return group def subnames(name): return [name + "_" + char for char in "abcde"] color_groups = VGroup( *[ color_group(color) for color in [ "blue", "teal", "green", "yellow", "gold", "red", "maroon", "purple", ] ] ).arrange_submobjects(buff=0.2, aligned_edge=DOWN) for line, char in zip(color_groups[0], "abcde"): color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2)) def named_lines_group(length, color_names, labels, align_to_block): colors = [getattr(Colors, color.upper()) for color in color_names] lines = VGroup( *[ Line( ORIGIN, RIGHT * length, stroke_width=55, color=color, ) for color in colors ] ).arrange_submobjects(buff=0.6, direction=DOWN) for line, name, color in zip(lines, labels, colors): line.add(Text(name, color=color.contrasting()).scale(0.6).move_to(line)) lines.next_to(color_groups, DOWN, buff=0.5).align_to( color_groups[align_to_block], LEFT ) return lines other_colors = ( "pink", "light_pink", "orange", "light_brown", "dark_brown", "gray_brown", ) other_lines = named_lines_group( 3.2, other_colors, other_colors, 0, ) gray_lines = named_lines_group( 6.6, ["white"] + subnames("gray") + ["black"], [ "white", "lighter_gray / gray_a", "light_gray / gray_b", "gray / gray_c", "dark_gray / gray_d", "darker_gray / gray_e", "black", ], 2, ) pure_colors = ( "pure_red", "pure_green", "pure_blue", "pure_cyan", "pure_magenta", "pure_yellow", ) pure_lines = named_lines_group( 3.2, pure_colors, pure_colors, 6, ) self.add(color_groups, other_lines, gray_lines, pure_lines) VGroup(*self.mobjects).move_to(ORIGIN) .. automanimcolormodule:: manim.utils.color.manim_colors """ from __future__ import annotations from .core import ManimColor WHITE = ManimColor("#FFFFFF") GRAY_A = ManimColor("#DDDDDD") GREY_A = ManimColor("#DDDDDD") GRAY_B = ManimColor("#BBBBBB") GREY_B = ManimColor("#BBBBBB") GRAY_C = ManimColor("#888888") GREY_C = ManimColor("#888888") GRAY_D = ManimColor("#444444") GREY_D = ManimColor("#444444") GRAY_E = ManimColor("#222222") GREY_E = ManimColor("#222222") BLACK = ManimColor("#000000") LIGHTER_GRAY = ManimColor("#DDDDDD") LIGHTER_GREY = ManimColor("#DDDDDD") LIGHT_GRAY = ManimColor("#BBBBBB") LIGHT_GREY = ManimColor("#BBBBBB") GRAY = ManimColor("#888888") GREY = ManimColor("#888888") DARK_GRAY = ManimColor("#444444") DARK_GREY = ManimColor("#444444") DARKER_GRAY = ManimColor("#222222") DARKER_GREY = ManimColor("#222222") PURE_RED = ManimColor("#FF0000") PURE_GREEN = ManimColor("#00FF00") PURE_BLUE = ManimColor("#0000FF") PURE_CYAN = ManimColor("#00FFFF") PURE_MAGENTA = ManimColor("#FF00FF") PURE_YELLOW = ManimColor("#FFFF00") BLUE_A = ManimColor("#C7E9F1") BLUE_B = ManimColor("#9CDCEB") BLUE_C = ManimColor("#58C4DD") BLUE_D = ManimColor("#29ABCA") BLUE_E = ManimColor("#236B8E") BLUE = ManimColor("#58C4DD") DARK_BLUE = ManimColor("#236B8E") TEAL_A = ManimColor("#ACEAD7") TEAL_B = ManimColor("#76DDC0") TEAL_C = ManimColor("#5CD0B3") TEAL_D = ManimColor("#55C1A7") TEAL_E = ManimColor("#49A88F") TEAL = ManimColor("#5CD0B3") GREEN_A = ManimColor("#C9E2AE") GREEN_B = ManimColor("#A6CF8C") GREEN_C = ManimColor("#83C167") GREEN_D = ManimColor("#77B05D") GREEN_E = ManimColor("#699C52") GREEN = ManimColor("#83C167") YELLOW_A = ManimColor("#FFF1B6") YELLOW_B = ManimColor("#FFEA94") YELLOW_C = ManimColor("#F7D96F") YELLOW_D = ManimColor("#F4D345") YELLOW_E = ManimColor("#E8C11C") YELLOW = ManimColor("#F7D96F") GOLD_A = ManimColor("#F7C797") GOLD_B = ManimColor("#F9B775") GOLD_C = ManimColor("#F0AC5F") GOLD_D = ManimColor("#E1A158") GOLD_E = ManimColor("#C78D46") GOLD = ManimColor("#F0AC5F") RED_A = ManimColor("#F7A1A3") RED_B = ManimColor("#FF8080") RED_C = ManimColor("#FC6255") RED_D = ManimColor("#E65A4C") RED_E = ManimColor("#CF5044") RED = ManimColor("#FC6255") MAROON_A = ManimColor("#ECABC1") MAROON_B = ManimColor("#EC92AB") MAROON_C = ManimColor("#C55F73") MAROON_D = ManimColor("#A24D61") MAROON_E = ManimColor("#94424F") MAROON = ManimColor("#C55F73") PURPLE_A = ManimColor("#CAA3E8") PURPLE_B = ManimColor("#B189C6") PURPLE_C = ManimColor("#9A72AC") PURPLE_D = ManimColor("#715582") PURPLE_E = ManimColor("#644172") PURPLE = ManimColor("#9A72AC") PINK = ManimColor("#D147BD") LIGHT_PINK = ManimColor("#DC75CD") ORANGE = ManimColor("#FF862F") LIGHT_BROWN = ManimColor("#CD853F") DARK_BROWN = ManimColor("#8B4513") GRAY_BROWN = ManimColor("#736357") GREY_BROWN = ManimColor("#736357") # Colors used for Manim Community's logo and banner LOGO_WHITE = ManimColor("#ECE7E2") LOGO_GREEN = ManimColor("#87C2A5") LOGO_BLUE = ManimColor("#525893") LOGO_RED = ManimColor("#E07A5F") LOGO_BLACK = ManimColor("#343434") _all_manim_colors: list[ManimColor] = [ x for x in globals().values() if isinstance(x, ManimColor) ] ================================================ FILE: manim/utils/commands.py ================================================ from __future__ import annotations import os from collections.abc import Generator from pathlib import Path from subprocess import run from typing import TypedDict import av from manim.typing import StrOrBytesPath __all__ = [ "capture", "get_video_metadata", "get_dir_layout", ] def capture( command: str | list[str], cwd: StrOrBytesPath | None = None, command_input: str | None = None, ) -> tuple[str, str, int]: p = run( command, cwd=cwd, input=command_input, capture_output=True, text=True, encoding="utf-8", ) out, err = p.stdout, p.stderr return out, err, p.returncode class VideoMetadata(TypedDict): width: int height: int nb_frames: str duration: str avg_frame_rate: str codec_name: str pix_fmt: str def get_video_metadata(path_to_video: str | os.PathLike) -> VideoMetadata: with av.open(str(path_to_video)) as container: stream = container.streams.video[0] ctxt = stream.codec_context rate = stream.average_rate if stream.duration is not None: duration = float(stream.duration * stream.time_base) num_frames = stream.frames else: num_frames = sum(1 for _ in container.decode(video=0)) duration = float(num_frames / stream.base_rate) return { "width": ctxt.width, "height": ctxt.height, "nb_frames": str(num_frames), "duration": f"{duration:.6f}", "avg_frame_rate": f"{rate.numerator}/{rate.denominator}", # Can be a Fraction "codec_name": stream.codec_context.name, "pix_fmt": stream.codec_context.pix_fmt, } def get_dir_layout(dirpath: Path) -> Generator[str, None, None]: """Get list of paths relative to dirpath of all files in dir and subdirs recursively.""" for p in dirpath.iterdir(): if p.is_dir(): yield from get_dir_layout(p) continue yield str(p.relative_to(dirpath)) ================================================ FILE: manim/utils/config_ops.py ================================================ """Utilities that might be useful for configuration dictionaries.""" from __future__ import annotations __all__ = [ "merge_dicts_recursively", "update_dict_recursively", "DictAsObject", ] import itertools as it from typing import Any, Generic, Protocol, cast import numpy.typing as npt from typing_extensions import TypeVar def merge_dicts_recursively(*dicts: dict[Any, Any]) -> dict[Any, Any]: """ Creates a dict whose keyset is the union of all the input dictionaries. The value for each key is based on the first dict in the list with that key. dicts later in the list have higher priority When values are dictionaries, it is applied recursively """ result: dict = {} all_items = it.chain(*(d.items() for d in dicts)) for key, value in all_items: if key in result and isinstance(result[key], dict) and isinstance(value, dict): result[key] = merge_dicts_recursively(result[key], value) else: result[key] = value return result def update_dict_recursively( current_dict: dict[Any, Any], *others: dict[Any, Any] ) -> None: updated_dict = merge_dicts_recursively(current_dict, *others) current_dict.update(updated_dict) # Occasionally convenient in order to write dict.x instead of more laborious # (and less in keeping with all other attr accesses) dict["x"] class DictAsObject: def __init__(self, dictin: dict[str, Any]): self.__dict__ = dictin _Data_T = TypeVar("_Data_T", bound="npt.NDArray[Any]", default="npt.NDArray[Any]") class _HasData(Protocol): data: dict[str, npt.NDArray[Any]] class _Data(Generic[_Data_T]): """Descriptor that allows _Data variables to be grouped and accessed from self.data["attr"] via self.attr. self.data attributes must be arrays. """ def __set_name__(self, obj: _HasData, name: str) -> None: self.name: str = name def __get__(self, obj: _HasData, owner: Any) -> _Data_T: value = cast(_Data_T, obj.data[self.name]) return value def __set__(self, obj: _HasData, array: _Data_T) -> None: obj.data[self.name] = array _Uniforms_T = TypeVar("_Uniforms_T", bound="float | tuple[float, ...]", default=float) class _HasUniforms(Protocol): uniforms: dict[str, float | tuple[float, ...]] class _Uniforms(Generic[_Uniforms_T]): """Descriptor that allows _Uniforms variables to be grouped from self.uniforms["attr"] via self.attr. self.uniforms attributes must be floats or tuples of floats. """ def __set_name__(self, obj: _HasUniforms, name: str) -> None: self.name: str = name def __get__(self, obj: _HasUniforms, owner: Any) -> _Uniforms_T: val = cast(_Uniforms_T, obj.uniforms[self.name]) return val def __set__(self, obj: _HasUniforms, num: _Uniforms_T) -> None: obj.uniforms[self.name] = num ================================================ FILE: manim/utils/debug.py ================================================ """Debugging utilities.""" from __future__ import annotations __all__ = ["print_family", "index_labels"] from typing import Any from manim.mobject.mobject import Mobject from manim.mobject.text.numbers import Integer from manim.utils.color import ManimColor from ..mobject.types.vectorized_mobject import VGroup from .color import BLACK def print_family(mobject: Mobject, n_tabs: int = 0) -> None: """For debugging purposes""" print("\t" * n_tabs, mobject, id(mobject)) for submob in mobject.submobjects: print_family(submob, n_tabs + 1) def index_labels( mobject: Mobject, label_height: float = 0.15, background_stroke_width: float = 5, background_stroke_color: ManimColor = BLACK, **kwargs: Any, ) -> VGroup: r"""Returns a :class:`~.VGroup` of :class:`~.Integer` mobjects that shows the index of each submobject. Useful for working with parts of complicated mobjects. Parameters ---------- mobject The mobject that will have its submobjects labelled. label_height The height of the labels, by default 0.15. background_stroke_width The stroke width of the outline of the labels, by default 5. background_stroke_color The stroke color of the outline of labels. kwargs Additional parameters to be passed into the :class`~.Integer` mobjects used to construct the labels. Examples -------- .. manim:: IndexLabelsExample :save_last_frame: class IndexLabelsExample(Scene): def construct(self): text = MathTex( "\\frac{d}{dx}f(x)g(x)=", "f(x)\\frac{d}{dx}g(x)", "+", "g(x)\\frac{d}{dx}f(x)", ) #index the fist term in the MathTex mob indices = index_labels(text[0]) text[0][1].set_color(PURPLE_B) text[0][8:12].set_color(DARK_BLUE) self.add(text, indices) """ labels = VGroup() for n, submob in enumerate(mobject): label = Integer(n, **kwargs) label.set_stroke( background_stroke_color, background_stroke_width, background=True ) label.height = label_height label.move_to(submob) labels.add(label) return labels ================================================ FILE: manim/utils/deprecation.py ================================================ """Decorators for deprecating classes, functions and function parameters.""" from __future__ import annotations __all__ = ["deprecated", "deprecated_params"] import inspect import logging import re from collections.abc import Callable, Iterable from typing import Any, TypeVar, overload from decorator import decorate, decorator logger = logging.getLogger("manim") def _get_callable_info(callable_: Callable[..., Any], /) -> tuple[str, str]: """Returns type and name of a callable. Parameters ---------- callable The callable Returns ------- Tuple[str, str] The type and name of the callable. Type can can be one of "class", "method" (for functions defined in classes) or "function"). For methods, name is Class.method. """ what = type(callable_).__name__ name = callable_.__qualname__ if what == "function" and "." in name: what = "method" elif what != "function": what = "class" return (what, name) def _deprecation_text_component( since: str | None = None, until: str | None = None, message: str | None = None, ) -> str: """Generates a text component used in deprecation messages. Parameters ---------- since The version or date since deprecation until The version or date until removal of the deprecated callable message The reason for why the callable has been deprecated Returns ------- str The deprecation message text component. """ since = f"since {since} " if since else "" until = ( f"is expected to be removed after {until}" if until else "may be removed in a later version" ) msg = " " + message if message else "" return f"deprecated {since}and {until}.{msg}" # TODO: Use ParamSpec to type decorated functions when Python 3.9 is out of life T = TypeVar("T") @overload def deprecated( func: Callable[..., T], since: str | None = None, until: str | None = None, replacement: str | None = None, message: str | None = "", ) -> Callable[..., T]: ... @overload def deprecated( func: None = None, since: str | None = None, until: str | None = None, replacement: str | None = None, message: str | None = "", ) -> Callable[[Callable[..., T]], Callable[..., T]]: ... def deprecated( func: Callable[..., T] | None = None, since: str | None = None, until: str | None = None, replacement: str | None = None, message: str | None = "", ) -> Callable[..., T] | Callable[[Callable[..., T]], Callable[..., T]]: """Decorator to mark a callable as deprecated. The decorated callable will cause a warning when used. The docstring of the deprecated callable is adjusted to indicate that this callable is deprecated. Parameters ---------- func The function to be decorated. Should not be set by the user. since The version or date since deprecation. until The version or date until removal of the deprecated callable. replacement The identifier of the callable replacing the deprecated one. message The reason for why the callable has been deprecated. Returns ------- Callable The decorated callable. Examples -------- Basic usage:: from manim.utils.deprecation import deprecated @deprecated def foo(**kwargs): pass @deprecated class Bar: def __init__(self): pass @deprecated def baz(self): pass foo() # WARNING The function foo has been deprecated and may be removed in a later version. a = Bar() # WARNING The class Bar has been deprecated and may be removed in a later version. a.baz() # WARNING The method Bar.baz has been deprecated and may be removed in a later version. You can specify additional information for a more precise warning:: from manim.utils.deprecation import deprecated @deprecated( since="v0.2", until="v0.4", replacement="bar", message="It is cooler." ) def foo(): pass foo() # WARNING The function foo has been deprecated since v0.2 and is expected to be removed after v0.4. Use bar instead. It is cooler. You may also use dates instead of versions:: from manim.utils.deprecation import deprecated @deprecated(since="05/01/2021", until="06/01/2021") def foo(): pass foo() # WARNING The function foo has been deprecated since 05/01/2021 and is expected to be removed after 06/01/2021. """ # If used as factory: if func is None: return lambda func: deprecated(func, since, until, replacement, message) what, name = _get_callable_info(func) def warning_msg(for_docs: bool = False) -> str: """Generate the deprecation warning message. Parameters ---------- for_docs Whether or not to format the message for use in documentation. Returns ------- str The deprecation message. """ msg = message if replacement is not None: repl = replacement if for_docs: mapper = {"class": "class", "method": "meth", "function": "func"} repl = f":{mapper[what]}:`~.{replacement}`" msg = f"Use {repl} instead.{' ' + message if message else ''}" deprecated = _deprecation_text_component(since, until, msg) return f"The {what} {name} has been {deprecated}" def deprecate_docs(func: Callable) -> None: """Adjust docstring to indicate the deprecation. Parameters ---------- func The callable whose docstring to adjust. """ warning = warning_msg(True) doc_string = func.__doc__ or "" func.__doc__ = f"{doc_string}\n\n.. attention:: Deprecated\n {warning}" def deprecate(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: """The actual decorator used to extend the callables behavior. Logs a warning message. Parameters ---------- func The callable to decorate. args The arguments passed to the given callable. kwargs The keyword arguments passed to the given callable. Returns ------- Any The return value of the given callable when being passed the given arguments. """ logger.warning(warning_msg()) return func(*args, **kwargs) if type(func).__name__ != "function": deprecate_docs(func) # The following line raises this mypy error: # Accessing "__init__" on an instance is unsound, since instance.__init__ # could be from an incompatible subclass [misc] func.__init__ = decorate(func.__init__, deprecate) return func func = decorate(func, deprecate) deprecate_docs(func) return func def deprecated_params( params: str | Iterable[str] | None = None, since: str | None = None, until: str | None = None, message: str = "", redirections: None | (Iterable[tuple[str, str] | Callable[..., dict[str, Any]]]) = None, ) -> Callable[..., T]: """Decorator to mark parameters of a callable as deprecated. It can also be used to automatically redirect deprecated parameter values to their replacements. Parameters ---------- params The parameters to be deprecated. Can consist of: * An iterable of strings, with each element representing a parameter to deprecate * A single string, with parameter names separated by commas or spaces. since The version or date since deprecation. until The version or date until removal of the deprecated callable. message The reason for why the callable has been deprecated. redirections A list of parameter redirections. Each redirection can be one of the following: * A tuple of two strings. The first string defines the name of the deprecated parameter; the second string defines the name of the parameter to redirect to, when attempting to use the first string. * A function performing the mapping operation. The parameter names of the function determine which parameters are used as input. The function must return a dictionary which contains the redirected arguments. Redirected parameters are also implicitly deprecated. Returns ------- Callable The decorated callable. Raises ------ ValueError If no parameters are defined (neither explicitly nor implicitly). ValueError If defined parameters are invalid python identifiers. Examples -------- Basic usage:: from manim.utils.deprecation import deprecated_params @deprecated_params(params="a, b, c") def foo(**kwargs): pass foo(x=2, y=3, z=4) # No warning foo(a=2, b=3, z=4) # WARNING The parameters a and b of method foo have been deprecated and may be removed in a later version. You can also specify additional information for a more precise warning:: from manim.utils.deprecation import deprecated_params @deprecated_params( params="a, b, c", since="v0.2", until="v0.4", message="The letters x, y, z are cooler.", ) def foo(**kwargs): pass foo(a=2) # WARNING The parameter a of method foo has been deprecated since v0.2 and is expected to be removed after v0.4. The letters x, y, z are cooler. Basic parameter redirection:: from manim.utils.deprecation import deprecated_params @deprecated_params( redirections=[ # Two ways to redirect one parameter to another: ("old_param", "new_param"), lambda old_param2: {"new_param22": old_param2}, ] ) def foo(**kwargs): return kwargs foo(x=1, old_param=2) # WARNING The parameter old_param of method foo has been deprecated and may be removed in a later version. # returns {"x": 1, "new_param": 2} Redirecting using a calculated value:: from manim.utils.deprecation import deprecated_params @deprecated_params( redirections=[lambda runtime_in_ms: {"run_time": runtime_in_ms / 1000}] ) def foo(**kwargs): return kwargs foo(runtime_in_ms=500) # WARNING The parameter runtime_in_ms of method foo has been deprecated and may be removed in a later version. # returns {"run_time": 0.5} Redirecting multiple parameter values to one:: from manim.utils.deprecation import deprecated_params @deprecated_params( redirections=[lambda buff_x=1, buff_y=1: {"buff": (buff_x, buff_y)}] ) def foo(**kwargs): return kwargs foo(buff_x=2) # WARNING The parameter buff_x of method foo has been deprecated and may be removed in a later version. # returns {"buff": (2, 1)} Redirect one parameter to multiple:: from manim.utils.deprecation import deprecated_params @deprecated_params( redirections=[ lambda buff=1: {"buff_x": buff[0], "buff_y": buff[1]} if isinstance(buff, tuple) else {"buff_x": buff, "buff_y": buff} ] ) def foo(**kwargs): return kwargs foo(buff=0) # WARNING The parameter buff of method foo has been deprecated and may be removed in a later version. # returns {"buff_x": 0, buff_y: 0} foo(buff=(1, 2)) # WARNING The parameter buff of method foo has been deprecated and may be removed in a later version. # returns {"buff_x": 1, buff_y: 2} """ # Check if decorator is used without parenthesis if callable(params): raise ValueError("deprecate_parameters requires arguments to be specified.") if params is None: params = [] # Construct params list params = re.split(r"[,\s]+", params) if isinstance(params, str) else list(params) # Add params which are only implicitly given via redirections if redirections is None: redirections = [] for redirector in redirections: if isinstance(redirector, tuple): params.append(redirector[0]) else: params.extend(list(inspect.signature(redirector).parameters)) # Keep ordering of params so that warning message is consistently the same # This will also help pass unit testing params = list(dict.fromkeys(params)) # Make sure params only contains valid identifiers identifier = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE) if not all(re.match(identifier, param) for param in params): raise ValueError("Given parameter values are invalid.") redirections = list(redirections) def warning_msg(func: Callable[..., T], used: list[str]) -> str: """Generate the deprecation warning message. Parameters ---------- func The callable with deprecated parameters. used The list of deprecated parameters used in a call. Returns ------- str The deprecation message. """ what, name = _get_callable_info(func) plural = len(used) > 1 parameter_s = "s" if plural else "" used_ = ", ".join(used[:-1]) + " and " + used[-1] if plural else used[0] has_have_been = "have been" if plural else "has been" deprecated = _deprecation_text_component(since, until, message) return f"The parameter{parameter_s} {used_} of {what} {name} {has_have_been} {deprecated}" def redirect_params(kwargs: dict[str, Any], used: list[str]) -> None: """Adjust the keyword arguments as defined by the redirections. Parameters ---------- kwargs The keyword argument dictionary to be updated. used The list of deprecated parameters used in a call. """ for redirector in redirections: if isinstance(redirector, tuple): old_param, new_param = redirector if old_param in used: kwargs[new_param] = kwargs.pop(old_param) else: redirector_params = list(inspect.signature(redirector).parameters) redirector_args = {} for redirector_param in redirector_params: if redirector_param in used: redirector_args[redirector_param] = kwargs.pop(redirector_param) if len(redirector_args) > 0: kwargs.update(redirector(**redirector_args)) def deprecate_params(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: """The actual decorator function used to extend the callables behavior. Logs a warning message when a deprecated parameter is used and redirects it if specified. Parameters ---------- func The callable to decorate. args The arguments passed to the given callable. kwargs The keyword arguments passed to the given callable. Returns ------- Any The return value of the given callable when being passed the given arguments. """ used = [param for param in params if param in kwargs] if len(used) > 0: logger.warning(warning_msg(func, used)) redirect_params(kwargs, used) return func(*args, **kwargs) return decorator(deprecate_params) # type: ignore[return-value] ================================================ FILE: manim/utils/docbuild/__init__.py ================================================ """Utilities for building the Manim documentation. For more information about the Manim documentation building, see: - :doc:`/contributing/development`, specifically the ``Documentation`` bullet point under :ref:`polishing-changes-and-submitting-a-pull-request` - :doc:`/contributing/docs` .. autosummary:: :toctree: ../reference autoaliasattr_directive autocolor_directive manim_directive module_parsing """ ================================================ FILE: manim/utils/docbuild/autoaliasattr_directive.py ================================================ """A directive for documenting type aliases and other module-level attributes.""" from __future__ import annotations from typing import TYPE_CHECKING from docutils import nodes from docutils.parsers.rst import Directive from docutils.statemachine import StringList from manim.utils.docbuild.module_parsing import parse_module_attributes if TYPE_CHECKING: from sphinx.application import Sphinx __all__ = ["AliasAttrDocumenter"] ALIAS_DOCS_DICT, DATA_DICT, TYPEVAR_DICT = parse_module_attributes() ALIAS_LIST = [ alias_name for module_dict in ALIAS_DOCS_DICT.values() for category_dict in module_dict.values() for alias_name in category_dict ] def smart_replace(base: str, alias: str, substitution: str) -> str: """Auxiliary function for substituting type aliases into a base string, when there are overlaps between the aliases themselves. Parameters ---------- base The string in which the type aliases will be located and replaced. alias The substring to be substituted. substitution The string which will replace every occurrence of ``alias``. Returns ------- str The new string after the alias substitution. """ occurrences = [] len_alias = len(alias) len_base = len(base) def condition(char: str) -> bool: return not char.isalnum() and char != "_" start = 0 i = 0 while True: i = base.find(alias, start) if i == -1: break if (i == 0 or condition(base[i - 1])) and ( i + len_alias == len_base or condition(base[i + len_alias]) ): occurrences.append(i) start = i + len_alias for o in occurrences[::-1]: base = base[:o] + substitution + base[o + len_alias :] return base def setup(app: Sphinx) -> None: app.add_directive("autoaliasattr", AliasAttrDocumenter) class AliasAttrDocumenter(Directive): """Directive which replaces Sphinx's Autosummary for module-level attributes: instead, it manually crafts a new "Type Aliases" section, where all the module-level attributes which are explicitly annotated as :class:`TypeAlias` are considered as such, for their use all around the Manim docs. These type aliases are separated from the "regular" module-level attributes, which get their traditional "Module Attributes" section autogenerated with Sphinx's Autosummary under "Type Aliases". See ``docs/source/_templates/autosummary/module.rst`` to watch this directive in action. See :func:`~.parse_module_attributes` for more information on how the modules are parsed to obtain the :class:`TypeAlias` information and separate it from the other attributes. """ objtype = "autoaliasattr" required_arguments = 1 has_content = True def run(self) -> list[nodes.Element]: module_name = self.arguments[0] # not present in the keys of the DICTs module_name = module_name.removeprefix("manim.") module_alias_dict = ALIAS_DOCS_DICT.get(module_name, None) module_attrs_list = DATA_DICT.get(module_name, None) module_typevars = TYPEVAR_DICT.get(module_name, None) content = nodes.container() # Add "Type Aliases" section if module_alias_dict is not None: module_alias_section = nodes.section(ids=[f"{module_name}.alias"]) content += module_alias_section # Use a rubric (title-like), just like in `module.rst` module_alias_section += nodes.rubric(text="Type Aliases") # category_name: str # category_dict: AliasCategoryDict = dict[str, AliasInfo] for category_name, category_dict in module_alias_dict.items(): category_section = nodes.section( ids=[category_name.lower().replace(" ", "_")] ) module_alias_section += category_section # category_name can be possibly "" for uncategorized aliases if category_name: category_section += nodes.title(text=category_name) category_alias_container = nodes.container() category_section += category_alias_container # alias_name: str # alias_info: AliasInfo = dict[str, str] # Contains "definition": str # Can possibly contain "doc": str for alias_name, alias_info in category_dict.items(): # Replace all occurrences of type aliases in the # definition for automatic cross-referencing! alias_def = alias_info["definition"] for A in ALIAS_LIST: alias_def = smart_replace(alias_def, A, f":class:`~.{A}`") # Using the `.. class::` directive is CRUCIAL, since # function/method parameters are always annotated via # classes - therefore Sphinx expects a class unparsed = StringList( [ f".. class:: {alias_name}", "", " .. parsed-literal::", "", f" {alias_def}", "", ] ) if "doc" in alias_info: # Replace all occurrences of type aliases in # the docs for automatic cross-referencing! alias_doc = alias_info["doc"] for A in ALIAS_LIST: alias_doc = alias_doc.replace(f"`{A}`", f":class:`~.{A}`") # also hyperlink the TypeVars from that module if module_typevars is not None: for T in module_typevars: alias_doc = alias_doc.replace(f"`{T}`", f":class:`{T}`") # Add all the lines with 4 spaces behind, to consider all the # documentation as a paragraph INSIDE the `.. class::` block doc_lines = alias_doc.split("\n") unparsed.extend( StringList([f" {line}" for line in doc_lines]) ) # Parse the reST text into a fresh container # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest alias_container = nodes.container() self.state.nested_parse(unparsed, 0, alias_container) category_alias_container += alias_container # then add the module TypeVars section if module_typevars is not None: module_typevars_section = nodes.section(ids=[f"{module_name}.typevars"]) content += module_typevars_section # Use a rubric (title-like), just like in `module.rst` module_typevars_section += nodes.rubric(text="TypeVar's") # name: str # definition: TypeVarDict = dict[str, str] for name, definition in module_typevars.items(): # Using the `.. class::` directive is CRUCIAL, since # function/method parameters are always annotated via # classes - therefore Sphinx expects a class unparsed = StringList( [ f".. class:: {name}", "", " .. parsed-literal::", "", f" {definition}", "", ] ) # Parse the reST text into a fresh container # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest typevar_container = nodes.container() self.state.nested_parse(unparsed, 0, typevar_container) module_typevars_section += typevar_container # Then, add the traditional "Module Attributes" section if module_attrs_list is not None: module_attrs_section = nodes.section(ids=[f"{module_name}.data"]) content += module_attrs_section # Use the same rubric (title-like) as in `module.rst` module_attrs_section += nodes.rubric(text="Module Attributes") # Let Sphinx Autosummary do its thing as always # Add all the attribute names with 4 spaces behind, so that # they're considered as INSIDE the `.. autosummary::` block unparsed = StringList( [ ".. autosummary::", *(f" {attr}" for attr in module_attrs_list), ] ) # Parse the reST text into a fresh container # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest data_container = nodes.container() self.state.nested_parse(unparsed, 0, data_container) module_attrs_section += data_container return [content] ================================================ FILE: manim/utils/docbuild/autocolor_directive.py ================================================ """A directive for documenting colors in Manim.""" from __future__ import annotations import inspect from typing import TYPE_CHECKING from docutils import nodes from docutils.parsers.rst import Directive from manim import ManimColor if TYPE_CHECKING: from sphinx.application import Sphinx __all__ = ["ManimColorModuleDocumenter"] def setup(app: Sphinx) -> None: app.add_directive("automanimcolormodule", ManimColorModuleDocumenter) class ManimColorModuleDocumenter(Directive): objtype = "automanimcolormodule" required_arguments = 1 has_content = True def add_directive_header(self, sig: str) -> None: # TODO: The Directive class has no method named # add_directive_header. super().add_directive_header(sig) # type: ignore[misc] def run(self) -> list[nodes.Element]: module_name = self.arguments[0] try: import importlib module = importlib.import_module(module_name) except ImportError: return [ nodes.error( None, # type: ignore[arg-type] nodes.paragraph(text=f"Failed to import module '{module_name}'"), ) ] # Number of Colors displayed in one row num_color_cols = 2 table = nodes.table(align="center") tgroup = nodes.tgroup(cols=num_color_cols * 2) table += tgroup for _ in range(num_color_cols * 2): tgroup += nodes.colspec(colwidth=1) # Create header rows for the table thead = nodes.thead() header_row = nodes.row() for _ in range(num_color_cols): header_col1 = nodes.paragraph(text="Color Name") header_col2 = nodes.paragraph(text="RGB Hex Code") header_row += nodes.entry("", header_col1) header_row += nodes.entry("", header_col2) thead += header_row tgroup += thead color_elements = [] for member_name, member_obj in inspect.getmembers(module): if isinstance(member_obj, ManimColor): r, g, b = member_obj.to_rgb() luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b # Choose the font color based on the background luminance font_color = "black" if luminance > 0.5 else "white" color_elements.append((member_name, member_obj.to_hex(), font_color)) tbody = nodes.tbody() for base_i in range(0, len(color_elements), num_color_cols): row = nodes.row() for idx in range(base_i, base_i + num_color_cols): if idx < len(color_elements): member_name, hex_code, font_color = color_elements[idx] col1 = nodes.literal(text=member_name) col2 = nodes.raw( "", f'
{hex_code}
', format="html", ) else: col1 = nodes.literal(text="") col2 = nodes.raw("", "", format="html") row += nodes.entry("", col1) row += nodes.entry("", col2) tbody += row tgroup += tbody return [table] ================================================ FILE: manim/utils/docbuild/manim_directive.py ================================================ r""" A directive for including Manim videos in a Sphinx document =========================================================== When rendering the HTML documentation, the ``.. manim::`` directive implemented here allows to include rendered videos. Its basic usage that allows processing **inline content** looks as follows:: .. manim:: MyScene class MyScene(Scene): def construct(self): ... It is required to pass the name of the class representing the scene to be rendered to the directive. As a second application, the directive can also be used to render scenes that are defined within doctests, for example:: .. manim:: DirectiveDoctestExample :ref_classes: Dot >>> from manim import Create, Dot, RED, Scene >>> dot = Dot(color=RED) >>> dot.color ManimColor('#FC6255') >>> class DirectiveDoctestExample(Scene): ... def construct(self): ... self.play(Create(dot)) Options ------- Options can be passed as follows:: .. manim:: :