En fait, le but de np.meshgridest déjà mentionné dans la documentation:
np.meshgrid
Renvoie les matrices de coordonnées des vecteurs de coordonnées.
Faire des tableaux de coordonnées ND pour des évaluations vectorisées de champs scalaires / vectoriels ND sur des grilles ND, étant donné les tableaux de coordonnées unidimensionnels x1, x2, ..., xn.
Son objectif principal est donc de créer une matrice de coordonnées.
Vous vous êtes probablement demandé:
Pourquoi devons-nous créer des matrices de coordonnées?
La raison pour laquelle vous avez besoin de matrices de coordonnées avec Python / NumPy est qu'il n'y a pas de relation directe entre les coordonnées et les valeurs, sauf lorsque vos coordonnées commencent par zéro et sont des entiers purement positifs. Ensuite, vous pouvez simplement utiliser les indices d'un tableau comme index. Cependant, lorsque ce n'est pas le cas, vous devez en quelque sorte stocker les coordonnées à côté de vos données. C'est là qu'interviennent les grilles.
Supposons que vos données soient:
1 2 1
2 5 2
1 2 1
Cependant, chaque valeur représente une région de 2 kilomètres de large horizontalement et de 3 kilomètres verticalement. Supposons que votre origine soit le coin supérieur gauche et que vous vouliez des tableaux qui représentent la distance que vous pourriez utiliser:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
où v est:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
et h:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
Donc, si vous avez deux indices, disons xet y(c'est pourquoi la valeur de retour de meshgridest généralement xxou xsau lieu de xdans ce cas j'ai choisi hhorizontalement!), Alors vous pouvez obtenir la coordonnée x du point, la coordonnée y du point et le valeur à ce point en utilisant:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
Cela facilite grandement le suivi des coordonnées et (plus important encore) vous pouvez les transmettre à des fonctions qui ont besoin de connaître les coordonnées.
Une explication un peu plus longue
Cependant, np.meshgridlui-même n'est pas souvent utilisé directement, la plupart du temps, on utilise simplement l'un des objets similairesnp.mgrid ou np.ogrid. Ici np.mgridreprésente le sparse=Falseet np.ogridle sparse=Truecas (je me réfère à l' sparseargument de np.meshgrid). Notez qu'il existe une différence significative entre
np.meshgridet np.ogridet np.mgrid: Les deux premières valeurs renvoyées (s'il y en a deux ou plus) sont inversées. Souvent, cela n'a pas d'importance, mais vous devez donner des noms de variables significatifs en fonction du contexte.
Par exemple, dans le cas d'une grille 2D et matplotlib.pyplot.imshowil est logique de nommer le premier élément retourné de np.meshgrid xet le second yalors que c'est l'inverse pour np.mgridet np.ogrid.
np.ogrid et grilles clairsemées
>>> 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]])
Comme déjà dit, la sortie est inversée par rapport à np.meshgrid, c'est pourquoi je l'ai décompressée au yy, xxlieu de 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]])
Cela ressemble déjà à des coordonnées, en particulier les lignes x et y pour les tracés 2D.
Visualisé:
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 et grilles denses / étoffées
>>> 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]])
Il en va de même ici: la sortie est inversée par rapport à 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]])
Contrairement à ogridces tableaux contiennent tous xx et yycoordonnées dans le -5 <= xx <= 5; -5 <= yy <= 5 grille.
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")

Fonctionnalité
Ce n'est pas seulement limité à la 2D, ces fonctions fonctionnent pour des dimensions arbitraires (enfin, il y a un nombre maximum d'arguments donnés pour fonctionner en Python et un nombre maximum de dimensions que NumPy permet):
>>> 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.
Même si ceux-ci fonctionnent également pour 1D, il existe deux fonctions de création de grille 1D (beaucoup plus courantes):
Outre l' argument startet stop, il prend également en charge l' stepargument (même les étapes complexes qui représentent le nombre d'étapes):
>>> 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.]])
Applications
Vous avez spécifiquement demandé à propos de l'objectif et en fait, ces grilles sont extrêmement utiles si vous avez besoin d'un système de coordonnées.
Par exemple, si vous avez une fonction NumPy qui calcule la distance en deux dimensions:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
Et vous voulez connaître la distance de chaque 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]])
La sortie serait identique si l'on passait dans une grille dense au lieu d'une grille ouverte. La diffusion NumPys rend cela possible!
Visualisons le résultat:
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()

Et cela est aussi quand NumPys mgridet ogriddeviennent très pratique car il vous permet de changer facilement la résolution de vos grilles:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

Toutefois, étant donné que imshowne prend pas en charge xet les yentrées on doit changer les tiques à la main. Ce serait vraiment pratique s'il acceptait les coordonnées xet y, n'est-ce pas?
Il est facile d'écrire des fonctions avec NumPy qui traitent naturellement des grilles. De plus, il existe plusieurs fonctions dans NumPy, SciPy, matplotlib qui s'attendent à ce que vous passiez dans la grille.
J'aime les images alors explorons 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)

Notez comment les coordonnées sont déjà correctement définies! Ce ne serait pas le cas si vous veniez de passer le density.
Ou pour donner un autre exemple amusant en utilisant des modèles d'astropie (cette fois, je ne me soucie pas beaucoup des coordonnées, je les utilise juste pour créer une grille):
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)

Bien que ce soit juste "pour l'apparence", plusieurs fonctions liées aux modèles fonctionnels et à l'ajustement (par exemple scipy.interpolate.interp2d,
scipy.interpolate.griddatamême montrer des exemples d'utilisation np.mgrid) dans Scipy, etc. nécessitent des grilles. La plupart d'entre eux fonctionnent avec des grilles ouvertes et des grilles denses, mais certains ne fonctionnent qu'avec l'une d'entre elles.
xxetyy. La partie mystérieuse pour moi était pourquoi elle renvoie cette paire de résultats, et à quoi ils ressemblent. La réponse de Hai Phan est pratique pour cela. Je suppose que cela fait cela pour plus de commodité, car l'intrigue veut deux paramètres comme ça.