接说问题用Manim展示 x25x6(x2)(x3) 的“十字相乘”面积模型你需要先想好怎样把大矩形拆成四块(x2)、(2x)、(3x)、(6)再手动计算每一块的边长和位置。换成 x27x12布局又要重新算。有没有办法只告诉程序“我要做这个多项式因式分解的拼图证明”它就能自动生成所有矩形的尺寸和坐标有用SymPy。它能够根据代数式的结构自动推导几何布局让你从“一个公式写一套代码”升级为“一类公式共用一套生成器”。1. 痛点场景还原公式一换布局全乱先看一个“传统”手动布局的例子。我们想讲 x25x6(x2)(x3) 的面积模型把大矩形分成四块from manim import * class ManualX2Plus5xPlus6(Scene): def construct(self): x 2 # 让 x 取某个具体值来画图 # 手动指定四块的宽高 # 大矩形宽 (x3)高 (x2) # 四块x*x, 3*x, 2*x, 2*3 sq_x2 Rectangle(widthx, heightx, colorBLUE, fill_opacity0.4) rec_3x Rectangle(width3, heightx, colorRED, fill_opacity0.4) rec_2x Rectangle(widthx, height2, colorRED, fill_opacity0.4) rec_6 Rectangle(width3, height2, colorGREEN, fill_opacity0.4) # 手动拼左下角 sq_x2右边 rec_3x上边 rec_2x右上 rec_6 sq_x2.shift(LEFT * (3 / 2) DOWN * (2 / 2)) rec_3x.next_to(sq_x2, RIGHT, buff0) rec_2x.next_to(sq_x2, UP, buff0) rec_6.next_to(rec_3x, UP, buff0) self.play(Create(sq_x2), Create(rec_3x), Create(rec_2x), Create(rec_6)) self.wait(1)要改成 x27x12(x3)(x4)你需要改常数项3→3、4矩形rec_3x的宽度 →4矩形rec_2x的高度 →3小矩形rec_6的宽高 →4和3shift里面的偏移量也要跟着变。每一次改公式都是一次手工劳动而且容易出错。如果公式结构稍微复杂一点比如二次项系数不是 1或者有三项展开这种手动模式基本就难以维护了。2. SymPy 解决方案因式分解→几何布局SymPy的杀手锏就在这里它可以对多项式进行因式分解或展开自动抽取出每一项的系数和次数。然后我们根据这些信息自动生成对应的矩形拼图布局。整体流程是输入一个多项式字符串如x**2 5*x 6用 SymPy 对其进行因式分解得到(x 2)*(x 3)从因式结果中读出两个一次式的常数项2 和 3从展开式中读出各项系数1, 5, 6自动生成四个矩形块x2边长 $ x 、 2x 宽2高 x 、 3x 宽 x $ 高 3、6宽 2 高 3并根据这些边长自动算出左下角坐标将布局信息输出为一个统一的数据结构供Manim使用。这样无论你输入 x27x12 还是 x2−3x2甚至带参数的 x2(ab)xab布局生成逻辑都完全一样——你只需要换一个多项式字符串。下面是一段纯SymPy的布局生成器代码不依赖Manim可以直接在Jupyter里跑from sympy import symbols, factor, expand, Poly from sympy.abc import x def generate_layout(poly_expr): 输入一个关于 x 的多项式可因式分解为 (xa)(xb) 输出四个矩形的布局信息列表每个矩形包括 (标签, 宽, 高, x坐标, y坐标) # 因式分解 factored factor(poly_expr) # 例如 (x 2)*(x 3) # 确保是两个一次因式 if not factored.is_Mul: raise ValueError(多项式不能分解为两个一次因式) factors factored.args if len(factors) ! 2: raise ValueError(暂时只支持两个一次因式) # 提取常数项 a, b a None b None for fac in factors: if fac.is_Add: # 形如 x c提取常数 c coeff_dict Poly(fac, x).as_dict() c -coeff_dict.get(0, 0) if 1 in coeff_dict and coeff_dict[1]1 else None # 这里做一个简单处理假定就是 x - a 形式 # 我们用 Poly 提取根 p Poly(fac, x) if p.degree() 1: root -p.coeff_monomial(1) / p.coeff_monomial(0) # 其实标准形式是 x - r # 更稳健fac x a0 a0 const p.coeff_monomial(1) # 系数 1 const_term p.coeff_monomial(0) # a0 if const 1: val const_term else: val const_term / const if a is None: a val else: b val # 展开式获取各项 expanded expand(poly_expr) poly Poly(expanded, x) coeff_x2 poly.coeff_monomial(2) # x^2 系数 coeff_x poly.coeff_monomial(1) # x 系数 const poly.coeff_monomial(0) # 常数项 # 现在已知大矩形的宽 (x a)高 (x b)但我们是取具体 x 值画图 # 这里的布局用符号 a, b 表达注意 a,b 是常数数值不是符号 # 返回布局宽和高用数值表达式含 x留给 Manim 代入 x_val layout [ {label: x^2, w: x, h: x, x0: 0, y0: 0}, {label: f{b}x, w: b, h: x, x0: x, y0: 0}, {label: f{a}x, w: x, h: a, x0: 0, y0: x}, {label: f{a*b}, w: b, h: a, x0: x, y0: x}, ] return layout, a, b # 示例x^2 5x 6 layout, a, b generate_layout(x**2 5*x 6) print(a , a, b , b) for item in layout: print(item)输出a 2 b 3 {label: x^2, w: x, h: x, x0: 0, y0: 0} {label: 3x, w: 3, h: x, x0: x, y0: 0} {label: 2x, w: x, h: 2, x0: 0, y0: x} {label: 6, w: 3, h: 2, x0: x, y0: x}可以看到矩形的宽高和坐标全部由a和b决定而a,b是从 SymPy 因式分解中自动提取的。换一个多项式只需改一行输入布局自动生成。3. Manim 联动实战通用因式分解拼图动画现在我们把这个自动布局引擎接入Manim做一个通用场景你只需要在开头指定多项式动画就会自动展示对应的面积拼图并标注公式。代码如下from manim import * from sympy import factor, Poly from sympy.abc import x class AutoFactorPuzzle(Scene): def construct(self): # 1. 在这里输入你要讲的多项式 poly_expr x**2 5 * x 6 # 试着改成 x**2 7*x 12 看看 x_val 1.5 # 动画中 x 的具体取值可调 # 2. SymPy 自动分析多项式 factored factor(poly_expr) if not factored.is_Mul or len(factored.args) ! 2: raise ValueError(多项式需能分解为两个一次因式 (xa)(xb)) # 提取 a, b roots [] for fac in factored.args: p Poly(fac, x) if p.degree() ! 1: raise ValueError(因式必须是一次式) # 一次多项式 ax ball_coeffs() 返回 [a, b] coeffs p.all_coeffs() # 根为 -b/a root -coeffs[1] / coeffs[0] roots.append(root) a, b float(roots[0]), float(roots[1]) # 常数项 a, b # 3. 根据 a, b 生成矩形布局 # 四个矩形x^2, b*x, a*x, a*b blocks [ {label: x^2, w: x_val, h: x_val, x0: 0, y0: 0, color: BLUE}, { label: f{abs(b)} \\times x, w: abs(b), h: x_val, x0: x_val, y0: 0, color: RED, }, { label: f{abs(a)} \\times x, w: x_val, h: abs(a), x0: 0, y0: x_val, color: YELLOW, }, { label: f{abs(b)} \\times {abs(a)}, w: abs(b), h: abs(a), x0: x_val, y0: x_val, color: GREEN, }, ] # 4. Manim 绘制 # 创建四个内部矩形 for blk in blocks: rect Rectangle( widthblk[w], heightblk[h], colorblk[color], fill_opacity0.4, stroke_width1, ) # 左下角坐标转换为 Manim 中心坐标 rect.move_to([blk[x0] blk[w] / 2, blk[y0] blk[h] / 2, 0]) # 偏移一个固定位置 rect.shift(LEFT * 2 DOWN) label MathTex(f{blk[label]}, font_size16) label.move_to(rect.get_center()) self.play(Create(rect), Write(label)) self.wait(0.5) # 显示等式 eq MathTex( f{{x}}^2 {poly_expr.coeff(x,1)}x {poly_expr.coeff(x,0)}, , f(x{a if a0 else abs(a)})(x{b if b0 else abs(b)}), font_size20, ).shift(DOWN * 1.5) self.play(Write(eq)) self.wait(2)关键解释多形式输入只改poly_expr ...一行整段代码就能绘制出对应的十字相乘面积图SymPy 的factor自动拆出一次因式Poly帮我们提取系数a和b直接成为矩形的边长参数整个布局的坐标逻辑只写了一次通过a、b、x_val计算出blocks没有手动偏移。试一下把poly_expr改成x**2 7*x 12重新运行动画将立刻变成 $ x^2 蓝、 4x 红、 3x 黄、 12 绿的四块拼图等式也变为 x^27x12(x4)(x3) $。4. 效果展示说明运行上面的AutoFactorPuzzle你会看到内部四块矩形依次浮现蓝色 x2 在左下右侧是一块红色 bx上方是一块 黄色 ax右上角是绿色常数块 ab。所有块之间严丝合缝因为它们的坐标和边长都来自同一个因式分解结果。标签 $ x^2 、 bx 、 ax 、 ab $ 精准居中清晰对应代数项。下方显示因式分解的等式左边是展开式右边是因式乘积学生可以立刻将图形与公式对应起来。更重要的是换一个多项式只需要改一行代码动画逻辑完全复用。想一次性展示多个公式的对比只需要建几个不同的场景实例即可。这让“制作一套完整的因式分解几何证明微课”从一天的工作量缩短到一小时。5. 小结SymPy在这个场景中扮演的角色是一个代数结构的自动解析器。传统方法也能拼出图但你得用大脑去“解析”公式再手动翻译成矩形的宽高和位置而SymPy帮你自动完成“因式分解 → 提取系数 → 生成几何参数”的全过程让你专注于教学设计和动