You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用水平面在Matplotlib中平滑裁剪3D曲面图?

3D曲面图顶部干净裁剪问题

我想要创建带z范围和等高线的3D曲面图,使用matplotlib的plot_surface函数已有初步成果,但始终无法干净地裁剪曲面顶部,尝试了多种网上推荐的方法都存在问题,以下是我在PyCharm的Jupyter Notebook中测试的几种方法及遇到的问题:

方法一:基础plot_surface函数

绘制的曲面z=f(x,y)上升极快,z轴刻度数值很大,导致我关注的局部最小值区域难以看清。

import matplotlib
import matplotlib.pyplot as plt
import jax.numpy as jnp

def f(x, y, a, b):
    return x**4 + y**4 + y**3 - (4 * x**2 * y) + y**2 - (a * x) + (b * y)

X, Y = jnp.meshgrid(jnp.arange(-3, 3, 0.01), jnp.arange(-3, 3, 0.01))
Z = f(X, Y, 0, 0)  # 为参数a和b的单一选择生成每个(x,y)处的z值

matplotlib.use("Qt5Agg")

fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(16, 12))

surf = ax.plot_surface(X, Y, Z, linewidth=0, antialiased=False, cmap="viridis")
ax.view_init(elev=10, azim=15, roll=0)

plt.tight_layout()
plt.show()

输出1:曲面整体完整显示,但z轴跨度极大,局部最小值区域细节无法分辨。

方法二:设置z范围并启用axlim_clip=True

此方法放大了目标区域,但颜色缩放仍沿用全局z值范围,导致关注区域内颜色几乎一致,且顶部边缘因整块曲面片被移除而呈现锯齿状。

import matplotlib
import matplotlib.pyplot as plt
import jax.numpy as jnp

def f(x, y, a, b):
    return x**4 + y**4 + y**3 - (4 * x**2 * y) + y**2 - (a * x) + (b * y)

X, Y = jnp.meshgrid(jnp.arange(-3, 3, 0.01), jnp.arange(-3, 3, 0.01))
Z = f(X, Y, 0, 0)  # 为参数a和b的单一选择生成每个(x,y)处的z值
Zmin, Zmax = jnp.min(Z), jnp.percentile(Z, 15.)

matplotlib.use("Qt5Agg")

fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(16, 12))

surf = ax.plot_surface(X, Y, Z, linewidth=0, antialiased=False, cmap="viridis", axlim_clip=True)
ax.view_init(elev=10, azim=15, roll=0)
ax.set_zlim(Zmin, Zmax)

plt.tight_layout()
plt.show()

输出2:目标区域被放大,但颜色区分度极低,曲面顶部边缘呈锯齿状。

方法三:用NaN遮罩超出阈值的z值

此方法解决了颜色缩放问题,关注区域内颜色渐变正常,但顶部边缘仍呈锯齿状,无法实现干净的裁剪效果。

import matplotlib
import matplotlib.pyplot as plt
import jax.numpy as jnp

def f(x, y, a, b):
    return x**4 + y**4 + y**3 - (4 * x**2 * y) + y**2 - (a * x) + (b * y)

X, Y = jnp.meshgrid(jnp.arange(-3, 3, 0.01), jnp.arange(-3, 3, 0.01))
Z = f(X, Y, 0, 0)  # 为参数a和b的单一选择生成每个(x,y)处的z值

Zmax = jnp.percentile(Z, 15.)
Zplateau = jnp.minimum(Z, Zmax)
Zmasked = jnp.where(Z > Zmax, jnp.nan, Zplateau)

matplotlib.use("Qt5Agg")

fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(16, 12))

surf = ax.plot_surface(X, Y, Zmasked, linewidth=0, antialiased=False, cmap="viridis")
ax.view_init(elev=10, azim=15, roll=0)
ax.set_zlim(jnp.min(Z), Zmax)

plt.tight_layout()
plt.show()

输出3:颜色显示正常,但曲面顶部裁剪边缘锯齿明显。

方法四:将超出阈值的z值设为阈值

此方法让顶部边缘平滑,但在曲面顶部形成了不必要的平台,不符合需求。

import matplotlib
import matplotlib.pyplot as plt
import jax.numpy as jnp

def f(x, y, a, b):
    return x ** 4 + y ** 4 + y ** 3 - (4 * x ** 2 * y) + y ** 2 - (a * x) + (b * y)

X, Y = jnp.meshgrid(jnp.arange(-3, 3, 0.01), jnp.arange(-3, 3, 0.01))
Z = f(X, Y, 0, 0)  # 为参数a和b的单一选择生成每个(x,y)处的z值

Zmax = jnp.percentile(Z, 15.)
Zclipped = jnp.where(Z > Zmax, Zmax, Z)

matplotlib.use("Qt5Agg")

fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(16, 12))

surf = ax.plot_surface(X, Y, Zclipped, linewidth=0, antialiased=False, cmap="viridis")
contours = ax.contour(X, Y, Z, levels=[Zmax], zdir="z", offset=Zmax, colors="k", linewidths=2)
ax.view_init(elev=10, azim=15, roll=0)
ax.set_zlim(jnp.min(Z), Zmax)

plt.tight_layout()
plt.show()

输出4:顶部边缘平滑,但出现了多余的平台区域。

补充说明

我尝试过使用更精细的xy网格,以及调整plot_surface的rstride和cstride参数,这些仅能让曲面下部更平滑,但顶部边缘仍呈锯齿状。


内容的提问来源于stack exchange,提问作者Chance Bowman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:24:50