如何绘制多元函数梯度?Python代码及numpy.gradient用法疑问
梯度计算与可视化方案 + numpy.gradient() 详解
一、numpy.gradient() 返回值说明
对于二维数组 Z(对应函数 Z=f(X,Y)),np.gradient(Z) 会返回两个同维度数组:
- 第一个数组:沿**轴0(行方向,对应Y轴的变化)**的梯度,即每个点对Y的偏导数近似值
∂Z/∂Y - 第二个数组:沿**轴1(列方向,对应X轴的变化)**的梯度,即每个点对X的偏导数近似值
∂Z/∂X
计算逻辑:内部点采用中心差分法(精度更高),边缘点采用单侧差分(前向或后向)。如果数组基于不等间距坐标生成,还可以通过 np.gradient(Z, dx, dy) 指定X、Y方向的步长 dx 和 dy,得到更准确的实际梯度值。
结合你提供的示例图像:
输入为3×3的数值矩阵,输出的两个矩阵分别对应轴0和轴1的梯度结果。比如输入矩阵的中间行,轴0梯度用上下两行的差值除以2(中心差分)计算,轴1梯度用左右两列的差值除以2计算;边缘行/列则直接用相邻行/列的差值(单侧差分)计算。
二、基于给定代码的梯度计算与可视化
以下是完整的修改代码,包含梯度计算、3D曲面+梯度矢量场的可视化:
import numpy as np import matplotlib.pyplot as plt # 原代码的曲面生成部分 fig = plt.figure(figsize=(12, 6)) # 子图1:原3D曲面 ax1 = fig.add_subplot(121, projection='3d') x = y = np.linspace(1, 10, 100) X, Y = np.meshgrid(x, y) Z = np.sin(X)**3 + np.cos(Y)**3 ax1.plot_surface(X, Y, Z, cmap='viridis', alpha=0.7) ax1.set_xlabel('X') ax1.set_ylabel('Y') ax1.set_zlabel('Z') ax1.set_title('原3D曲面') # 梯度计算部分 # 计算X、Y方向的步长 dx = x[1] - x[0] dy = y[1] - y[0] # 计算梯度:dz_dy对应轴0的梯度,dz_dx对应轴1的梯度 dz_dy, dz_dx = np.gradient(Z, dy, dx) # 子图2:3D曲面叠加梯度矢量场 ax2 = fig.add_subplot(122, projection='3d') ax2.plot_surface(X, Y, Z, cmap='viridis', alpha=0.7) # 为了避免箭头过密,每隔5个点取一个样本点 skip = 5 ax2.quiver(X[::skip, ::skip], Y[::skip, ::skip], Z[::skip, ::skip], dz_dx[::skip, ::skip], dz_dy[::skip, ::skip], -np.ones_like(Z[::skip, ::skip]), length=0.5, color='red') ax2.set_xlabel('X') ax2.set_ylabel('Y') ax2.set_zlabel('Z') ax2.set_title('曲面+梯度矢量场') plt.tight_layout() plt.show()
代码说明:
- 步长计算:
dx = x[1]-x[0]得到X方向的间隔,传入np.gradient后,计算出的梯度是实际物理空间的偏导值,而非默认的单位步长结果。 - 矢量场绘制:用
quiver函数绘制3D箭头,参数中前三个是箭头起点坐标,后三个是箭头的分量(X、Y、Z方向的矢量)。这里Z方向分量取负,是为了让箭头指向梯度下降方向(如果要上升方向则取正)。 - 采样间隔:设置
skip=5是因为原数组有100×100个点,全部绘制箭头会导致画面拥挤,每隔5个点采样一次可以让可视化更清晰。
内容的提问来源于stack exchange,提问作者AmolosRicha1
相关产品推荐
相关产品推荐

