Manim arrange 和 arrange_in_grid 用法详解:buff、aligned_edge、rows/cols(0.21.0 实测)

arrange 和 arrange_in_grid 是 Manim 里给一组物体排版的两个方法。group.arrange(RIGHT, buff=0.5) 把组里的成员从左到右排成一行,buff 是相邻两个之间的空隙,方向换成 DOWN 就是一列,加 aligned_edge=LEFT 可以左对齐。group.arrange_in_grid(rows=2, cols=3) 排成两行三列,rows 和 cols 只写一个也行。两者的默认间距都是 0.25。区别在排完之后:arrange 会把整组挪到原点,arrange_in_grid 不会。

先交代一下版本:下面的代码、坐标和报错信息出自 Manim Community 0.21.0,这是 2026 年的最新版本,我们是 2026 年 10 月在上面逐条跑的。Manim 本身是一个 Python 动画库,3Blue1Brown 的数学视频用的就是它,图形和公式都拿代码来摆;背景知识可以看这篇介绍。

下面三段完整代码可以直接贴进极坐标⋅XYZ 的工作区点运行,里面装的也是 Manim 0.21.0,本机不用装 Python 和 LaTeX。

先排一行,再排成两行三列

六个方块建出来的时候都在原点,叠成了一个。先让它们排成一行,再改成两行三列:

python 复制代码
from manim import *


class RowAndGrid(Scene):
    def construct(self):
        colors = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE]
        boxes = VGroup(*[Square(side_length=1, color=c).set_fill(c, 0.6) for c in colors])
        self.add(boxes)  # 六个方块都在原点,叠成一个
        self.wait(0.5)

        # 一行:从左往右,相邻两个之间留 0.5
        self.play(boxes.animate.arrange(RIGHT, buff=0.5))
        self.wait(0.5)

        # 两行三列
        self.play(boxes.animate.arrange_in_grid(rows=2, cols=3, buff=0.5))
        self.wait()

第一步播完,六个方块的中心 x 依次是 -3.75、-2.25、-0.75、0.75、2.25、3.75,y 都是 0。方块边长 1,间隙 0.5,所以相邻两个的中心隔 1.5,整排以原点为中心左右对称。

第二步播完,上面一行是红、橙、黄,下面一行是绿、蓝、紫,x 是 -1.5、0、1.5,y 是 0.75 和 -0.75。成员按加进 VGroup 的顺序填格子,先填满第一行,再填第二行。

buff 是相邻两个成员之间的空隙,两个方法不写的话都是 0.25。arrange 的第一个参数是方向,RIGHT、DOWN 之外也可以写 LEFT、UP,顺序就反过来。斜着排也行,我们试过三个边长 1 的方块 arrange(DR, buff=0.2),中心落在 (-1.2, 1.2)、(0, 0)、(1.2, -1.2),是一条往右下走的台阶。

arrange 是一串 next_to

Manim 0.21.0 里 arrange 的函数体只有几行,去掉类型标注大致是这样:

python 复制代码
def arrange(self, direction=RIGHT, buff=0.25, center=True, **kwargs):
    for m1, m2 in zip(self.submobjects[:-1], self.submobjects[1:]):
        m2.next_to(m1, direction, buff, **kwargs)
    if center:
        self.center()
    return self

第一个成员不动,第二个 next_to 到第一个旁边,第三个 next_to 到第二个旁边,一路接下去。接完之后,整组用 center() 挪到原点。

next_to 管的是两个物体边到边的距离,所以 arrange 保证的是间隙相等。成员一样大的时候看不出区别,大小不一就能看出来了。我们拿宽度是 0.6、2、1、3 的四个图形 arrange(RIGHT, buff=0.5),量出来三段间隙都是 0.5,相邻中心的距离是 1.8、2.0、2.5。

