Skip to content

综合场景(多库协同·需联网) ​

pandas / scipy / sklearn / statsmodels / matplotlib 与 Manim 串成一条讲解管线,需联网取包。

本页 5 条示例。代码引自 corpus/examples/combo/,截图为真机渲染的终态。

综合场景:pandas 洗数 → sklearn 拟合 → Manim 画线 ​

数据点散布 + 拟合直线:直线贴合数据趋势,斜率截距与 sklearn 的结果一致。

综合场景:pandas 洗数 → sklearn 拟合 → Manim 画线

py
"""综合场景:pandas 洗数 → sklearn 拟合 → Manim 画线

@expect 数据点散布 + 拟合直线:直线贴合数据趋势,斜率截距与 sklearn 的结果一致。
@note 多库协同的真实样子:pandas 管表、sklearn 管模型、numpy 管数值、manim 管画面。
      一段里同时用到 DataFrame 构造、train_test_split、Pipeline(缩放+回归)、predict 与向量化——
      单库的简单例子预测不了这种链路会不会在按需取包后出问题。
"""

from manim import *
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(11)
n = 60
df = pd.DataFrame({"x": rng.uniform(0, 10, n)})
df["y"] = 2.1 * df["x"] + 1.5 + rng.normal(0, 1.6, n)

x_train, x_test, y_train, y_test = train_test_split(df[["x"]], df["y"], test_size=0.25, random_state=0)
model = Pipeline([("scale", StandardScaler()), ("lin", LinearRegression())])
model.fit(x_train, y_train)
score = float(model.score(x_test, y_test))

xs = np.linspace(0, 10, 50)
pred = model.predict(pd.DataFrame({"x": xs}))
slope = float(model.named_steps["lin"].coef_[0])
print("combo-sklearn", round(score, 3), round(slope, 3), round(float(pred[0]), 3))

px = df["x"].to_numpy(dtype=float)
py = df["y"].to_numpy(dtype=float)
fx = xs.astype(float)
fy = np.asarray(pred, dtype=float)


class ComboSklearnScene(Scene):
    def construct(self):
        ax = Axes(x_range=[0, 10, 2], y_range=[0, 24, 4])
        dots = VGroup(*[Dot(point=ax.c2p(float(a), float(b)), color=BLUE) for a, b in zip(px, py)])
        line = ax.plot(lambda t: float(np.interp(t, fx, fy)), x_range=[0, 10], color=YELLOW)
        self.play(Create(ax), FadeIn(dots))
        self.play(Create(line))
        self.wait(0.3)

综合场景:pandas 滚动统计 + scipy.signal 平滑与寻峰 ​

原始数据、平滑后的曲线、寻峰标记三层都在:峰位与数据特征对得上。

综合场景:pandas 滚动统计 + scipy.signal 平滑与寻峰

py
"""综合场景:pandas 滚动统计 + scipy.signal 平滑与寻峰

@expect 原始数据、平滑后的曲线、寻峰标记三层都在:峰位与数据特征对得上。
@note 时序数据三件套:pandas 造表与滚动、scipy 滤波去噪与找峰、numpy 管索引。
      峰值点回画布上标出来,数据链路从表一路走到画面——跨三库的索引对齐最容易出问题。
"""

from manim import *
import numpy as np
import pandas as pd
from scipy.signal import find_peaks, savgol_filter

rng = np.random.default_rng(3)
t = np.arange(80)
base = 2.0 + np.sin(t / 6.0) * 1.5
df = pd.DataFrame({"t": t, "v": base + rng.normal(0, 0.35, 80)})
df["smooth"] = savgol_filter(df["v"].to_numpy(dtype=float), 9, 3)
df["roll"] = df["smooth"].rolling(5, min_periods=1).mean()

smooth = df["smooth"].to_numpy(dtype=float)
ts = df["t"].to_numpy(dtype=float)
peaks, _props = find_peaks(smooth, distance=6, prominence=0.4)
print("combo-scipy", len(peaks), int(peaks[0]), round(float(df["roll"].iloc[-1]), 3))


class ComboSignalScene(Scene):
    def construct(self):
        ax = Axes(x_range=[0, 80, 20], y_range=[0, 4, 1])
        curve = ax.plot(lambda x: float(np.interp(x, ts, smooth)), x_range=[0, 79], color=GREEN)
        marks = VGroup(*[Dot(point=ax.c2p(float(ts[i]), float(smooth[i])), color=RED) for i in peaks])
        self.play(Create(ax))
        self.play(Create(curve), FadeIn(marks))
        self.wait(0.3)

综合场景:scipy 解 ODE + numpy 取解 + Manim 画两条对照曲线 ​

两条对照曲线的形态与 ODE 数值解一致,图例 / 标注齐全。

综合场景:scipy 解 ODE + numpy 取解 + Manim 画两条对照曲线

py
"""综合场景:scipy 解 ODE + numpy 取解 + Manim 画两条对照曲线

@expect 两条对照曲线的形态与 ODE 数值解一致,图例 / 标注齐全。
@note solve_ivp 返回的是一整包解(Bunch),这里用属性访问 + 切片把它拆成可画的曲线,
      再叠一条解析解对照——看「库对象的形状转换」在桥上顺不顺。
"""

from manim import *
import numpy as np
from scipy.integrate import solve_ivp


