实际上np.meshgrid
文档中已经提到了的目的:
np.meshgrid
从坐标向量返回坐标矩阵。
在给定一维坐标数组 x1、x2、...、xn 的情况下,制作 ND 坐标数组,用于在 ND 网格上对 ND 标量/矢量场进行矢量化评估。
所以它的主要目的是创建一个坐标矩阵。
你可能只是问自己:
为什么我们需要创建坐标矩阵?
使用 Python/NumPy 需要坐标矩阵的原因是坐标与值之间没有直接关系,除非坐标从零开始并且是纯正整数。然后你可以只使用数组的索引作为索引。但是,如果不是这种情况,您需要以某种方式将坐标与数据一起存储。这就是网格的用武之地。
假设您的数据是:
1 2 1
2 5 2
1 2 1
但是,每个值代表 3 x 2 公里的区域(水平 x 垂直)。假设您的原点是左上角,并且您想要表示可以使用的距离的数组:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
其中 v 是:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
和 h:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
因此,如果你有两个索引,假设x
and y
(这就是为什么返回值meshgrid
通常是xx
或者xs
而不是x
在这种情况下我选择h
水平!)然后你可以得到点的 x 坐标,点的 y 坐标和在这一点上的价值通过使用:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
这使得跟踪坐标变得更加容易,并且(更重要的是)您可以将它们传递给需要知道坐标的函数。
稍微长一点的解释
但是,np.meshgrid
它本身并不经常直接使用,大多只是使用类似对象之一np.mgrid
或np.ogrid
. 这里np.mgrid
表示sparse=False
和np.ogrid
的sparse=True
情况(我指的是 的sparse
论点np.meshgrid
)。请注意,
np.meshgrid
andnp.ogrid
和之间存在显着差异np.mgrid
:前两个返回值(如果有两个或更多)是相反的。通常这无关紧要,但您应该根据上下文给出有意义的变量名称。
例如,在 2D 网格的情况下,将返回的第一个项目命名为和第二个matplotlib.pyplot.imshow
是有意义的,而对于and则相反。np.meshgrid
x
y
np.mgrid
np.ogrid
>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
如前所述,与 相比,输出是相反的np.meshgrid
,这就是为什么我将其解压缩为yy, xx
而不是xx, yy
:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
这已经看起来像坐标,特别是 2D 绘图的 x 和 y 线。
可视化:
yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")

>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
此处同样适用:输出与以下内容相反np.meshgrid
:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
不像ogrid
这些数组包含所有 xx
和yy
坐标在 -5 <= xx <= 5; -5 <= yy <= 5 格。
yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")

功能性
它不仅限于 2D,这些函数适用于任意维度(嗯,Python 中的函数有最大数量的参数以及 NumPy 允许的最大维度数量):
>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
x1
array([[[[0]]],
[[[1]]],
[[[2]]]])
x2
array([[[[1]],
[[2]],
[[3]]]])
x3
array([[[[2],
[3],
[4]]]])
x4
array([[[[3, 4, 5]]]])
>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
# Identical output so it's omitted here.
即使这些也适用于一维,也有两个(更常见的)一维网格创建函数:
除了start
andstop
参数,它还支持step
参数(甚至是表示步骤数的复杂步骤):
>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1 # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.],
[7., 7., 7., 7.],
[9., 9., 9., 9.]])
>>> x2 # The dimension with the "number of steps"
array([[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.]])
应用
您特别询问了目的,事实上,如果您需要坐标系,这些网格非常有用。
例如,如果您有一个计算二维距离的 NumPy 函数:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
你想知道每个点的距离:
>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys) # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
7.07106781, 7. , 7.07106781, 7.28010989, 7.61577311],
[8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
6.08276253, 6. , 6.08276253, 6.32455532, 6.70820393],
[7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
5.09901951, 5. , 5.09901951, 5.38516481, 5.83095189],
[7.21110255, 6.40312424, 5.65685425, 5. , 4.47213595,
4.12310563, 4. , 4.12310563, 4.47213595, 5. ],
[6.70820393, 5.83095189, 5. , 4.24264069, 3.60555128,
3.16227766, 3. , 3.16227766, 3.60555128, 4.24264069],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6. , 5. , 4. , 3. , 2. ,
1. , 0. , 1. , 2. , 3. ],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128]])
如果通过密集网格而不是开放网格,输出将是相同的。NumPys 广播使之成为可能!
让我们可视化结果:
plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel()) # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()

这也是 NumPys变得非常方便的时候mgrid
,ogrid
因为它允许您轻松更改网格的分辨率:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

但是,由于imshow
不支持x
和y
输入,因此必须手动更改刻度。如果它接受x
andy
坐标,那真的很方便,对吧?
使用 NumPy 编写自然处理网格的函数很容易。此外,NumPy、SciPy、matplotlib 中有几个函数希望您通过网格。
我喜欢图片,所以让我们探索一下matplotlib.pyplot.contour
:
ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)

请注意坐标是如何正确设置的!如果您只是通过density
.
或者再举一个使用天体模型的有趣例子(这次我不太关心坐标,我只是用它们来创建一些网格):
from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
g2d = models.Gaussian2D(amplitude=100,
x_mean=np.random.randint(0, 100),
y_mean=np.random.randint(0, 100),
x_stddev=3,
y_stddev=3)
z += g2d(x, y)
a2d = models.AiryDisk2D(amplitude=70,
x_0=np.random.randint(0, 100),
y_0=np.random.randint(0, 100),
radius=5)
z += a2d(x, y)

尽管这只是“外观”,但Scipy 等中与功能模型和拟合相关的几个功能(例如scipy.interpolate.interp2d
,
scipy.interpolate.griddata
甚至使用 显示示例)都需要网格。np.mgrid
其中大多数适用于开放网格和密集网格,但有些仅适用于其中之一。