arrange 不认识的参数会原样交给 next_to,最常用的是 aligned_edge。往下排的时候,默认是每个成员的中心对中心。三个宽度是 1、3、2 的长条 arrange(DOWN, buff=0.3),左边缘的 x 是 -0.5、-1.5、-1.0,参差不齐。加上 aligned_edge=LEFT,三个左边缘都在 -1.5。几行文字要左对齐、一排高矮不同的图形要底边对齐(aligned_edge=DOWN),都是这么写。

最后那个 center() 可以关掉。arrange(RIGHT, buff=0.5, center=False) 只做前面那串 next_to,第一个成员在哪,整排就从哪开始。我们把第一个方块先放到 (-4, 1) 再这样排,三个方块落在 (-4, 1)、(-2.5, 1)、(-1, 1)。

arrange_in_grid 先量格子,再往里放

要是只用 arrange 排两行,得先把每行各排一次,再把两行上下叠起来。成员大小一样时这么做没问题,大小不一的话,两行各排各的,上下就对不成列。下面左边是这种写法,右边是同样六个方块交给 arrange_in_grid:

python 复制代码
from manim import *


class UnevenSizes(Scene):
    def construct(self):
        sides = [0.5, 2, 0.5, 1, 0.5, 1.5]

        def make(color):
            return [Square(side_length=s, color=color).set_fill(color, 0.5) for s in sides]

        # 左边:两行各自 arrange,再把两行上下叠起来
        m = make(BLUE)
        row1 = VGroup(*m[:3]).arrange(RIGHT, buff=0.2)
        row2 = VGroup(*m[3:]).arrange(RIGHT, buff=0.2)
        nested = VGroup(row1, row2).arrange(DOWN, buff=0.2).move_to([-3.5, 0, 0])

        # 右边:同样六个方块,交给 arrange_in_grid
        grid = VGroup(*make(YELLOW)).arrange_in_grid(rows=2, cols=3, buff=0.2).move_to([3.5, 0, 0])

        self.add(nested, grid)
        self.wait()

以各自那一组的中心为零点,左边第一行三个方块的 x 是 -1.45、0、1.45,第二行是 -1.2、-0.25、0.95,六个中心落在六个不同的 x 上。右边两行都是 -1.95、-0.25、1.7。

arrange_in_grid 的做法和 arrange 不一样。它先把成员按行列分好,量出每一列里最宽的那个、每一行里最高的那个,当作这一列的宽和这一行的高,这样就有了一张格子。然后把每个成员放进自己的格子,默认摆在格子正中。所以同一列的成员中心在一条竖线上,同一行的在一条横线上。

想让格子里的东西靠边,有两个参数。cell_alignment=LEFT 让所有成员贴着格子左边,上面那六个方块这样排,每列的左边缘是 -2.45、-1.25、0.95。col_alignments="lcr" 可以一列一列地指定,三个字母对应三列的左、中、右;行的方向是 row_alignments,字母用 u、c、d。

行数和列数可以只写一个,另一个它自己算。七个方块写 cols=3 排出来是 3、3、1,写 rows=2 是 4、3。两个都不写,列数取成员个数开平方再向上取整:六个排成 3、3,七个是 3、3、1,十个是 4、4、2。

排完之后,整组在哪

arrange 的最后一步是 center(),整组回到原点。arrange_in_grid 开头先记下了整组的中心,最后一行是 self.move_to(start_pos),把排好的网格挪回那个中心。同样是「把三个方块排成一行」,写法不同,落点就不同:

python 复制代码
from manim import *