def damped(t, state):
    x, v = state
    return [v, -0.6 * v - 4.0 * x]


sol = solve_ivp(damped, (0.0, 12.0), [1.0, 0.0], t_eval=np.linspace(0, 12, 240))
ts = sol.t
xs = sol.y[0]
analytic = np.exp(-0.3 * ts) * np.cos(np.sqrt(4.0 - 0.09) * ts)
err = float(np.max(np.abs(xs - analytic)))
print("combo-ode", bool(sol.success), len(ts), round(err, 4))


class ComboOdeScene(Scene):
    def construct(self):
        ax = Axes(x_range=[0, 12, 2], y_range=[-1.2, 1.2, 0.5])
        curve = ax.plot(lambda x: float(np.interp(x, ts, xs)), x_range=[0, 12], color=BLUE)
        ref = ax.plot(lambda x: float(np.interp(x, ts, analytic)), x_range=[0, 12], color=YELLOW)
        self.play(Create(ax))
        self.play(Create(curve), Create(ref))
        self.wait(0.3)

综合场景:pandas 造表 → statsmodels OLS 拟合与预测 → Manim 画回归 ​

造表、拟合、画回归一条龙:拟合线贴合数据,预测点落在合理位置。

综合场景:pandas 造表 → statsmodels OLS 拟合与预测 → Manim 画回归

py
"""综合场景:pandas 造表 → statsmodels OLS 拟合与预测 → Manim 画回归

@expect 造表、拟合、画回归一条龙:拟合线贴合数据,预测点落在合理位置。
@note OLS 吃 pandas 时参数名来自列名,predict 要同形状的外生变量表。
      残差、RMSE 这些统计量与画面同源——验「统计库产出的 pandas 对象」能不能顺着链路走下去。
"""

from manim import *
import numpy as np
import pandas as pd
import statsmodels.api as sm

rng = np.random.default_rng(9)
n = 40
df = pd.DataFrame({"x": rng.uniform(0, 6, n)})
df["y"] = 1.4 * df["x"] + 2.0 + rng.normal(0, 0.8, n)

exog = sm.add_constant(df["x"])
fit = sm.OLS(df["y"], exog).fit()
df["fit"] = fit.predict(exog)
df["resid"] = df["y"] - df["fit"]
rmse = float(np.sqrt(np.mean(df["resid"].to_numpy(dtype=float) ** 2)))
print("combo-statsmodels", round(float(fit.params["x"]), 3), round(float(fit.rsquared), 3), round(rmse, 3))

gx = np.linspace(0, 6, 60)
lx = gx.astype(float)
ly = np.asarray(fit.params["const"] + fit.params["x"] * gx, dtype=float)
px = df["x"].to_numpy(dtype=float)
py = df["y"].to_numpy(dtype=float)


class ComboOlsScene(Scene):
    def construct(self):
        ax = Axes(x_range=[0, 6, 1], y_range=[0, 12, 2])
        dots = VGroup(*[Dot(point=ax.c2p(float(a), float(b)), color=BLUE) for a, b in zip(px, py)])
        lin = ax.plot(lambda t: float(np.interp(t, lx, ly)), x_range=[0, 6], color=YELLOW)
        self.play(Create(ax), FadeIn(dots))
        self.play(Create(lin))
        self.wait(0.3)

综合场景:numpy 造簇 → sklearn KMeans → matplotlib 取色 → Manim 上色 ​

散点按 KMeans 的簇用 matplotlib 取的色上色:同簇同色、中心可辨。

综合场景:numpy 造簇 → sklearn KMeans → matplotlib 取色 → Manim 上色

py
"""综合场景:numpy 造簇 → sklearn KMeans → matplotlib 取色 → Manim 上色

@expect 散点按 KMeans 的簇用 matplotlib 取的色上色:同簇同色、中心可辨。
@note 四个库各司其职:numpy 造点、KMeans 聚类、matplotlib 的 colormap 取色、
      manim 上色画散点。簇标签是 numpy 数组,索引与逐点取色都用上——
      颜色从「库算出来的 hex 串」一路交给 manim,这条转换最容易踩坑。
"""

from manim import *
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

rng = np.random.default_rng(1)
centers = np.array([[0.0, 0.0], [3.0, 3.5], [0.5, 4.0]])
pts = np.vstack([c + rng.normal(0, 0.45, (25, 2)) for c in centers])

km = KMeans(n_clusters=3, n_init=10, random_state=0).fit(pts)
labels = km.labels_

cmap = plt.get_cmap("viridis")
hexes = [matplotlib.colors.to_hex(cmap(i / 2.0)) for i in range(3)]
cols = [hexes[int(label)] for label in labels]
print("combo-kmeans", int(km.n_clusters), round(float(km.inertia_), 2), hexes[0])

px = pts[:, 0].astype(float)
py = pts[:, 1].astype(float)


class ComboKMeansScene(Scene):
    def construct(self):
        ax = Axes(x_range=[-2, 5, 1], y_range=[-2, 6, 2])
        dots = VGroup(*[
            Dot(point=ax.c2p(float(a), float(b)), color=cols[i])
            for i, (a, b) in enumerate(zip(px, py))
        ])
        self.play(Create(ax), FadeIn(dots))
        self.wait(0.3)

MIT licensed · Manim 与 Pyodide 各依其自身许可(见「安装」)