bencher.results.manim_cartesian.cartesian_product_scene ======================================================= .. py:module:: bencher.results.manim_cartesian.cartesian_product_scene .. autoapi-nested-parse:: Dimensional extrusion animation using PIL. Shows how each dimension builds on the last: point --dim1--> line --dim2--> grid --dim3--> stack --repeat--> extrude --over_time--> film strip --dim4+--> sets of sets ... Renders frames directly with PIL (fast), saves as animated PNG (APNG). Attributes ---------- .. autoapisummary:: bencher.results.manim_cartesian.cartesian_product_scene.logger bencher.results.manim_cartesian.cartesian_product_scene.CELL_SIZE bencher.results.manim_cartesian.cartesian_product_scene.CELL_GAP bencher.results.manim_cartesian.cartesian_product_scene.DIM_PALETTE bencher.results.manim_cartesian.cartesian_product_scene.CELL_BORDER bencher.results.manim_cartesian.cartesian_product_scene.BG_COLOR bencher.results.manim_cartesian.cartesian_product_scene.LABEL_COLOR bencher.results.manim_cartesian.cartesian_product_scene.DEPTH_DX bencher.results.manim_cartesian.cartesian_product_scene.DEPTH_DY bencher.results.manim_cartesian.cartesian_product_scene.GROUP_GAP bencher.results.manim_cartesian.cartesian_product_scene.GAP bencher.results.manim_cartesian.cartesian_product_scene.FILM_COLOR bencher.results.manim_cartesian.cartesian_product_scene.FILM_EDGE bencher.results.manim_cartesian.cartesian_product_scene.FILM_FRAME_BORDER bencher.results.manim_cartesian.cartesian_product_scene.FILM_LABEL_COLOR bencher.results.manim_cartesian.cartesian_product_scene.FILM_PAD bencher.results.manim_cartesian.cartesian_product_scene.FILM_FRAME_PAD bencher.results.manim_cartesian.cartesian_product_scene.FILM_FRAME_GAP bencher.results.manim_cartesian.cartesian_product_scene.FILM_SPROCKET_W bencher.results.manim_cartesian.cartesian_product_scene.FILM_SPROCKET_H bencher.results.manim_cartesian.cartesian_product_scene.FILM_SPROCKET_R bencher.results.manim_cartesian.cartesian_product_scene.FILM_SPROCKET_SPACING bencher.results.manim_cartesian.cartesian_product_scene.FILM_SPROCKET_MARGIN bencher.results.manim_cartesian.cartesian_product_scene.FILM_LABEL_H Classes ------- .. autoapisummary:: bencher.results.manim_cartesian.cartesian_product_scene.Shape bencher.results.manim_cartesian.cartesian_product_scene.TimelineShape bencher.results.manim_cartesian.cartesian_product_scene.StrobeShape Functions --------- .. autoapisummary:: bencher.results.manim_cartesian.cartesian_product_scene.render_shape_to_image bencher.results.manim_cartesian.cartesian_product_scene._generate_unique_filename bencher.results.manim_cartesian.cartesian_product_scene._get_font bencher.results.manim_cartesian.cartesian_product_scene._direction_for bencher.results.manim_cartesian.cartesian_product_scene.render_animation Module Contents --------------- .. py:data:: logger .. py:data:: CELL_SIZE :value: 20 .. py:data:: CELL_GAP :value: 3 .. py:data:: DIM_PALETTE :value: [(150, 190, 240), (240, 160, 155), (150, 220, 160), (245, 225, 140), (220, 170, 235), (245, 200,... .. py:data:: CELL_BORDER :value: (180, 180, 180) .. py:data:: BG_COLOR :value: (255, 255, 255) .. py:data:: LABEL_COLOR :value: (30, 30, 30) .. py:data:: DEPTH_DX :value: 10 .. py:data:: DEPTH_DY :value: -8 .. py:data:: GROUP_GAP :value: 20 .. py:data:: GAP :value: '...' .. py:function:: render_shape_to_image(shape: Shape, target_w: int, target_h: int, bg_color: tuple[int, int, int] = BG_COLOR, alpha: float = 1.0) -> PIL.Image.Image Render `shape` into an offscreen image scaled to fit target_w x target_h. The returned image is at most target_w x target_h and centered content-wise. .. py:function:: _generate_unique_filename(cfg: bencher.results.manim_cartesian.cartesian_product_cfg.CartesianProductCfg, width: int, height: int) -> str Generate a unique filename based on animation parameters. .. py:function:: _get_font(size: int) Get a font, falling back to default if no TTF available. .. py:class:: Shape(children: list[Shape] | None = None, direction: str = 'right', depth: int = 0, color_index: int = 0) Recursive shape representation for dimensional extrusion. A Shape is either a leaf (single cell) or a collection of sub-shapes arranged along an axis. ``depth`` tracks nesting level so that higher-dimensional extrusions use wider gaps. .. py:attribute:: children :value: None .. py:attribute:: direction :value: 'right' .. py:attribute:: depth :value: 0 .. py:attribute:: color_index :value: 0 .. py:attribute:: _cached_size :value: None .. py:property:: is_leaf :type: bool .. py:property:: gap :type: int Gap between children. Depth 0-2 (first two spatial dims forming the basic grid): tight CELL_GAP. Depth 3 (stack direction): uses isometric offset, gap not used. Depth 4+ (sets of stacks, sets of sets): GROUP_GAP scaling with depth. .. py:method:: size() -> tuple[int, int] Return (width, height) in pixels. Cached — tree structure is immutable. .. py:method:: draw(img: PIL.ImageDraw.ImageDraw, x: int, y: int, alpha: float = 1.0) Draw this shape at position (x, y) on the image. .. py:method:: extrude(n: int, direction: str, color_index: int | None = None) -> Shape Create a new shape by extruding this one n times along direction. .. py:method:: _deep_copy() -> Shape .. py:method:: _deep_copy_recolored(color_index: int) -> Shape Copy and recolor in a single traversal. .. py:function:: _direction_for(dim_index: int) -> str Map dimension index to layout direction. .. py:data:: FILM_COLOR :value: (35, 35, 38) .. py:data:: FILM_EDGE :value: (25, 25, 28) .. py:data:: FILM_FRAME_BORDER :value: (90, 90, 95) .. py:data:: FILM_LABEL_COLOR :value: (100, 100, 100) .. py:data:: FILM_PAD :value: 6 .. py:data:: FILM_FRAME_PAD :value: 10 .. py:data:: FILM_FRAME_GAP :value: 16 .. py:data:: FILM_SPROCKET_W :value: 8 .. py:data:: FILM_SPROCKET_H :value: 14 .. py:data:: FILM_SPROCKET_R :value: 2 .. py:data:: FILM_SPROCKET_SPACING :value: 14 .. py:data:: FILM_SPROCKET_MARGIN :value: 4 .. py:data:: FILM_LABEL_H :value: 18 .. py:class:: TimelineShape(inner: Shape, count: int) Bases: :py:obj:`Shape` Film-strip timeline for the over_time dimension. Each time step is a "frame" in a horizontal film strip with sprocket holes along top and bottom edges — unmistakably film. The film chrome (sprockets, borders, padding) is always rendered at a fixed pixel size. The inner shape is scaled to fit within a constant frame window so the strip looks the same regardless of content complexity. .. py:attribute:: FRAME_W :value: 100 .. py:attribute:: FRAME_H :value: 80 .. py:attribute:: inner .. py:attribute:: count .. py:attribute:: _skip_labels :value: False .. py:property:: is_leaf :type: bool .. py:method:: _outer_frame_size() -> tuple[int, int] Size of each frame including padding. .. py:method:: size() -> tuple[int, int] Return (width, height) in pixels. Cached — tree structure is immutable. .. py:method:: draw(img: PIL.ImageDraw.ImageDraw, x: int, y: int, alpha: float = 1.0) Draw this shape at position (x, y) on the image. .. py:method:: _draw_sprockets(img: PIL.ImageDraw.ImageDraw, strip_x: int, row_y: int, strip_w: int) :staticmethod: Draw a row of rounded sprocket holes across the strip width. .. py:method:: strip_size() -> tuple[int, int] Size of the film strip excluding the label row below. .. py:method:: draw_without_labels(img: PIL.ImageDraw.ImageDraw, x: int, y: int) -> None Draw the film strip without frame labels, preserving previous state. .. py:method:: render_strip_image(v_scale: float = 1.0) -> PIL.Image.Image Render the strip (without labels) into an offscreen image. The strip is drawn at full resolution and then uniformly scaled by *v_scale* (typically chosen to fit the canvas height). The returned image can be pasted directly — PIL clips any overflow naturally. .. py:method:: draw_label_overlay_for_viewport(img: PIL.ImageDraw.ImageDraw, strip_x: int, strip_y: int, strip_h: int, scale: float, canvas_w: int) -> None Draw frame labels at fixed pixel size for frames visible on canvas. .. py:method:: _deep_copy() -> Shape .. py:class:: StrobeShape(inner: Shape, count: int, cfg: bencher.results.manim_cartesian.cartesian_product_cfg.CartesianProductCfg, flash: float = 0.0) Bases: :py:obj:`Shape` Shape with a glowing border and tally-mark counter. ``flash`` (0–1) controls the glow intensity for animation frames. All visual tunables are read from ``cfg`` (a CartesianProductCfg). .. py:attribute:: inner .. py:attribute:: count .. py:attribute:: cfg .. py:attribute:: flash :value: 0.0 .. py:attribute:: _skip_tally :value: False .. py:property:: is_leaf :type: bool .. py:method:: size() -> tuple[int, int] Return (width, height) in pixels. Cached — tree structure is immutable. .. py:method:: draw(img: PIL.ImageDraw.ImageDraw, x: int, y: int, alpha: float = 1.0) Draw this shape at position (x, y) on the image. .. py:method:: _draw_tally(img, mx0, my, avail_w, color, c) Proper tally marks (vertical lines, diagonal strike every 5) + xN label. Tallies grow from the left. The xN number is always on the right. Only draws as many complete groups/marks as fit cleanly; the label alone conveys the count when space is tight. .. py:method:: content_box_size() -> tuple[int, int] Size of border + inner shape, excluding the tally mark row. .. py:method:: draw_without_tally(img: PIL.ImageDraw.ImageDraw, x: int, y: int) -> None Draw the shape without tallies, preserving previous state. .. py:method:: draw_tally_overlay(img: PIL.ImageDraw.ImageDraw, anchor_x: int, anchor_y: int, avail_w: int) Draw tally marks at fixed pixel size on the final frame. .. py:method:: draw_tally_overlay_for_box(img: PIL.ImageDraw.ImageDraw, box_x: int, box_y: int, box_w: int, box_h: int) -> None Draw fixed-size tally overlay below a rendered box. Spacing is derived from cfg fields so layout stays consistent when configuration changes. .. py:method:: _deep_copy() -> Shape .. py:function:: render_animation(cfg: bencher.results.manim_cartesian.cartesian_product_cfg.CartesianProductCfg, width: int = 400, height: int = 300, fps: int = 15, step_frames: int = 4, output_dir: str = 'cachedir/cartesian') -> str Render the dimensional extrusion animation. :param cfg: Sweep configuration. :type cfg: CartesianProductCfg :param width: Video resolution. :type width: int :param height: Video resolution. :type height: int :param fps: Frames per second. :type fps: int :param step_frames: Frames to show each extrusion step (per sub-copy). :type step_frames: int :param output_dir: Directory for the output video. :type output_dir: str :returns: Path to the output animation file. :rtype: str