Насправді мета np.meshgridвже згадується в документації:
np.meshgrid
Повернути матриці координат від векторів координат.
Складіть ND-координатні масиви для векторних оцінок скалярних / векторних полів ND через сітки ND, задавши одновимірні масиви координат x1, x2, ..., xn.
Тому його основна мета - створити матриці координат.
Ви, мабуть, просто запитали себе:
Чому нам потрібно створити координатні матриці?
Причина, що вам потрібні матриці координат з Python / NumPy, полягає в тому, що прямого відношення від координат до значень немає, за винятком випадків, коли ваші координати починаються з нуля і є чисто позитивними цілими числами. Тоді ви можете просто використовувати індекси масиву як індекс. Однак, коли це не так, вам потрібно якось зберігати координати поряд зі своїми даними. Ось куди заходять сітки.
Припустимо, ваші дані:
1 2 1
2 5 2
1 2 1
Однак кожне значення являє собою 2 кілометрові області по горизонталі та 3 кілометри по вертикалі. Припустимо, ваш джерело - верхній лівий кут, і ви хочете, щоб масиви відображали відстань:
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і 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.ogridsparse=True разі (я посилатися на sparseаргумент np.meshgrid). Зауважте, що існує значна різниця між
np.meshgridі np.ogridта np.mgrid: Перші два повернених значення (якщо їх два чи більше) повертаються назад. Часто це не має значення, але вам слід давати змістовні імена змінних залежно від контексту.
Наприклад, у випадку двовимірної сітки та matplotlib.pyplot.imshowмає сенс назвати перший повернутий елемент np.meshgrid xта другийy тоді як це навпаки для np.mgridі np.ogrid.
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]])
Це вже виглядає як координати, зокрема лінії 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")

np.mgrid і щільні / м'ясисті сітки
>>> 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.
Навіть якщо вони також працюють для 1D, є дві (набагато більш поширені) функції створення 1D сітки:
Крім того, startі stopаргумент він також підтримує 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 і yкоординати, правда?
Писати функції з 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.interpolate.interp2d,
scipy.interpolate.griddataнавіть показують приклади використання np.mgrid) в Scipy тощо, потребують сітки. Більшість із них працює з відкритими сітками та щільними сітками, проте деякі працюють лише з однією з них.
xxтаyy. Таємничою для мене частиною було те, чому вона повертає ту пару результатів і як вони виглядають. Відповідь Хай Фана для цього корисна. Я думаю, що це робиться для зручності, оскільки сюжет хоче таких двох параметрів.