class WhereDoesItGo(Scene):
    def construct(self):
        plane = NumberPlane(background_line_style={"stroke_opacity": 0.3})
        a = VGroup(*[Square(side_length=0.8, color=BLUE).set_fill(BLUE, 0.5) for _ in range(3)])
        b = VGroup(*[Square(side_length=0.8, color=YELLOW).set_fill(YELLOW, 0.5) for _ in range(3)])
        a.move_to([-4, 2, 0])
        b.move_to([4, -2, 0])
        self.add(plane, a, b)
        self.wait(0.5)

        # 两组都是「排成一行」,写法不同
        self.play(a.animate.arrange(RIGHT), b.animate.arrange_in_grid(rows=1), run_time=2)
        self.wait(0.5)

        # arrange 后面接一个 move_to,把整组送回去
        self.play(a.animate.arrange(RIGHT).move_to([-4, 2, 0]), run_time=2)
        self.wait()

第一个 play 播完,蓝色那组的中心在 (0, 0),它一边散开一边从左上角滑到了画面正中。黄色那组的中心还是 (4, -2),在原地散开。

第二个 play 把 arrange 和 move_to 串在一条 .animate 后面,蓝色那组回到 (-4, 2),三个方块在 (-5.05, 2)、(-4, 2)、(-2.95, 2)。

我们自己写场景时,arrange 后面基本都会跟一个定位:.arrange(RIGHT).to_edge(UP)、.arrange(DOWN).next_to(title, DOWN)、.arrange(RIGHT).move_to(...)。对整个组调 move_to,成员是一起平移的,排好的间距不会变,这一点上一篇讲 shift 和 move_to 时试过。

什么时候用哪个

你想做的事 写法
排成一行 group.arrange(RIGHT, buff=0.5)
排成一列,左边对齐 group.arrange(DOWN, buff=0.3, aligned_edge=LEFT)
一排高矮不同的图形,底边对齐 group.arrange(RIGHT, aligned_edge=DOWN)
排成两行三列 group.arrange_in_grid(rows=2, cols=3)
每行固定 4 个,行数随个数变 group.arrange_in_grid(cols=4)
横向间隙 0.2,纵向间隙 1 group.arrange_in_grid(cols=3, buff=(0.2, 1))
从上往下一列一列地填 group.arrange_in_grid(rows=2, flow_order="dr")
排好之后放到指定位置 在后面接 .move_to(...)、.to_edge(...) 或 .next_to(...)

常见写错的地方

先定位,后 arrange

python 复制代码
row = VGroup(a, b, c).to_edge(UP).arrange(RIGHT)

这一行想的是「放到画面顶上,再排开」,结果整排在画面正中。arrange 最后那步 center() 把前面的 to_edge(UP) 盖掉了。我们试过 move_to([3, 2, 0]) 之后再 arrange(RIGHT),组的中心是 (0, 0);两步调个顺序,中心是 (3, 2)。

python 复制代码
row = VGroup(a, b, c).arrange(RIGHT).to_edge(UP)

组里只有一个成员时也会这样。一个在 (2, 2) 的方块单独装进 VGroup 再 arrange(RIGHT),没有东西可排,它照样被挪到了原点。成员个数是循环算出来的时候,容易碰上这种情况。

排完之后又加成员、又改大小

arrange 只在被调用的那一刻摆一次位置,之后组里再发生什么它都不管。

排好三个方块之后往组里 add 第四个,新来的那个还在它自己原来的位置。我们试的时候它在 (5, 3),离那一排很远,整个组的外接框被它撑大,中心变成了 (2, 1.75)。

排好之后把中间那个 scale(2),原本 0.5 的间隙变成了 0,三个方块贴在一起。

这两种情况都是再调一次 arrange,然后把定位那一步也重做一遍。这和 next_to 摆好的标签不会跟着物体走是同一个道理,那一篇里讲过。

rows × cols 装不下

python 复制代码
VGroup(*[Square() for _ in range(7)]).arrange_in_grid(rows=2, cols=3)

七个成员放不进 2×3 的格子,0.21.0 直接报 ValueError: Too few rows and columns to fit all submobjetcs.(最后一个词是源码里的拼写,照抄的)。成员个数不固定的时候,rows 和 cols 只写一个,让另一个自己算。

往 VGroup 里放图片

python 复制代码
VGroup(Square(), ImageMobject("logo.png"))

