如何在Manim中制作带丰富色图的类Matlab/Octave风格曲面图动画?
实现Manim中类似Octave风格的3D曲面动画(带丰富色图)
1. 从Octave导出计算数据
先把Octave中计算好的X、Y网格矩阵和对应的Z高度矩阵导出,方便Manim读取:
- 导出为CSV文件(适合小数据):
在Octave中执行:csvwrite("x_data.csv", X); csvwrite("y_data.csv", Y); csvwrite("z_data.csv", Z); - 导出为numpy兼容的.npy文件(适合大数据,读写更快):
先在Octave中安装octave-numpy包,然后执行:save("-npy", "x_data.npy", X); save("-npy", "y_data.npy", Y); save("-npy", "z_data.npy", Z);
2. 在Manim中实现丰富色图
Manim的Surface类支持自定义颜色映射,完全可以复刻Octave/Matlab的色图效果,无需局限于默认棋盘格:
方法1:直接使用Matplotlib色图
Manim兼容Matplotlib的所有色图(比如viridis、plasma、jet等,和Octave内置色图对应),只需导入Matplotlib的颜色映射模块:
from manim import * import matplotlib.cm as cm import numpy as np class CustomSurface(ThreeDScene): def construct(self): # 从Octave导出的文件读取数据 X = np.load("x_data.npy") Y = np.load("y_data.npy") Z = np.load("z_data.npy") # 创建带自定义色图的曲面 surface = Surface( lambda u, v: np.array([X[u, v], Y[u, v], Z[u, v]]), u_range=(0, X.shape[0]-1), v_range=(0, X.shape[1]-1), color_map=cm.viridis, # 这里替换成你需要的色图,比如cm.jet fill_opacity=1 ) # 设置俯视视角 self.set_camera_orientation(phi=0 * DEGREES, theta=-90 * DEGREES) self.add(surface) self.wait()
方法2:自定义颜色渐变
如果需要完全自定义色图,可以通过get_color方法手动映射Z值到颜色:
from manim import * import numpy as np class CustomColoredSurface(ThreeDScene): def construct(self): X = np.load("x_data.npy") Y = np.load("y_data.npy") Z = np.load("z_data.npy") # 归一化Z值到0-1范围 z_min, z_max = Z.min(), Z.max() norm_z = (Z - z_min) / (z_max - z_min) # 自定义颜色映射函数 def get_color(u, v): z_val = norm_z[u, v] # 从蓝色到红色的渐变,可根据需求调整 return interpolate_color(BLUE, RED, z_val) surface = Surface( lambda u, v: np.array([X[u, v], Y[u, v], Z[u, v]]), u_range=(0, X.shape[0]-1), v_range=(0, X.shape[1]-1), get_color=get_color, fill_opacity=1 ) self.set_camera_orientation(phi=0 * DEGREES, theta=-90 * DEGREES) self.add(surface) self.wait()
3. 添加动画效果
要制作曲面的动态展示,比如从平面升起、颜色渐变动画等,示例如下:
from manim import * import matplotlib.cm as cm import numpy as np class SurfaceAnimation(ThreeDScene): def construct(self): X = np.load("x_data.npy") Y = np.load("y_data.npy") Z = np.load("z_data.npy") z_min = Z.min() # 初始平面(Z值为最小值) initial_surface = Surface( lambda u, v: np.array([X[u, v], Y[u, v], z_min]), u_range=(0, X.shape[0]-1), v_range=(0, X.shape[1]-1), color_map=cm.viridis, fill_opacity=1 ) # 目标曲面 target_surface = Surface( lambda u, v: np.array([X[u, v], Y[u, v], Z[u, v]]), u_range=(0, X.shape[0]-1), v_range=(0, X.shape[1]-1), color_map=cm.viridis, fill_opacity=1 ) self.set_camera_orientation(phi=0 * DEGREES, theta=-90 * DEGREES) self.add(initial_surface) # 播放从平面到目标曲面的过渡动画 self.play(Transform(initial_surface, target_surface), run_time=3) self.wait()
关键注意事项
- 确保Octave导出的X、Y、Z矩阵维度一致,Manim的Surface要求输入的网格坐标和高度一一对应。
- 调整
phi和theta参数可以精准设置俯视视角,phi=0对应完全俯视,theta=-90调整水平朝向。 - 如果使用CSV文件读取,需要用
np.genfromtxt替代np.load,注意处理数据格式。
内容的提问来源于stack exchange,提问作者Redsbefall
相关产品推荐
相关产品推荐

