首先,让我们在常规网格上对其进行评估,类似于您的示例代码。(顺便提一句,您的方程求值代码中有一个错误。它缺少exp
内部的负号。):
import numpy as np
import matplotlib.pyplot as plt
# Set limits and number of points in grid
y, x = np.mgrid[10:-10:100j, 10:-10:100j]
x_obstacle, y_obstacle = 0.0, 0.0
alpha_obstacle, a_obstacle, b_obstacle = 1.0, 1e3, 2e3
p = -alpha_obstacle * np.exp(-((x - x_obstacle)**2 / a_obstacle
+ (y - y_obstacle)**2 / b_obstacle))
接下来,我们需要计算梯度(这是一种简单的有限差分方法,与上述函数的解析导数计算不同):
# For the absolute values of "dx" and "dy" to mean anything, we'll need to
# specify the "cellsize" of our grid. For purely visual purposes, though,
# we could get away with just "dy, dx = np.gradient(p)".
dy, dx = np.gradient(p, np.diff(y[:2, 0]), np.diff(x[0, :2]))
现在我们可以制作“箭头图”,但是结果可能不会像您期望的那样,因为在网格上的每个点都显示了一个箭头:
fig, ax = plt.subplots()
ax.quiver(x, y, dx, dy, p)
ax.set(aspect=1, title='Quiver Plot')
plt.show()
![这里输入图片描述](https://istack.dev59.com/jTqRU.webp)
让箭头变大。最简单的方法是绘制每n个箭头,并让matplotlib处理自动缩放。我们在此处使用每3个点。如果您想要更少但更大的箭头,请将3更改为较大的整数。
skip = (slice(None, None, 3), slice(None, None, 3))
fig, ax = plt.subplots()
ax.quiver(x[skip], y[skip], dx[skip], dy[skip], p[skip])
ax.set(aspect=1, title='Quiver Plot')
plt.show()
![enter image description here](https://istack.dev59.com/ab9Eg.webp)
还不错,但是那些箭头仍然很难看到。更好的可视化方法可能是使用带有黑色渐变箭头覆盖的图像绘制:
skip = (slice(None, None, 3), slice(None, None, 3))
fig, ax = plt.subplots()
im = ax.imshow(p, extent=[x.min(), x.max(), y.min(), y.max()])
ax.quiver(x[skip], y[skip], dx[skip], dy[skip])
fig.colorbar(im)
ax.set(aspect=1, title='Quiver Plot')
plt.show()
![这里输入图片描述](https://istack.dev59.com/yebHR.webp)
理想情况下,我们希望使用不同的色图或更改箭头颜色。 我会把那部分留给你。 你也可以考虑使用等值线图(ax.contour(x, y, p)
)或流线图(ax.streamplot(x, y, dx, dy
)来展示一个快速的例子:
fig, ax = plt.subplots()
ax.streamplot(x, y, dx, dy, color=p, density=0.5, cmap='gist_earth')
cont = ax.contour(x, y, p, cmap='gist_earth')
ax.clabel(cont)
ax.set(aspect=1, title='Streamplot with contours')
plt.show()
![在此输入图片描述](https://istack.dev59.com/EYBnp.webp)
...为了变得更加花哨而言:
from matplotlib.patheffects import withStroke
fig, ax = plt.subplots()
ax.streamplot(x, y, dx, dy, linewidth=500*np.hypot(dx, dy),
color=p, density=1.2, cmap='gist_earth')
cont = ax.contour(x, y, p, cmap='gist_earth', vmin=p.min(), vmax=p.max())
labels = ax.clabel(cont)
plt.setp(labels, path_effects=[withStroke(linewidth=8, foreground='w')])
ax.set(aspect=1, title='Streamplot with contours')
plt.show()
![在这里输入图像描述](https://istack.dev59.com/VRBuE.webp)
numpy.gradient
获取势场的梯度。例如,在你上面的例子中,使用v, u = np.gradient(P)
。它返回 dy,dx 而不是 dx,dy,因为 NumPy 数组是按行、列索引而不是按列、行索引。 - Joe Kington