报的是 TypeError: Only values of type VMobject can be added as submobjects of VGroup, but the value ImageMobject (at index 0 of parameter 1) is of type ImageMobject. You can try adding this value into a Group instead.

VGroup 只收矢量图形,图片是位图。报错信息最后一句已经给了改法,换成 Group 就行。arrange 和 arrange_in_grid 是定义在 Mobject 上的,Group 一样能调。我们把一个方块和一张图片装进 Group 再 arrange(RIGHT, buff=0.5),两个正常排开了。

常见追问(FAQ)

Q:buff 不写的话,间距是多少? A:arrange 和 arrange_in_grid 的默认值都是 0.25 个画布单位。默认画布高 8 个单位,0.25 大概是画面高度的 3%。

Q:网格的横向和纵向间距想设得不一样,怎么写? A:buff 传一个元组。我们量过 buff=(0.2, 1.0):同一行里相邻两个的间隙是 0.2,上下两行之间是 1.0,也就是第一个数管横向,第二个数管纵向。0.21.0 的文档字符串把这个元组写成 (row, col),容易看反,以实际跑出来的为准。

Q:网格能不能从上往下一列一列地填? A:能,加 flow_order="dr",意思是先往下(down)再往右(right)。默认是 "rd",先往右再往下。六个方块排 2×3,"dr" 的结果是第 1、2 个在第一列,第 3、4 个在第二列。

Q:arrange 能做成动画吗? A:能,self.play(group.animate.arrange(RIGHT)),每个成员从现在的位置沿直线滑到排好的位置,本文第一段代码就是这么写的。后面还可以接着串,比如 group.animate.arrange(RIGHT).to_edge(UP)。

Q:VGroup 里面还套着 VGroup,arrange 会把里面那层也打散吗? A:不会。arrange 只挪直接成员,里面那个组被当成一整块。我们把一个上下摞着两个方块的小组和另外两个图形一起 arrange(RIGHT),小组里两个方块还是上下摞着,相对位置没变。

Q:对一个 Text 调 arrange 会怎样? A:会把字拆开重排。Text("ABC") 本身就是一个组,三个字母是它的三个成员,调 arrange(RIGHT, buff=0.5) 之后字距被拉开,我们量到宽度从 1.34 变成了 2.25。要排的是几行文字的话,把几个 Text 装进一个 VGroup,对这个 VGroup 调 arrange(DOWN, aligned_edge=LEFT)。


VGroup、arrange 和 arrange_in_grid 在教程《布局(下)· 尺寸 / 包围 / 编组 / 深度 + 实战》的第三节「编组与排列」里有视频讲解,旁边的代码可以边看边改;next_to 和 aligned_edge 在前一课《布局(上)· 描述关系不算坐标》里。

来源:极坐标⋅XYZ · jizuobiao.xyz · 更新于 2026-10-05 · 基于 Manim Community 0.21.0

相关推荐
小小龙学IT1 小时前
Go 语言 reflect 反射包深度解析:从 Type/Value 到三大定律与工业实践
前端·golang
外收内放1 小时前
Python基础语法练习题(拓展2)
python·pygame
“AI国潮设计-小江”1 小时前
《Python+SDXL实战:用ControlNet批量生成“英歌舞草莓蛋糕”IP,附自动化脚本与商用思路》
开发语言·人工智能·python·prompt·aigc
小溪学编程1 小时前
C语言篇:枚举类型
java·c语言·前端
为啥全要学1 小时前
大模型流式输出过滤敏感词
开发语言·python
xingpanvip1 小时前
星盘接口开发文档:推算星座接口指南
前端·php
Da Da 泓1 小时前
HTML浅浅入门
前端·html
এ慕ོ冬℘゜1 小时前
es6基础
前端·javascript·es6
2601_962885721 小时前
如何用 Python 统计 A 股连续涨停(几连板)?
java·linux·python