3D 填充面积图(3D filled area / surface / trisurf / polygon fill)是把二维面积图的“填充”概念扩展到三维空间的一类可视化方式。常见于地形、热力、工程、物理仿真、金融波动面、医学数据等场景。本文面向微信公众号读者,系统介绍绘制 3D 填充面积图所需库与基础知识,并给出 6 个从入门到复杂的、每个都可独立执行的示例代码(含解释),同时在文末给出使用场景与实践建议。
- numpy:数组与数值计算(pip install numpy)
- matplotlib:基础绘图(pip install matplotlib)
- mpl_toolkits.mplot3d:matplotlib 自带的 3D 绘图工具包
- matplotlib.tri(mtri):用于三角剖分
- 栅格网格(meshgrid):常用来生成 X, Y 网格,进而计算 Z,绘制规则网格表面。
- 三角剖分(Triangulation / Delaunay):用于不规则点集绘制三角网面(plot_trisurf)。
-面(surface)与多边形(polygon):surface(如 plot_surface、plot_trisurf)基于网格面片绘制填充;Polygon(Poly3DCollection)直接用顶点列表构造三维填充区域。
- 透明度(alpha)、色带(colormap)、光照(lighting)与法向量(normals)可提升可读性与美观。
- 性能提示:高分辨率网格会显著增加绘图时间,交互性绘图(Plotly)数据也会更重。
示例1:基础3D表面图
最常见的“3D 填充面积图”形式——规则网格上的表面,用颜色表示高度,常用于地形或函数可视化。
import numpy as npimport matplotlib.pyplot as plt# 生成数据X = np.linspace(-5, 5, 80)Y = np.linspace(-5, 5, 80)X, Y = np.meshgrid(X, Y)Z = np.sin(np.sqrt(X**2 + Y**2))# 绘图fig = plt.figure(figsize=(8, 6))ax = fig.add_subplot(111, projection="3d")surf = ax.plot_surface(X, Y, Z, cmap="viridis", edgecolor="none", alpha=0.9)ax.set_title("示例1:基础 3D 表面")ax.set_xlabel("X")ax.set_ylabel("Y")ax.set_zlabel("Z")fig.colorbar(surf, shrink=0.6, aspect=10)plt.show()
示例2:3D底面填充等高线
有时需要同时展示表面和其在底面(或某固定平面)上的填充等高线,便于观察高度分布。
import numpy as npimport matplotlib.pyplot as pltplt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "SimSun", "Arial Unicode MS"]plt.rcParams["axes.unicode_minus"] = False # 数据X = np.linspace(-4, 4, 100)Y = np.linspace(-4, 4, 100)X, Y = np.meshgrid(X, Y)Z = np.exp(-(X**2 + Y**2) / 4) * np.cos(3 * np.sqrt(X**2 + Y**2))# 绘图fig = plt.figure(figsize=(9, 6))ax = fig.add_subplot(111, projection="3d")# 表面(半透明)ax.plot_surface(X, Y, Z, cmap="coolwarm", edgecolor="none", alpha=0.7)# 在 z 轴底面做填充等高线(offset 设置底面高度)z_offset = Z.min() - 0.5ax.contourf(X, Y, Z, zdir="z", offset=z_offset, cmap="coolwarm", levels=12, alpha=0.9)ax.set_zlim(z_offset, Z.max())ax.set_title("表面 + 底面填充等高线")ax.set_xlabel("X")ax.set_ylabel("Y")ax.set_zlabel("Z")plt.show()
示例3:3D曲线下方填充面积
当数据为一条三维曲线(而非规则表面)时,可以用多边形将曲线与基线之间的区域进行填充,形成“3D 面积”的视觉效果。
import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d.art3d import Poly3DCollectionplt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "SimSun", "Arial Unicode MS"]plt.rcParams["axes.unicode_minus"] = False # 参数曲线t = np.linspace(0, 2 * np.pi, 200)x = np.cos(t)y = np.sin(t)z = 0.8 * np.sin(3 * t) # 曲线高度# 基线高度(例如 z= -1)z0 = -1.0# 构造多边形(曲线 + 与之对应的基线点(反向))upper = list(zip(x, y, z))lower = list(zip(x[::-1], y[::-1], np.full_like(x, z0)[::-1]))verts = [upper + lower]# 绘图fig = plt.figure(figsize=(8, 6))ax = fig.add_subplot(111, projection="3d")# 绘制曲线ax.plot(x, y, z, color="k", lw=1.5, label="curve")# 添加填充面poly = Poly3DCollection(verts, facecolors="orange", alpha=0.6, edgecolor="k")ax.add_collection3d(poly)ax.set_title("3D曲线下方填充面积")ax.set_xlim(-1.5, 1.5)ax.set_ylim(-1.5, 1.5)ax.set_zlim(z0 - 0.2, z.max() + 0.2)ax.set_xlabel("X")ax.set_ylabel("Y")ax.set_zlabel("Z")plt.show()
当要比较多组函数或多层数据随空间变化时,可将若干表面按一定偏移堆叠并设透明度,形成层叠的填充效果。import numpy as npimport matplotlib.pyplot as pltplt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "SimSun", "Arial Unicode MS"]plt.rcParams["axes.unicode_minus"] = False # 基础网格X = np.linspace(-3, 3, 80)Y = np.linspace(-3, 3, 80)X, Y = np.meshgrid(X, Y)# 多层表面(不同频率或参数)fig = plt.figure(figsize=(9, 7))ax = fig.add_subplot(111, projection="3d")layers = 5offset = 0.6 # 每层在 Z 方向上的偏移for i in range(layers): freq = 1 + i * 0.6 Z = np.sin(np.sqrt((X * freq) ** 2 + (Y * freq) ** 2)) + i * offset ax.plot_surface(X, Y, Z, cmap="viridis", alpha=0.5 - i * 0.07, edgecolor="none")ax.set_title("堆叠的 3D 填充表面(多层)")ax.set_xlabel("X")ax.set_ylabel("Y")ax.set_zlabel("Z")plt.show()
当你的采样点不规则(非网格化)时,可以使用三角剖分并画出三角网面(trisurf),常见于点云可视化与不规则地形建模。
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.tri as mtriplt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "SimSun", "Arial Unicode MS"]plt.rcParams["axes.unicode_minus"] = False# 随机不规则点n = 400rng = np.random.default_rng(42)x = rng.uniform(-3, 3, n)y = rng.uniform(-3, 3, n)# 示例函数,高度与 (x,y) 相关z = np.exp(-0.2 * (x**2 + y**2)) * np.cos(3 * (x + y))# 三角剖分tri = mtri.Triangulation(x, y)# 绘图fig = plt.figure(figsize=(9, 6))ax = fig.add_subplot(111, projection="3d")tplot = ax.plot_trisurf( x, y, z, triangles=tri.triangles, cmap="plasma", linewidth=0.2, antialiased=True)fig.colorbar(tplot, shrink=0.6)ax.set_title("不规则点集三角网填充")ax.set_xlabel("X")ax.set_ylabel("Y")ax.set_zlabel("Z")plt.show()
静态图在许多场景已足够,但交互式图(旋转、缩放、悬浮提示)可以极大提升分析体验。Plotly 可直接输出可交互的 HTML 或在 Jupyter / 浏览器中展示。
import numpy as npimport plotly.graph_objects as go# 数据x = np.linspace(-6, 6, 80)y = np.linspace(-6, 6, 80)X, Y = np.meshgrid(x, y)Z = np.sinc(np.sqrt(X**2 + Y**2) / np.pi) # 示例函数# Plotly 绘图fig = go.Figure( data=[go.Surface(z=Z, x=X, y=Y, colorscale="Viridis", showscale=True)])fig.update_layout( title="交互式3D填充表面", autosize=True, font=dict(family="Microsoft YaHei, SimHei, SimSun, sans-serif"), scene=dict(xaxis_title="X", yaxis_title="Y", zaxis_title="Z"),)fig.show()
实战建议
- 采样与分辨率:网格越密,表面越平滑,但绘制和交互成本也越高。先用粗网格调试,再提升分辨率用于最终展示。
- 透明度(alpha):多层展示或堆叠时配合 alpha 有助于观察内部结构,但透明度会影响渲染时间。
- 颜色映射(cmap)与色标:确保 colormap 对比明显且考虑色盲友好(如
viridis)。 - 光照与法线:matplotlib 的光照支持有限;高级可视化(更真实的光照)可考虑使用 PyVista、Mayavi 或 Plotly 的一些着色选项。
- 不规则点:对于不规则采样优先考虑三角剖分(
plot_trisurf)而不是强行插值成规则网格,以保留原始数据特征。 - 导出与交互:保存为矢量图(SVG)适合静态出版;交互式输出(Plotly HTML)适合网页或报告展示。
- 性能:大量三角形或高分辨率网格在 matplotlib 中可能变慢;必要时使用 downsampling、LOD(level of detail)或专用 GPU 渲染工具。
- - 地学 / 地形可视化:展示海拔、地貌、等高线与剖面。
- 工程与仿真:应力场、温度场、流场的三维分布展示。
- 医学影像:在三维空间展示器官表面、功能强度分布(常与体绘制结合)。
- 金融分析:波动率曲面、收益/风险表面等三维可视化。
- 科研与教学:数学函数、物理场分布的直观演示。
- 数据仪表盘:交互式三维展示帮助业务人员快速理解复杂模型。
- 直观性:相比数表,三维填充图显著提升对空间关系与趋势的直观感知。
- 诊断能力:有助于发现局部极值、异常模式与多变量交互效应。
- 表达力:在报告与可视化沟通中,三维填充图能更有效传达复杂信息。
- 静态高质量图:matplotlib 足够且便捷。
- 交互式或分享型可视化:优先考虑 Plotly 或专门的 3D 渲染库(PyVista、Mayavi)。
- 大规模渲染或实时:考虑基于 GPU 的渲染方案。
本文从基础工具、核心概念出发,给出 6 个“可直接运行”的示例,涵盖规则表面、底面填充、曲线到基线的多边形填充、堆叠表面、不规则三角网以及交互式绘图。建议读者根据目标场景选择合适的绘图库与表现形式:需要交互就用 Plotly,需要高度自定义就用 matplotlib + Poly3DCollection,需要处理不规则点就用三角剖分。
寄语:世间三美,明月,清风,眼前……
看到这儿的朋友帮转发、点赞和在看,谢谢支持~!